-
Spring:现代Java开发的必备框架
- Spring创建bean的生命周期以及对应的接口和注解
- Spring使用三级缓存解决循环依赖的原理
- Spring使用三级缓存创建bean的过程
- Spring使用AOP
- SpringAOP的实现原理
- Spring使用事务管理
- Spring事务的原理
- DataSourceTransactionManager的实现
- DataSourceTransactionManager的工作流程
- Spring不太常用的注解
Spring:现代Java开发的必备框架
Spring创建bean的生命周期以及对应的接口和注解
Spring创建bean的生命周期包含以下步骤:
- 实例化Bean:Spring通过构造器或工厂方法来创建Bean实例。
- 设置Bean属性:Spring通过setter方法或直接访问字段来设置Bean的属性值。
- BeanNameAware接口:如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName(方法。
- BeanFactoryAware接口:如果Bean实现了BeanFactoryAware接口,Spring将BeanFactory实例传递给setBeanFactory(方法。
- ApplicationContextAware接口:如果Bean实现了ApplicationContextAware接口,Spring将ApplicationContext实例传递给setApplicationContext(方法。
- Pre-Initialization BeanPostProcessor:在Bean初始化之前,Spring通过调用PostProcessBeforeInitialization(方法提供了一个扩展点,可以在Bean初始化之前对Bean进行定制。
- InitializingBean接口:如果Bean实现了InitializingBean接口,Spring将调用afterPropertiesSet(方法。
- 自定义初始化方法:Bean可以自定义初始化方法,只需要在Bean定义中指定该方法的名称。
- Post-Initialization BeanPostProcessor:在Bean初始化之后,Spring通过调用PostProcessAfterInitialization(方法提供了一个扩展点,可以在Bean初始化之后对Bean进行定制。
- DisposableBean接口:如果Bean实现了DisposableBean接口,Spring将调用destroy(方法。
- 自定义销毁方法:Bean可以自定义销毁方法,只需要在Bean定义中指定该方法的名称。
- @PostConstruct:指定初始化方法,相当于InitializingBean接口的afterPropertiesSet(方法。
- @PreDestroy:指定销毁方法,相当于DisposableBean接口的destroy(方法。
- @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod":指定初始化方法和销毁方法。
Spring使用三级缓存解决循环依赖的原理
- singletonObjects:保存已经完全创建好的单例Bean。
- earlySingletonObjects:保存已经实例化、但是还未填充属性的单例Bean。
- singletonFactories:保存Bean的工厂方法。
Spring使用三级缓存创建bean的过程
Spring使用三级缓存创建Bean的详细过程如下:
- 首先,Spring会检查该Bean是否已经创建并存储在singletonObjects缓存中。如果Bean已经存在,则直接返回该Bean实例。这是最快的情况。
- 如果Bean不存在于singletonObjects缓存中,Spring会检查该Bean是否正在创建中。如果正在创建中,则返回一个代理对象,该代理对象会在真正的Bean创建完成后被替换成真正的Bean对象。这是为了防止循环依赖的情况。
- 如果该Bean既不存在于singletonObjects缓存中,也没有正在创建中,则Spring会创建一个ObjectFactory,该ObjectFactory负责创建该Bean实例。ObjectFactory是一个工厂方法,它负责创建和返回Bean实例。
- 然后,Spring会将该ObjectFactory存储到singletonFactories缓存中,以便下次获取该Bean实例时使用。这是为了提高创建Bean实例的效率。
- 接着,Spring会检查该Bean是否依赖于其他Bean。如果依赖于其他Bean,则会先创建依赖的Bean实例。依赖项可以是其他Bean,也可以是基本类型或集合。
- 如果依赖的Bean实例还不存在,则Spring会递归地创建依赖的Bean实例,直到所有依赖的Bean实例都已经创建完成。这是为了保证依赖关系正确。
- 如果所有依赖的Bean实例都已经创建完成,则Spring会从singletonFactories缓存中获取该Bean的ObjectFactory,并使用该ObjectFactory创建该Bean实例。这是Bean实例的创建过程。
- 创建该Bean实例后,Spring会将该Bean实例存储到earlySingletonObjects缓存中,以便后续填充该Bean的属性。earlySingletonObjects缓存包含已经创建的单例Bean实例,但是还没有填充属性。
- 接着,Spring会递归地填充该Bean的属性。如果该Bean的属性依赖于其他Bean,则会先创建依赖的Bean实例。填充属性之前,Spring会调用所有实现了BeanPostProcessor接口的类的postProcessBeforeInitialization(方法做一些预处理工作。这是为了提供一个扩展点,可以在Bean初始化之前对Bean进行定制。
- 如果所有依赖的Bean实例都已经创建完成,则Spring会从singletonObjects缓存中获取依赖的Bean实例,并将依赖的Bean实例填充到该Bean的属性中。填充属性之后,Spring会再次调用所有实现了BeanPostProcessor接口的类的postProcessAfterInitialization(方法做一些后处理工作。这是为了提供一个扩展点,可以在Bean初始化之后对Bean进行定制。
- 填充该Bean的属性后,Spring会将该Bean实例存储到singletonObjects缓存中,并从earlySingletonObjects缓存中移除该Bean实例。singletonObjects缓存包含已经创建的单例Bean实例,并已经填充了属性。
- 最后,Spring会递归地处理该Bean的后置处理器,然后返回该Bean实例。如果Bean实现了InitializingBean接口,Spring会调用其afterPropertiesSet(方法,这是Bean初始化之后的最后一步。如果Bean实现了DisposableBean接口,Spring会在Bean销毁之前调用其destroy(方法。
Spring使用AOP
- 在配置类上添加@EnableAspectJAutoProxy注解,启用AspectJ自动代理。
- 创建一个切面类,并且在该类上使用@Aspect注解来标识该类为切面类。
- 在切面类中定义一个或多个切点,用来匹配需要拦截的方法。
- 在切面类中定义一个或多个通知,用来在方法执行前、执行后或抛出异常时执行一些额外的逻辑。
- 将切面类添加到Spring的容器中。
以下是一个使用注解方式实现AOP的示例:
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.demo.service.*.*(.."
public void serviceLayer({}
@Before("serviceLayer("
public void logBefore(JoinPoint joinPoint {
System.out.println("Before " + joinPoint.getSignature(.getName(;
}
@After("serviceLayer("
public void logAfter(JoinPoint joinPoint {
System.out.println("After " + joinPoint.getSignature(.getName(;
}
}
@Service
public class DemoService {
public void doSomething( {
System.out.println("Doing something...";
}
}
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example.demo"
public class AppConfig {
}
在上面的示例中,LoggingAspect是一个切面类,它定义了一个切点serviceLayer(和两个通知logBefore(和logAfter(。serviceLayer(用来匹配com.example.demo.service包中所有方法,logBefore(和logAfter(分别在方法执行前和执行后输出一条日志。DemoService是一个普通的服务类,它的doSomething(方法会被LoggingAspect拦截。最后,AppConfig是一个配置类,它启用了AspectJ自动代理,并将LoggingAspect和DemoService添加到Spring的容器中。
SpringAOP的实现原理
Spring使用事务管理
Spring的事务管理可以通过如下方式来使用:
- 配置事务管理器:Spring提供了多种事务管理器,如DataSourceTransactionManager、HibernateTransactionManager等。可以通过配置事务管理器来选择适合的事务管理器。
- 配置事务属性:可以通过配置事务属性来指定事务的传播行为、隔离级别、超时时间、只读等特性。
- 使用@Transactional注解:可以在需要事务管理的方法上添加@Transactional注解,Spring会自动管理该方法的事务。@Transactional注解可以指定事务的传播行为、隔离级别、超时时间、只读等特性。
- REQUIRED:如果当前存在事务,则加入该事务,否则创建一个新的事务。
- SUPPORTS:如果当前存在事务,则加入该事务,否则以非事务的方式执行。
- MANDATORY:必须在一个已有的事务中执行,否则抛出异常。
- REQUIRES_NEW:创建一个新的事务,并且暂停当前事务(如果存在)。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则暂停该事务。
- NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
- NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作。
Spring事务的隔离级别指的是多个事务之间的隔离程度。Spring定义了五种隔离级别,包括:
- DEFAULT:使用底层数据库的默认隔离级别。
- READ_UNCOMMITTED:允许脏读、不可重复读和幻读。
- READ_COMMITTED:禁止脏读,但允许不可重复读和幻读。
- REPEATABLE_READ:禁止脏读和不可重复读,但允许幻读。
- SERIALIZABLE:禁止脏读、不可重复读和幻读,最严格的隔离级别。
可以使用@Transactional注解来指定事务的传播行为、隔离级别、超时时间、只读等特性。例如:
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 3600, readOnly = false
public void doSomething( {
// some code
}
在这个例子中,@Transactional注解指定了事务的传播行为为REQUIRED、隔离级别为DEFAULT、超时时间为3600秒、只读为false。
Spring事务的原理
当一个方法被标记为@Transactional时,Spring会创建一个代理对象来代理该方法。该代理对象会将目标方法的调用转发给事务通知。在事务通知中,会根据事务管理器的配置来开启、提交或回滚事务。如果方法执行过程中发生了异常,则会回滚事务。如果方法执行成功,则会提交事务。事务管理器会将事务的状态存储在ThreadLocal中,以便在同一线程中的其他方法也可以访问该事务。
DataSourceTransactionManager的实现
DataSourceTransactionManager的实现主要包括以下内容:
- 实现了PlatformTransactionManager接口,用于管理事务的生命周期。PlatformTransactionManager接口是Spring事务管理器的核心接口,它定义了事务的生命周期和状态转换规则。DataSourceTransactionManager实现了PlatformTransactionManager接口,用于管理基于DataSource的事务。PlatformTransactionManager接口包括以下方法:
- getTransaction(TransactionDefinition definition:获取一个新的事务或将当前线程中的事务加入到当前方法的事务中。
- commit(TransactionStatus status:提交当前事务。
- rollback(TransactionStatus status:回滚当前事务。
DataSourceTransactionManager的工作流程
- 当一个方法被标记为@Transactional时,Spring会创建一个代理对象来代理该方法。
- 代理对象会调用TransactionAspectSupport类的invokeWithinTransaction(方法,该方法会在事务的上下文中执行目标方法。
- 在invokeWithinTransaction(方法中,会调用DataSourceTransactionManager的doBegin(方法来开启事务。
- 在doBegin(方法中,会获取当前线程中的Connection对象,并将其设置为事务的连接。
- 如果当前线程中没有Connection对象,则会从DataSource中获取一个新的Connection对象,并将其设置为事务的连接。
- 如果事务的隔离级别不是默认值,则会将事务的隔离级别设置到Connection对象上。
- 如果事务的超时时间不是默认值,则会将事务的超时时间设置到Connection对象上。
- 在目标方法执行完毕后,会调用TransactionAspectSupport类的invokeWithinTransaction(方法的afterCompletion(方法来提交或回滚事务。
- 在afterCompletion(方法中,会调用DataSourceTransactionManager的doCleanupAfterCompletion(方法来清理事务状态。
- 在doCleanupAfterCompletion(方法中,会将事务的连接关闭,并将其从当前线程中移除。
Spring不太常用的注解
- @Lazy:指定Bean是否延迟初始化。默认情况下,Spring会在容器启动时创建所有的单例Bean,通过设置@Lazy注解可以将Bean的创建推迟到第一次使用时。这对于那些启动时间较长的应用程序来说非常有用,可以提高应用程序的启动速度。
- @DependsOn:指定Bean依赖的其他Bean。如果被依赖的Bean未被创建,则会先创建该Bean。@DependsOn注解可以用来控制Bean的创建顺序,确保依赖的Bean在当前Bean之前被创建。
- @Primary:在多个Bean实现某个接口时,指定默认使用哪个Bean。当一个接口有多个实现类时,可以使用@Primary注解来指定默认使用哪个实现类。如果没有指定@Primary注解,则需要使用@Qualifier注解来指定使用哪个实现类。
- @Qualifier:指定使用哪个Bean实现某个接口。当有多个Bean实现同一个接口时,可以使用@Qualifier注解来指定使用哪个Bean。@Qualifier注解需要与@Autowired注解一起使用,在注入Bean时指定使用哪个实现类。
- @Profile:指定Bean在特定的环境中才会被创建。可以使用@Profile注解来指定Bean在哪些环境下被创建,例如开发环境、测试环境或生产环境。
- @Value:从属性文件中获取Bean的属性值。可以使用@Value注解来指定Bean的属性值。@Value注解可以用来注入简单类型的值,例如字符串、数字或布尔值。
- @RestController:将一个类声明为RESTful Web服务的控制器。可以使用@RestController注解来将一个类声明为RESTful Web服务的控制器,使其能够处理HTTP请求并返回JSON或XML格式的数据。
- @ExceptionHandler:处理异常。可以使用@ExceptionHandler注解来处理Controller中的异常,当Controller中抛出异常时,会自动调用@ExceptionHandler注解中指定的方法来处理异常。
- “成功的秘诀在于坚持,坚持,再坚持。”——张德芬
- “成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。”——阿斯顿·马丁
- “只有在经历了漫长跋涉之后,才能登上理想的山巅。”——菲茨杰拉德
- “成功的关键在于我们是否真正热爱我们所做的事情,是否做到了最好。”——贺绿汀
- “成功者不是从不失败,而是能够从失败中振作起来。”——乔治·爱德华·伯纳德·肖
- “不要害怕失败,失败是通向成功的必经之路。”——迈克尔·乔丹
成功不是一蹴而就的,它需要我们一步一个脚印地向前走,不断地尝试和学习,不断地改进和完善。在这个过程中,我们可能会遇到挫折和困难,但是只要我们保持信心和勇气,坚持不懈地努力,最终我们一定会迎来成功的喜悦。