深入探究Spring底层核心原理
作者:胡尚
Spring底层核心原理
下面这几行代码是一个Spring的入门代码,第一行是通过java配置类 注解的方式创建一个Spring容器,第二行是通过XML配置文件的方式创建一个Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = (UserService) context.getBean("userService"); userService.test();
最后两行代码就是从Spring容器中拿一个Bean对象并执行方法。那么Spring是如何创建一个Bean对象的嘞?
Bean的生命周期
- 推断构造方法,并执行得到普通对象
- 依赖注入
- aware回调
- 初始化前
执行BeanPostProcessor
接口中的postProcessBeforeInitialization()
方法
- 初始化
执行有@PostConstruct
注解的方法执行
InitializingBean
接口中的afterPropertiesSet()
方法
执行XML配置文件中init-method
属性指定的方法
- 初始化后
执行BeanPostProcessor
接口中的postProcessAfterInitialization()
方法
- 普通对象/代理对象 存入容器中
- 使用
- 销毁
执行DisposableBean
接口的destroy()
方法
有@PreDestroy
注解的方法
XML 配置文件中destroy-method
属性指定的方法
推断构造方法
如果没有写构造方法,那么Spring会执行默认空参的构造方法
如果显示写了一个构造方法,那么Spring就会使用这个构造方法,构造方法中如果有参数那么会进行依赖注入
如果显示写了多个构造方法并有空参的构造方法时,会执行空参的构造方法
如果显示写了多个构造方法没有空参的构造方法时,运行时会报错。解决方法是在要执行的构造方法上加@Autowired
注解
AOP原理
cjlib和jdk两种动态代理的实现都是有一个target属性来存储普通对象,代理对象中重写要执行的方法,首先执行增强逻辑,然后通过target属性去执行目标方法。伪代码如下:
public class UserServiceProxy extends UserService{ private UserService target; public void test(){ // TODO 增强业务 target.test(); // TODO 增强业务 } }
那么如何判断一个Bean是否需要进行AOP创建一个普通对象嘞?
- 遍历所有有
@Aspect
注解的切面Bean - 遍历所有的方法
- 判断方法上的切点表达式是否和当前正在创建的Bean匹配
- 如果匹配则把这个切面中增强方法存入一个Map缓存中
真正要执行代理对象的方法时会从缓存中取出相应的增强逻辑来执行,再去执行目标方法。
Spring事务
Spring中如果要使用事务需要配置一个JdbcTemplate和一个事务管理器,它们俩都需要配置DataSource。
@ComponentScan("com.hs") @Configuration public class AppConfig { @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } @Bean public PlatformTransactionManager transactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource()); return transactionManager; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/hs?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"); dataSource.setUsername("root"); dataSource.setPassword("123456"); return dataSource; } }
Spring事务大致执行流程如下:
- 判断要执行的方法上是否存在
@Transcational
注解 - 如果存在则通过事务管理器创建一个connection连接对象
- autoCommit设置为false
- 去执行目标方法target.method()
- 如果出现了异常则回滚rollback(),没有异常则提交commit()
如果上面的配置类中不加@Configuration
注解,那么Spring的事务会失效。原因如下:
JdbcTemplate和事务管理器都需要DataSource,都会调用dataSource()
获取。如果不加@Configuration
注解,那么他们俩获取的DataSource就不是同一个。
代理对象中操作的是事务管理器的连接对象,而业务方法却是使用的JdbcTemplate,所以就导致了Spring事务失效。
而如果加上了@Configuration
注解,在调用dataSource()
时会先去Spring容器中找DataSource,如果没找到才回去调用方法创建一个。
到此这篇关于深入探究Spring底层核心原理的文章就介绍到这了,更多相关Spring底层原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!