Spring——Spring注解驱动开发(容器篇)

0. ApplicationContext

传统的Spring项目,使用配置文件的方式

  1. 添加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>
  1. bean:Person.java
private String name;
private Integer age;
//默认getter、setter、toString...
  1. 配置文件:beans.xml
<bean id="person" class="com.atguigu.bean.Person" >
	<property name="age" value="18"></property>
	<property name="name" value="zhangsan"></property>
</bean>
  1. 向容器中添加组件:主启动类 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);
}
}
  1. 打印结果
Person [name=zhangsan, age=18]

1. AnnotationConfigApplicationContext

  1. 添加maven依赖
  2. bean:Person.java
  3. 使用配置类代替配置文件
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {	
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean
	public Person person(){
		return new Person("lisi", 20);
	}
}
  1. 向容器中添加组件:主启动类 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);
	}
}
  1. 打印结果
Person [name=lisi, age=20]
  1. 测试配置类中注册组件的id
//MainTest.java添加
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
	System.out.println(name);
}
//打印结果:person
  1. 修改配置类中容器的方法名为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();
	}
}

数据库插入数据:

idnameage
194fb919

模拟:当操作数据库出现错误,依旧会插入新的数据,修改UserService.insertUser

public void insertUser(){
	userDao.insert();
	System.out.println("插入完成...");
	int i = 10/0;//出错
}
idnameage
194fb919
287f7019

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>

使用注解配置事务

  1. 给UserService.insertUser方法上标注 @Transactional 表示当前方法是一个事务方法
  2. 给配置类TxConfig.java上标注@EnableTransactionManagement ,开启基于注解的事务管理功能,等同于xml配置中的< tx:annotation-driven />
  3. 配置事务管理器 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 源码分析

  1. @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;
		}
	}
}
  1. 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);
	}
}
  1. 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.
			//省略...	
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值