文章目录
0. ApplicationContext
传统的Spring项目,使用配置文件的方式
- 添加maven依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
- bean:Person.java
private String name;
private Integer age;
//默认getter、setter、toString...
- 配置文件:beans.xml
<bean id="person" class="com.atguigu.bean.Person" >
<property name="age" value="18"></property>
<property name="name" value="zhangsan"></property>
</bean>
- 向容器中添加组件:主启动类 MainTest.java
public class MainTest {
public static void main(String[] args) {
//扫描配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//按照id获取组件
Person bean = (Person) applicationContext.getBean("person");
System.out.println(bean);
}
}
- 打印结果
Person [name=zhangsan, age=18]
1. AnnotationConfigApplicationContext
- 添加maven依赖
- bean:Person.java
- 使用配置类代替配置文件
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean
public Person person(){
return new Person("lisi", 20);
}
}
- 向容器中添加组件:主启动类 MainTest.java
public class MainTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
//扫描配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
//按照类型获取
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean);
}
}
- 打印结果
Person [name=lisi, age=20]
- 测试配置类中注册组件的id
//MainTest.java添加
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
System.out.println(name);
}
//打印结果:person
- 修改配置类中容器的方法名为person001
@Configuration //告诉Spring这是一个配置类
public class MainConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean
public Person person001(){
return new Person("lisi", 20);
}
}
//打印结果:person001
2. 组件添加
3. 组件赋值
4. 组件注入
5. AOP
6. 声明式事务
6.1 环境准备:导入依赖:数据源、数据库驱动、Spring-jdbc模块
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
6.2 配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
//数据源
@Bean
public DataSource dataSource() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("0824");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1");
return dataSource;
}
//JdbcTemplate
@Bean
public JdbcTemplate jdbcTemplate() throws Exception{
//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
}
6.3 为什么要添加事务
UserService.java
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void insertUser(){
userDao.insert();
System.out.println("插入完成...");
}
}
UserDao .java
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "INSERT INTO `tbl_user`(name,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username,19);
}
}
测试
public class IOCTest_Tx {
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
applicationContext.close();
}
}
数据库插入数据:
id | name | age |
---|---|---|
1 | 94fb9 | 19 |
模拟:当操作数据库出现错误,依旧会插入新的数据,修改UserService.insertUser
public void insertUser(){
userDao.insert();
System.out.println("插入完成...");
int i = 10/0;//出错
}
id | name | age |
---|---|---|
1 | 94fb9 | 19 |
2 | 87f70 | 19 |
6.4 如何添加事务
使用xml文件配置事务
<!-- 1. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 2. 配置事务属性 -->
<!--<tx:advice>元素声明事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 根据方法名指定事务的属性 -->
<tx:method name="*"/>
<!--propagation配置事务传播行为-->
<tx:method name="purchase" propagation="REQUIRES_NEW"/>
<!--isolation配置事务的隔离级别-->
<tx:method name="update*" isolation="SERIALIZABLE"/>
<!--rollback-for配置事务遇到异常必须回滚,no-rollback-for配置事务遇到异常必须不能回滚-->
<tx:method name="add*" rollback-for="java.io.IOException" no-rollback-for="com.dmsd.spring.tx.BookStockException"/>
<!--read-only配置事务只读属性-->
<tx:method name="find*" read-only="true"/>
<!--timeout配置事务的超时属性-->
<tx:method name="get*" timeout="3"/>
</tx:attributes>
</tx:advice>
<!-- 3. 配置事务切入点, 以及把事务切入点和事务属性关联起来 -->
<aop:config>
<aop:pointcut expression="execution(* com.atguigu.spring.tx.xml.service.*.*(..))"
id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
使用注解配置事务
- 给UserService.insertUser方法上标注 @Transactional 表示当前方法是一个事务方法
- 给配置类TxConfig.java上标注@EnableTransactionManagement ,开启基于注解的事务管理功能,等同于xml配置中的< tx:annotation-driven />
- 配置事务管理器 PlatformTransactionManager 来控制事务
修改如下:
@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
//省略。。。
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws Exception{
return new DataSourceTransactionManager(dataSource());
}
}
@Transactional
public void insertUser(){
userDao.insert();
System.out.println("插入完成...");
int i = 10/0;//出错
}
6.5 源码分析
- @EnableTransactionManagement注解做了什么?
导入TransactionManagementConfigurationSelector.class
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
}
重写了selectImports方法,依据adviceMode,返回不同的类,而EnableTransactionManagement定义默认的AdviceMode为AdviceMode.PROXY,所以会导入AutoProxyRegistrar.class、ProxyTransactionManagementConfiguration.class这两个组件
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
- AutoProxyRegistrar.class做了什么?
调用registerBeanDefinitions方法,
get(“mode”),默认是AdviceMode.PROXY
get(“proxyTargetClass”),默认是false
执行AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)方法
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//省略...
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
//省略...
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
//省略...
}
}
registerAutoProxyCreatorIfNecessary方法往容器中注册了InfrastructureAdvisorAutoProxyCreator.class这个组件
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
InfrastructureAdvisorAutoProxyCreator.class利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
- ProxyTransactionManagementConfiguration.class做了什么?
ProxyTransactionManagementConfiguration 也是一个配置类,给容器中添加组件,首先给容器中注册事务增强器transactionAdvisor,然后advisor.setTransactionAttributeSource(transactionAttributeSource())设置事务注解信息,transactionAttributeSource返回new AnnotationTransactionAttributeSource()
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
AnnotationTransactionAttributeSource调用this,this.annotationParsers.add(new SpringTransactionAnnotationParser())添加Spring注解解析器
public AnnotationTransactionAttributeSource() {
this(true);
}
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
SpringTransactionAnnotationParser 注解解析器解析@Transactional注解的属性值
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
}
事务增强器transactionAdvisor除了能设置事务注解信息,还能设置事务拦截器advisor.setAdvice(transactionInterceptor())。事务拦截器也是先设置事务属性setTransactionAttributeSource(transactionAttributeSource()),然后设置事务管理器setTransactionManager(this.txManager)
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
//省略...
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
//省略...
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
transactionInterceptor是一个MethodInterceptor方法拦截器,之前的AutoProxyRegistrar给容器中返回一个代理对象,代理对象执行目标方法时,方法拦截器开始工作,怎么工作呢?
在目标方法执行时,先执行拦截器链,这里的拦截器只有一个,就是transactionInterceptor,其中有invoke方法,返回invokeWithinTransaction
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
}
invokeWithinTransaction方法先获取事务属性TransactionAttribute txAttr,再获取事务管理器PlatformTransactionManager tm。
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
}
}
如何获取事务管理器?如果已经配置过多个事务管理器,在注解中指定事务管理器@Transactional(transactionManager=" “)或者@Transactional(value=” "),就能获取到指定的事务管理器。
如果没有配置过,defaultTransactionManager 为null,从ioc容器beanFactory中依据类型getBean(PlatformTransactionManager.class)生成默认的PlatformTransactionManager事务管理器。
protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
}
else {
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
有了事务管理器,如何执行目标方法?先判断是不是回滚的事务管理器,如果不是,proceedWithInvocation执行目标方法,有异常执行回滚操作。没有异常,commitTransactionAfterReturning提交事务
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
//省略...
}
}