Spring注解驱动开发(五)
声明式事务-环境搭建
- 导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
- 配置数据源、JdbcTemplate(Spring提供简化数据库操作的工具)操作数据
@PropertySource({"classpath:dbconfig.properties"})
@Configuration
public class TxConfig {
//数据源
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("12358");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
//Spring会的@Configuration类会做特殊的处理:给容器中添加组件,多次调用都是从容器中找组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
}
- 在mysql数据库中创建一张表
- 创建配置类:
/**
声明式事务:
环境搭建:
1.导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
2.配置数据源、JdbcTemplate(Spring提供简化数据库操作的工具)操作数据
*/
@ComponentScan({"com.ldc.tx"})
@PropertySource({"classpath:dbconfig.properties"})
@Configuration
public class TxConfig {
//数据源
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("12358");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
//Spring会的@Configuration类会做特殊的处理:给容器中添加组件,多次调用都是从容器中找组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
}
- 创建UserService类:
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void insertUser() {
userDao.insert();
System.out.println("插入完成...");
}
}
- 创建UserDao
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert() {
String sql = "INSERT INTO `tbl_user` (username,age)VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username, 19);
}
}
- 我们来测试一下:
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
}
测试结果为:
插入完成…
此时数据也进来了:
此时默认是没有事务的:这里int i = 10/0;会出现异常,此时没有事务,插入的方法也不会回滚;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void insertUser() {
userDao.insert();
System.out.println("插入完成...");
int i = 10 / 0;
}
}
我们重新来运行一下测试方法:
虽然出现了异常,但是数据还是插入进来了:
声明式事务-测试成功
我们可以给方法上面加入@Transactional
这个注解:
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser() {
userDao.insert();
System.out.println("插入完成...");
int i = 10 / 0;
}
}
但是只是加上这样的一个注解还是不行的,我们还需要:
4.@EnableTransactionManagement 开启基于注解的事务管理功能;
5.配置事务管理器来控制事务
/**
声明式事务:
环境搭建:
1.导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
2.配置数据源、JdbcTemplate(Spring提供简化数据库操作的工具)操作数据
3.给方法上标注@Transactional注解表示当前的方法是一个事务方法;
4.@EnableTransactionManagement 开启基于注解的事务管理功能;
5.配置事务管理器来控制事务
*/
@ComponentScan({"com.ldc.tx"})
@PropertySource({"classpath:dbconfig.properties"})
@Configuration
@EnableTransactionManagement
public class TxConfig {
//数据源
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("12358");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
//Spring会的@Configuration类会做特殊的处理:给容器中添加组件,多次调用都是从容器中找组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws PropertyVetoException {
return new DataSourceTransactionManager(dataSource());
}
}
这个时候,我们再来运行测试方法,数据就没有插入成功了,事务就已经生效了;
声明式事务:
环境搭建:
1.导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
2.配置数据源、JdbcTemplate(Spring提供简化数据库操作的工具)操作数据
3.给方法上标注@Transactional注解表示当前的方法是一个事务方法;
4.@EnableTransactionManagement 开启基于注解的事务管理功能;
5.配置事务管理器来控制事务(必须要有这一步)
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws PropertyVetoException {
return new DataSourceTransactionManager(dataSource());
}
[源码]-声明式事务-源码分析
声明式事务:
环境搭建:
1、导入相关依赖
数据源、数据库驱动、Spring-jdbc模块
2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
@EnableXXX
5、配置事务管理器来控制事务;
@Bean
public PlatformTransactionManager transactionManager()
原理:
1)、@EnableTransactionManagement
利用TransactionManagementConfigurationSelector给容器中会导入组件
导入两个组件
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
2)、AutoProxyRegistrar:
给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
InfrastructureAdvisorAutoProxyCreator:?
利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
3)、ProxyTransactionManagementConfiguration 做了什么?
1、给容器中注册事务增强器;
1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
2)、事务拦截器:
TransactionInterceptor;保存了事务属性信息,事务管理器;
他是一个 MethodInterceptor;
在目标方法执行的时候;
执行拦截器链;
事务拦截器:
1)、先获取事务相关的属性
2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
最终会从容器中按照类型获取一个PlatformTransactionManager;
3)、执行目标方法
如果异常,获取到事务管理器,利用事务管理回滚操作;
如果正常,利用事务管理器,提交事务
扩展原理-BeanFactoryPostProcessor
扩展原理:
BeanPostProcessor:bean的后置处理器,bean创建对象初始化前后进行拦截工作的
BeanFactoryPostProcessor:BeanFactory的后置处理器,在BeanFactory的标准初始化之后调用
所有bean的定义已经保存加载到BeanFactory,但是bean的实例还未创建
/**
* 扩展原理:
* BeanPostProcessor:bean的后置处理器,bean创建对象初始化前后进行拦截工作的
*
* BeanFactoryPostProcessor:BeanFactory的后置处理器,在BeanFactory的标准初始化之后调用
* 所有bean的定义已经保存加载到BeanFactory,但是bean的实例还未创建
*/
@Configuration
@ComponentScan("com.ldc.ext")
public class ExtConfig {
@Bean
public Blue blue() {
return new Blue();
}
}
我们来手动写上一个:MyBeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor...PostProcessorBeanFactory...");
int count = beanFactory.getBeanDefinitionCount();
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
System.out.println("当前的BeanFactory中有"+count+"个Bean");
Stream.of(beanDefinitionNames).forEach(System.out::println);
}
}
我们再来测试:
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
}
运行结果:
MyBeanFactoryPostProcessor…PostProcessorBeanFactory…
当前的BeanFactory中有9个Bean
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
extConfig
myBeanFactoryPostProcessor
blue
我们可以看到MyBeanFactoryPostProcessor是在所有的bean创建之前执行的;
我们以debug来运行:
BeanFactoryPostProcessor原理:
1)、ioc容器创建对象
2)、invokeBeanFactoryPostProcessors(beanFactory);
如何找到所有的BeanFactoryPostProcessor并执行他们的方法;
1)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
2)、在初始化创建其他组件前面执行
扩展原理-BeanDefinitionRegistryPostProcessor
2、BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
postProcessBeanDefinitionRegistry();
在所有bean定义信息将要被加载,bean实例还未创建的;
优先于BeanFactoryPostProcessor执行;
利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件;
原理:
1)、ioc创建对象
2)、refresh()-》invokeBeanFactoryPostProcessors(beanFactory);
3)、从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件。
1、依次触发所有的postProcessBeanDefinitionRegistry()方法
2、再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor;
4)、再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法
我们自己来创建一个:
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量"+beanFactory.getBeanDefinitionCount());
}
//BeanDefinitionRegistry是bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean的定义信息创建bean的实例
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量"+registry.getBeanDefinitionCount());
RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
registry.registerBeanDefinition("hello",beanDefinition);
}
}
运行测试方法,运行结果为:
MyBeanDefinitionRegistryPostProcessor…bean的数量10
MyBeanDefinitionRegistryPostProcessor…bean的数量11
MyBeanFactoryPostProcessor…PostProcessorBeanFactory…
当前的BeanFactory中有11个Bean
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
extConfig
myBeanDefinitionRegistryPostProcessor
myBeanFactoryPostProcessor
blue
hello
扩展原理-ApplicationListener用法
3、ApplicationListener:监听容器中发布的事件。事件驱动模型开发;
public interface ApplicationListener<E extends ApplicationEvent>
监听 ApplicationEvent 及其下面的子事件;
步骤:
1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)
@EventListener;
原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener;
2)、把监听器加入到容器;
3)、只要容器中有相关事件的发布,我们就能监听到这个事件;
ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件;
ContextClosedEvent:关闭容器会发布这个事件;
4)、发布一个事件:
applicationContext.publishEvent();
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
//当容器中发布次事件,方法触发
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到的事件"+event);
}
}
我们再来运行测试方法:
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
applicationContext.close();
}
运行结果:
MyBeanDefinitionRegistryPostProcessor…bean的数量11
MyBeanDefinitionRegistryPostProcessor…bean的数量12
MyBeanFactoryPostProcessor…PostProcessorBeanFactory…
当前的BeanFactory中有12个Bean
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
extConfig
myApplicationListener
myBeanDefinitionRegistryPostProcessor
myBeanFactoryPostProcessor
blue
hello
收到的事件org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3a4afd8d: startup date [Wed Jan 16 20:51:59 CST 2019]; root of context hierarchy]
收到的事件org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3a4afd8d: startup date [Wed Jan 16 20:51:59 CST 2019]; root of context hierarchy]
扩展原理-ApplicationListener原理
原理:
ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的时间]、ContextClosedEvent;
1)、ContextRefreshedEvent事件:
1)、容器创建对象:refresh();
2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
2)、自己发布事件;
3)、容器关闭会发布ContextClosedEvent;
【事件发布流程】:
3)、publishEvent(new ContextRefreshedEvent(this));
1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
2)、multicastEvent派发事件:
3)、获取到所有的ApplicationListener;
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
1)、如果有Executor,可以支持使用Executor进行异步派发;
Executor executor = getTaskExecutor();
2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);
拿到listener回调onApplicationEvent方法;
【事件多播器(派发器)】
1)、容器创建对象:refresh();
2)、initApplicationEventMulticaster();初始化ApplicationEventMulticaster;
1)、先去容器中找有没有id=“applicationEventMulticaster”的组件;
2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;
【容器中有哪些监听器】
1)、容器创建对象:refresh();
2)、registerListeners();
从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
//将listener注册到ApplicationEventMulticaster中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
扩展原理-@EventListener与SmartInitializingSingleton
@Service
public class UserService {
@EventListener(classes = {ApplicationEvent.class})
public void listen(ApplicationEvent event) {
System.out.println("UserService监听的事件"+event);
}
}
运行结果:
MyBeanDefinitionRegistryPostProcessor…bean的数量12
MyBeanDefinitionRegistryPostProcessor…bean的数量13
MyBeanFactoryPostProcessor…PostProcessorBeanFactory…
当前的BeanFactory中有13个Bean
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
extConfig
myApplicationListener
myBeanDefinitionRegistryPostProcessor
myBeanFactoryPostProcessor
userService
blue
hello
UserService监听的事件org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3a4afd8d: startup date [Wed Jan 16 21:11:12 CST 2019]; root of context hierarchy]
收到的事件org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3a4afd8d: startup date [Wed Jan 16 21:11:12 CST 2019]; root of context hierarchy]
UserService监听的事件org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3a4afd8d: startup date [Wed Jan 16 21:11:12 CST 2019]; root of context hierarchy]
收到的事件org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3a4afd8d: startup date [Wed Jan 16 21:11:12 CST 2019]; root of context hierarchy]
SmartInitializingSingleton 原理:->afterSingletonsInstantiated();
1)、ioc容器创建对象并refresh();
2)、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;
1)、先创建所有的单实例bean;getBean();
2)、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;
如果是就调用afterSingletonsInstantiated();