事务配置文件
<!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="append*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="repair" propagation="REQUIRED" />
<tx:method name="delAndRepair" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="load*" propagation="SUPPORTS" />
<tx:method name="search*" propagation="SUPPORTS" />
<tx:method name="datagrid*" propagation="SUPPORTS" />
<tx:method name="*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transactionPointcut" expression="execution(* blog.service.imp.BlogService.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
</aop:config>
通过前面介绍spring自定义命名空间可以知道上面事务配置使用了两个自定义命名空间tx和aop。这里我们直接看aop的命名空间。找到spring中AOP的源码可以
http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
那么aop命名空间的配置使用AopNamespaceHandler
来解析。进入代码可以看到解析的类registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
//org.springframework.aop.config.ConfigBeanDefinitionParser#parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
//这一步很重要采用BeanPostProcessor自动创建代理类:AspectJAwareAdvisorAutoProxyCreator
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
//pointcut会被映射成 AspectJExpressionPointcut
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
//advisor会被注册成 DefaultBeanFactoryPointcutAdvisor
//持有AspectJExpressionPointcut和TransactionInterceptor
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
我们知道在使用AOP托管事务时,如果想要在自己的代码前后添加开启事务和关闭事务必然需要使用代理来实现。那么问题来了难道所有的service层的类都是代理类不成,如果是那这些service层的代理类是在什么时候生成的呢?现在来回答上面的问题。
- 所有service层的类确实都是代理类,不然就没办法注入事务代码
- spring使用Bean生命周期中的BeanPostProcessor来创建代理类。也就是在类实例前先调用
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
确实是否需要创建代理类
分析实现过程
下面是具体实现
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//创建BeanDefinition。这个BeanDefinition的class是:AspectJAwareAdvisorAutoProxyCreator
//AspectJAwareAdvisorAutoProxyCreator会实现BeanDefinition接口,在IOC容器创建对象的时候会执行AspectJAwareAdvisorAutoProxyCreator里面的postProcessAfterInstantiation方法
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//将AspectJAwareAdvisorAutoProxyCreator注册到IOC容器中
registerComponentIfNecessary(beanDefinition, parserContext);
}
一旦AspectJAwareAdvisorAutoProxyCreator
注册到容器中,那么所有类在实例的时候会自动调用postProcessAfterInitialization
这个方法。(不清楚BeanPostProcessor的同学可以在网上找一下相关文章,很好理解。这篇文章先继续介绍事务的源码)那么在创建对象的时候会进入下面代码
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//查询配置中的execution(* blog.service.imp.BlogService.*(..))表达式
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//将上面的表达式和当前的Bean对比看是不是需要被代理的类。下面方法最终会用到Pointcut类里面的methodMatcher方法进行对比还有classFilter.matches来对比类
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//如果没有匹配上eligibleAdvisors为空
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
来分析一下上面的代码
- 首先我们需要知道只要是IOC容器里面的类就都会进过上面的方法逻辑
- 需要通过一定的规则过滤掉不需要代理的类
- 我们在配置AOP的时候使用pointcut,这个pointcut就是用来判断进入这个方法里面的类是否需要创建代理
- 首先获得配置里面所有的
execution(* blog.service.imp.BlogService.*(..))表达式
- 然后按照pointcut里面的ClassFilter过滤类
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
// 省略部分代码.....
}
这样最终可以判断需要代理的类就生成代理类。
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
上面创建代理类的过程和我们自己写的代理类过程类似创建proxyFactory设置目标对象(TargetSource)和增强(Advisors)