介绍
Spring框架是一个庞大且复杂的Java应用开发框架,其源码包含了众多核心功能和设计模式的实现。以下是Spring源码的简单介绍,涵盖其核心模块和一些关键概念:
核心模块与关键概念
1. Spring Core(核心模块)
Spring Core是Spring框架的基础,提供了依赖注入(DI)和控制反转(IoC)的核心功能。
-
BeanFactory
:Spring容器的基础接口,用于创建和管理Bean。 -
ApplicationContext
:继承自BeanFactory
,提供了更多高级功能,如事件传播、国际化消息支持等。 -
BeanDefinition
:描述Bean的元信息,包括类名、作用域、初始化方法等。
2. Spring AOP(面向切面编程)
Spring AOP允许开发者将横切关注点(如日志记录、事务管理)与业务逻辑分离。
-
ProxyFactoryBean
:用于创建代理对象,是AOP的核心实现之一。 -
AspectJ
:与Spring AOP集成,用于定义切面和增强逻辑。
3. Spring MVC
Spring MVC是Spring框架中的Web模块,用于构建Web应用程序。
-
DispatcherServlet
:Spring MVC的核心,负责将HTTP请求分发到合适的处理器。 -
@Controller
、@RequestMapping
:用于定义控制器和请求映射。
4. Spring事务管理
Spring提供了声明式和编程式事务管理。
-
@Transactional
:声明式事务的核心注解,用于标注事务方法。 -
事务传播行为和隔离级别:定义事务的传播方式和隔离级别。
5. Spring Boot
Spring Boot简化了Spring应用的开发,提供了自动配置和快速启动的能力。
-
@SpringBootApplication
:Spring Boot应用的入口注解,集成了@EnableAutoConfiguration
、@ComponentScan
等。 -
@EnableAutoConfiguration
:启用Spring Boot的自动配置。
6. Spring Data
Spring Data简化了数据访问层的开发,支持多种数据存储方式。
-
Repository
、CrudRepository
:定义了数据访问的基本接口。
设计模式的应用
Spring源码中广泛使用了多种设计模式,如:
-
工厂模式:
BeanFactory
和ApplicationContext
用于创建和管理Bean。 -
单例模式:Spring中的Bean默认是单例的,通过
DefaultSingletonBeanRegistry
实现。 -
代理模式:AOP的实现依赖于代理模式,如
JdkDynamicAopProxy
。
Bean
singleton | 单例 |
prototype | 每次返回一个新的 |
request | 每次Http请求创建新的 |
session | 同一个session共享一个Bean |
globalSession | Portlet |
生命周期
-
实例化(Instantiation)
-
属性赋值(Populate)
-
初始化(Initialization)
-
销毁(Destruction)
事务隔离级别
无
脏读,幻读,不可重复读
幻读,不可重复读
脏读,不可重复读
完全服从ACID的隔离级别,影响性能
脏读:事务 B 去查询了事务 A 修改过的数据,但是此时事务 A 还没提交,所以事务 A 随时会回滚导致事务 B 再次查询就读不到刚才事务 A 修改的数据了。
幻读:事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。
不可重复读:事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了。
Spring IOC的初始化过程
1. 资源加载
-
加载配置文件或注解:Spring IoC容器的启动通常从加载配置信息开始。配置信息可以是XML文件、注解或者Java配置类。
-
如果是基于XML配置,Spring会通过
ClassPathResource
或FileSystemResource
等类加载XML配置文件。 -
如果是基于注解或Java配置,Spring会扫描指定的包路径,查找带有
@Configuration
注解的类。
-
-
创建
BeanDefinitionRegistry
:Spring会创建一个BeanDefinitionRegistry
,用于存储Bean的定义信息。对于XML配置,XmlBeanDefinitionReader
会解析XML文件并注册Bean定义;对于注解配置,ClassPathBeanDefinitionScanner
会扫描类路径并注册Bean定义。
2. 解析Bean定义
-
解析XML配置:如果使用XML配置,Spring会解析
<bean>
标签,提取Bean的类名、属性值、依赖关系等信息,并将其封装为BeanDefinition
对象。 -
解析注解配置:如果使用注解,Spring会扫描类上的注解(如
@Component
、@Service
、@Controller
、@Repository
等),并根据注解信息创建BeanDefinition
对象。同时,还会解析@Autowired
、@Value
等注解,记录依赖关系。 -
注册Bean定义:将解析得到的
BeanDefinition
对象注册到BeanDefinitionRegistry
中,以便后续的Bean实例化和依赖注入。
3. 实例化Bean
-
创建Bean实例:Spring根据
BeanDefinition
中的类信息,通过反射调用无参构造函数创建Bean实例。如果Bean定义中指定了工厂方法,Spring会调用工厂方法来创建Bean实例。 -
处理Aware接口:如果Bean实现了
Aware
接口(如BeanFactoryAware
、ApplicationContextAware
等),Spring会在Bean实例化后,将对应的上下文信息注入到Bean中。
4. 依赖注入
-
注入属性值:Spring根据
BeanDefinition
中记录的属性值信息,通过反射调用set
方法或直接操作字段,将属性值注入到Bean实例中。 -
注入依赖Bean:如果Bean之间存在依赖关系,Spring会根据
BeanDefinition
中记录的依赖信息,调用set
方法或构造函数注入依赖的Bean实例。
5. 初始化Bean
-
调用
@PostConstruct
注解的方法:如果Bean类中存在带有@PostConstruct
注解的方法,Spring会在依赖注入完成后调用该方法。 -
调用
InitializingBean
接口的afterPropertiesSet
方法:如果Bean实现了InitializingBean
接口,Spring会调用afterPropertiesSet
方法。 -
调用
init-method
指定的方法:如果在Bean定义中指定了init-method
属性,Spring会调用该方法。
6. 完成初始化
-
注册到容器:完成初始化后,Bean实例会被注册到Spring IoC容器中,供后续使用。
-
触发
ApplicationEvent
:Spring会触发一些应用事件(如ContextRefreshedEvent
),通知其他组件容器已经初始化完成。
7. 容器销毁
-
调用销毁方法:当Spring IoC容器关闭时,会调用Bean的销毁方法。如果Bean实现了
DisposableBean
接口,会调用destroy
方法;如果指定了destroy-method
属性,会调用该方法。 -
清理资源:Spring会清理容器中的资源,释放内存。
AOP实现原理
Spring AOP(面向切面编程)的实现原理主要基于动态代理技术,通过将横切关注点(如日志记录、事务管理、权限检查等)从业务逻辑中分离出来,实现代码的模块化和可维护性。以下是Spring AOP实现原理的详细解析:
1. 核心概念
-
切面(Aspect):切面是AOP的核心概念,它将横切关注点(如日志记录、事务管理等)封装成独立的模块。
-
切入点(Pointcut):定义了哪些类和方法需要被增强,通常通过表达式语言(如AspectJ表达式)来指定。
-
通知(Advice):定义了具体的增强逻辑,例如在方法执行前、执行后或抛出异常时执行的代码。
-
连接点(Join Point):程序执行过程中的某个特定点,如方法调用或异常抛出。
-
织入(Weaving):将切面逻辑插入到目标对象的过程。
2. 动态代理技术
Spring AOP主要通过动态代理技术实现,动态代理分为两种:
-
JDK动态代理:当目标对象实现了接口时,Spring使用JDK动态代理。通过
java.lang.reflect.Proxy
类动态生成代理类,代理类实现了与目标对象相同的接口。 -
CGLIB代理:如果目标对象没有实现接口,Spring会使用CGLIB库生成目标类的子类作为代理类,覆盖目标方法并插入增强逻辑。
3. 代理对象的创建
Spring AOP的代理对象创建过程如下:
-
启用AOP功能:通过在Spring Boot应用的启动类上添加
@EnableAspectJAutoProxy
注解来开启AOP功能。 -
定义切面:使用
@Aspect
注解标识一个类为切面类,其中可以定义切入点和通知。 -
生成代理对象:Spring根据目标对象是否实现接口选择使用JDK动态代理或CGLIB代理,并创建代理对象。
4. 通知的执行
Spring AOP通过ReflectiveMethodInvocation
类实现责任链模式,管理通知的执行顺序。当方法被调用时,Spring会根据配置的切面信息,依次执行所有匹配的前置、后置、环绕通知,最后调用目标方法。
5. 应用场景
Spring AOP广泛应用于以下场景:
-
日志记录:在方法执行前后记录日志。
-
事务管理:在方法执行前后管理事务。
-
权限检查:在方法执行前进行权限验证。
-
性能监控:记录方法的执行时间。
6. 实现机制
Spring AOP的实现机制可以分为以下几个步骤:
-
解析切面:Spring解析带有
@Aspect
注解的类,提取切入点和通知信息。 -
创建代理对象:根据目标对象是否实现接口,选择JDK动态代理或CGLIB代理。
-
方法拦截:通过动态代理技术拦截方法调用,并根据切面配置执行相应的通知。
-
织入切面:将切面逻辑动态地织入到目标对象的方法中。
动态代理和静态代理
1. 静态代理
静态代理是一种传统的代理方式,代理类和目标类在编译时就已经确定,代理类需要手动实现与目标类相同的接口或继承目标类。
原理
-
目标类(Subject):定义了业务逻辑接口或类。
-
代理类(Proxy):实现与目标类相同的接口或继承目标类,在代理类中调用目标类的方法,并在调用前后添加额外逻辑(如日志记录、权限检查等)。
-
客户端:通过代理类调用目标类的方法,而无需直接调用目标类。
2. 动态代理
动态代理是Spring AOP的核心实现方式。代理类在运行时动态生成,不需要手动编写代理类代码。Spring支持两种动态代理技术:JDK动态代理和CGLIB动态代理。
原理
-
JDK动态代理:
-
使用
java.lang.reflect.Proxy
类动态生成代理类。 -
代理类实现与目标类相同的接口。
-
通过
InvocationHandler
接口处理方法调用,插入额外逻辑。
-
-
CGLIB动态代理:
-
使用CGLIB库动态生成目标类的子类。
-
覆盖目标类的方法,插入额外逻辑。
-
适用于目标类没有实现接口的情况。
-
IOC原理
1. IoC 的核心概念
-
控制反转(IoC):传统的程序中,对象的创建和依赖关系的管理是由代码直接控制的。而在 IoC 中,这些控制权被反转到容器中,由容器负责创建对象和管理对象之间的依赖关系。
-
依赖注入(DI):依赖注入是 IoC 的一种实现方式,通过将依赖对象注入到目标对象中,从而实现对象之间的解耦。
-
容器(Container):Spring 容器是 IoC 的核心,它负责管理对象的生命周期、依赖注入和配置信息。
2. IoC 的实现原理
Spring IoC 的实现主要通过以下步骤完成:
1. 资源加载
-
加载配置文件或注解:Spring 容器的启动通常从加载配置信息开始。配置信息可以是 XML 文件、注解或者 Java 配置类。
-
XML 配置:通过
ClassPathResource
或FileSystemResource
等类加载 XML 配置文件。 -
注解配置:通过
@Configuration
注解标记的类,Spring 会扫描指定的包路径,查找带有@Component
、@Service
、@Controller
、@Repository
等注解的类。 -
Java 配置:通过
@Configuration
注解的类,定义@Bean
方法,返回需要管理的 Bean 实例。
-
2. 解析配置信息
-
解析 XML 配置:如果使用 XML 配置,Spring 会解析
<bean>
标签,提取 Bean 的类名、属性值、依赖关系等信息,并将其封装为BeanDefinition
对象。 -
解析注解配置:如果使用注解,Spring 会扫描类上的注解(如
@Component
、@Service
等),并根据注解信息创建BeanDefinition
对象。同时,还会解析@Autowired
、@Value
等注解,记录依赖关系。 -
注册 BeanDefinition:将解析得到的
BeanDefinition
对象注册到BeanDefinitionRegistry
中,以便后续的 Bean 实例化和依赖注入。
3. Bean 实例化
-
创建 Bean 实例:Spring 根据
BeanDefinition
中的类信息,通过反射调用无参构造函数创建 Bean 实例。如果 Bean 定义中指定了工厂方法,Spring 会调用工厂方法来创建 Bean 实例。 -
处理 Aware 接口:如果 Bean 实现了
Aware
接口(如BeanFactoryAware
、ApplicationContextAware
等),Spring 会在 Bean 实例化后,将对应的上下文信息注入到 Bean 中。
4. 依赖注入
-
注入属性值:Spring 根据
BeanDefinition
中记录的属性值信息,通过反射调用set
方法或直接操作字段,将属性值注入到 Bean 实例中。 -
注入依赖 Bean:如果 Bean 之间存在依赖关系,Spring 会根据
BeanDefinition
中记录的依赖信息,调用set
方法或构造函数注入依赖的 Bean 实例。
5. 初始化 Bean
-
调用
@PostConstruct
注解的方法:如果 Bean 类中存在带有@PostConstruct
注解的方法,Spring 会在依赖注入完成后调用该方法。 -
调用
InitializingBean
接口的afterPropertiesSet
方法:如果 Bean 实现了InitializingBean
接口,Spring 会调用afterPropertiesSet
方法。 -
调用
init-method
指定的方法:如果在 Bean 定义中指定了init-method
属性,Spring 会调用该方法。
6. 完成初始化
-
注册到容器:完成初始化后,Bean 实例会被注册到 Spring IoC 容器中,供后续使用。
-
触发
ApplicationEvent
:Spring 会触发一些应用事件(如ContextRefreshedEvent
),通知其他组件容器已经初始化完成。
7. 容器销毁
-
调用销毁方法:当 Spring IoC 容器关闭时,会调用 Bean 的销毁方法。如果 Bean 实现了
DisposableBean
接口,会调用destroy
方法;如果指定了destroy-method
属性,会调用该方法。 -
清理资源:Spring 会清理容器中的资源,释放内存。
自己怎么实现一个IOC容器
1. 理解 IoC 容器的核心功能
-
注册(Register):将类或对象与一个标识符(如字符串)关联起来,存储在容器中。
-
解析(Resolve):根据标识符从容器中获取对象,并自动处理对象的依赖关系。
2. 实现步骤
(1)定义一个容器类
容器类需要维护一个字典,用于存储注册的类或对象。
(2)实现注册功能
提供一个方法,允许用户将类或实例与一个标识符关联起来。
(3)实现解析功能
根据标识符获取对象,并处理依赖注入。如果对象有依赖关系,需要递归解析依赖。
spring和springboot区别
Spring 和 Spring Boot 是 Java 开发中非常重要的框架,但它们在设计理念、功能和使用方式上存在一些区别。以下是它们的主要区别:
1. 定义和目标
-
Spring:
-
定义:Spring 是一个轻量级的 Java 开发框架,提供了依赖注入(DI)、面向切面编程(AOP)、事务管理、数据访问抽象等功能。
-
目标:Spring 的核心目标是简化 Java 企业级开发,通过提供各种模块(如 Spring Core、Spring MVC、Spring Data 等)来解决开发中的复杂问题。
-
-
Spring Boot:
-
定义:Spring Boot 是基于 Spring 框架的进一步封装,旨在简化 Spring 应用的初始搭建和开发过程。
-
目标:Spring Boot 的核心目标是“约定优于配置”,通过自动配置(Auto-Configuration)和“启动器”(Starter)来减少开发者的配置工作,快速启动和运行 Spring 应用。
-
2. 配置方式
-
Spring:
-
配置复杂:Spring 需要大量的配置,包括 XML 配置文件、注解配置等。开发者需要手动配置各种 Bean、事务管理器、数据源等。
-
灵活性高:虽然配置复杂,但提供了高度的灵活性,开发者可以自定义几乎所有的配置细节。
-
-
Spring Boot:
-
配置简化:Spring Boot 通过“启动器”(如
spring-boot-starter-web
)和自动配置机制,自动配置了许多常见的场景,减少了大量的配置工作。 -
约定优于配置:遵循 Spring Boot 的默认约定,开发者可以快速搭建应用,而无需手动配置。如果需要自定义配置,也可以通过少量的配置文件(如
application.properties
或application.yml
)来实现。
-
3. 项目启动速度
-
Spring:
-
启动速度较慢:由于需要加载大量的配置文件和初始化各种组件,Spring 项目的启动速度相对较慢。
-
-
Spring Boot:
-
启动速度快:Spring Boot 通过自动配置和优化的类加载机制,大幅提高了项目的启动速度。它还提供了“嵌入式”服务器(如 Tomcat、Jetty),无需部署 WAR 文件,进一步简化了开发流程。
-
4. 依赖管理
-
Spring:
-
依赖管理复杂:在 Spring 项目中,开发者需要手动管理依赖,包括版本号和依赖之间的兼容性。
-
-
Spring Boot:
-
依赖管理简化:Spring Boot 提供了“启动器”(Starter),这些启动器预定义了一组依赖,开发者只需引入相应的启动器即可。Spring Boot 还会自动管理这些依赖的版本,确保兼容性。
-
5. 功能和模块
-
Spring:
-
功能丰富:Spring 提供了丰富的功能模块,如 Spring Core、Spring MVC、Spring Data、Spring Security 等。开发者可以根据需要选择和组合这些模块。
-
模块化设计:Spring 的模块化设计使得开发者可以灵活地使用其中的部分模块,而无需引入整个框架。
-
-
Spring Boot:
-
功能集成:Spring Boot 集成了 Spring 的核心功能,并提供了许多额外的特性,如自动配置、嵌入式服务器、健康检查、度量指标等。
-
一站式解决方案:Spring Boot 提供了一站式的解决方案,适合快速开发和部署微服务和小型项目。
-
6. 适用场景
-
Spring:
-
适用场景:适用于大型企业级应用,尤其是那些需要高度定制化和复杂配置的项目。Spring 提供了强大的功能和灵活性,适合对性能和资源管理有严格要求的场景。
-
-
Spring Boot:
-
适用场景:适用于快速开发和部署小型到中型项目,尤其是微服务架构。Spring Boot 的“约定优于配置”理念使得开发和部署变得非常简单,适合敏捷开发和快速迭代。
-