关于proxy模式下,@Transactional标签在创建代理对象时的应用
2016-03-26 16:08
549 查看
@Transactional标签用于Spring中的事务标记。
先简单说下几个概念:
1)Spring的AOP是应用于Spring管理的bean上并基于代理实现的,代理的方法有java动态代理和CGLib动态代理方式,在不进行任何设置时,如果一个被代理的类实现了接口,就优先使用java动态代理。
2)Spring在bean的创建过程中将代理应用于bean上,代理的创建有这么一个重要的类AbstractAutoProxyCreator,这个类用于自动代理的创建,而这个类实现的接口中有BeanPostProcessor这个接口。但是这个类是一个抽象类,因为系统会根据不同的配置方式创建不同的子类:
对于aop:config的标签,创建的是AspectJAwareAdvisorAutoProxyCreator类,对于aspectj-autoproxy标签,创建的是AnnotationAwareAspectJAutoProxyCreator类。其继承结构如下:
3)BeanPostProcessor的几个方法都是钩子函数,Spring容器管理的bean在创建过程中会调用实现了BeanPostProcessor的类的几个方法,用于修改创建的bean的实例。
4)Spring中aop采用了aopalliance的约定,Advice是一个标记接口,其子接口为Interceptor,事务的实现类就是一个Interceptor。Advisor接口用来包含Advice和其他一些信息,分为IntroductionAdvisor和PointcutAdvisor两个分支,前者只能应用于类层面。事务管理中的Advisor类是BeanFactoryTransactionAttributeSourceAdvisor,是PointcutAdvisor的一个分支。
5)事务的Interceptor为TransactionInterceptor
那么我们从AbstractAutoProxyCreator作为入口进行源代码的分析:
首先看实现的BeanPostProcessor的钩子函数
这个方法的注释说明了这个方法的作用是:创建代理并应用所配置的interceptor于其上。
沿着这个方法继续查看wrapIfNecessary方法的代码片断:
可以发现,系统将查找应用于这个bean上的advice和advisor,然后根据此创建代理。getAdvicesAndAdvisorsForBean这个方式是一个模板方法,具体的实现由子类AbstractAdvisorAutoProxyCreator实现。
子类中getAdvicesAndAdvisorsForBean调用了findEligibleAdvisors函数:
findCandidateAdvisors会查找系统中所有实现了Advisor接口的bean。
然后findAdvisorsThatCanApply在所有Advisor中过滤适用于当前正在创建的bean的Advisor。
我们追踪findAdvisorsThatCanApply的函数调用,会发现此功能委托给了AopUtils.findAdvisorsThatCanApply函数,查找PointcutAdvisor类型的过滤,定位到AopUtils类的如下函数:
上述代码中:Pointcut pc参数是PointcutAdvisor保存的切点的信息,对于BeanFactoryTransactionAttributeSourceAdvisor,它是TransactionAttributeSourcePointcut。MethodMatcher是切点的属性,用于判断一个方法是否适用于advice,TransactionAttributeSourcePointcut在继承体系上实现了MethodMatcher接口,将返回this。上述代码中,methodMatcher.matches(method, targetClass)即是TransactionAttributeSourcePointcut的match方法的调用,代码如下:
此时会从目标类和方法中获取TransactionAttribute,它包含了事务的定义,对于以标签形式定义的事务,它是AnnotationTransactionAttributeSource。查看AnnotationTransactionAttributeSource的getTransactionAttribute方法,它的定义位于父类:
系统将先从Map的缓存查找,若没有,则调用
computeTransactionAttribute,这个方法定义也位于父类:
这个函数很好的说明了@Transactional标签的查找顺序。
我们查看方法上的@Transactional标签的查找,调用归为自身的如下方法:
可见,@Transactional标签的解析是由TransactionAnnotationParser接口列表解析完成的,这个接口列表默认只有SpringTransactionAnnotationParser。SpringTransactionAnnotationParser的parseTransactionAnnotation方法将解析Transactional标签并将其属性转换到TransactionAttribute的实现类RuleBasedTransactionAttribute。
到此为止,对于具有TransactionAttribute的解析完成并加入缓存。
对于当前bean适用的advisor也判断完成,回到AbstractAutoProxyCreator的wrapIfNecessary方法,如果存在advisor的话,将调用createProxy方法,创建代理的过程最终会归结为CglibAopProxy和JdkDynamicAopProxy两个类上,分别对应两种类型的代理的创建。
代理创建好后,执行代理上的一个方法将会执行特定的代理函数,对于CglibAopProxy创建的代理,这个方法是CglibAopProxy内部的DynamicAdvisedInterceptor类的intercept方法,对于JdkDynamicAopProxy为invoke方法。
这两个方法中都会获取interception链:
然后追踪函数,发现系统先从缓存中获取,若缓存不存在则调用DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法,贴一段这个方法的代码片段:
这里获取的MethodInterceptor[] interceptors是TransactionInterceptor。
而且又看到了MethodMatcher!只是将比较放在了MethodMatchers.matches中了而已:
上述方法如果判定匹配的话,则将interceptors返回。
TransactionInterceptor的invoke方法将在代理对象的方法被调用前调用:
看到这里,对于在代理对象上调用一个方法时事务是否作用以及如何作用相信已经清楚了。
转载请注明出处!
先简单说下几个概念:
1)Spring的AOP是应用于Spring管理的bean上并基于代理实现的,代理的方法有java动态代理和CGLib动态代理方式,在不进行任何设置时,如果一个被代理的类实现了接口,就优先使用java动态代理。
2)Spring在bean的创建过程中将代理应用于bean上,代理的创建有这么一个重要的类AbstractAutoProxyCreator,这个类用于自动代理的创建,而这个类实现的接口中有BeanPostProcessor这个接口。但是这个类是一个抽象类,因为系统会根据不同的配置方式创建不同的子类:
对于aop:config的标签,创建的是AspectJAwareAdvisorAutoProxyCreator类,对于aspectj-autoproxy标签,创建的是AnnotationAwareAspectJAutoProxyCreator类。其继承结构如下:
3)BeanPostProcessor的几个方法都是钩子函数,Spring容器管理的bean在创建过程中会调用实现了BeanPostProcessor的类的几个方法,用于修改创建的bean的实例。
4)Spring中aop采用了aopalliance的约定,Advice是一个标记接口,其子接口为Interceptor,事务的实现类就是一个Interceptor。Advisor接口用来包含Advice和其他一些信息,分为IntroductionAdvisor和PointcutAdvisor两个分支,前者只能应用于类层面。事务管理中的Advisor类是BeanFactoryTransactionAttributeSourceAdvisor,是PointcutAdvisor的一个分支。
5)事务的Interceptor为TransactionInterceptor
那么我们从AbstractAutoProxyCreator作为入口进行源代码的分析:
首先看实现的BeanPostProcessor的钩子函数
/** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.containsKey(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
这个方法的注释说明了这个方法的作用是:创建代理并应用所配置的interceptor于其上。
沿着这个方法继续查看wrapIfNecessary方法的代码片断:
// Create proxy if we have advice. // 查找这个bean的adive和advisor Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { // 加入缓存 this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建代理 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; }
可以发现,系统将查找应用于这个bean上的advice和advisor,然后根据此创建代理。getAdvicesAndAdvisorsForBean这个方式是一个模板方法,具体的实现由子类AbstractAdvisorAutoProxyCreator实现。
子类中getAdvicesAndAdvisorsForBean调用了findEligibleAdvisors函数:
//找到所有advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); //过滤适用于这个bean的advisor List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
findCandidateAdvisors会查找系统中所有实现了Advisor接口的bean。
然后findAdvisorsThatCanApply在所有Advisor中过滤适用于当前正在创建的bean的Advisor。
我们追踪findAdvisorsThatCanApply的函数调用,会发现此功能委托给了AopUtils.findAdvisorsThatCanApply函数,查找PointcutAdvisor类型的过滤,定位到AopUtils类的如下函数:
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(); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); //扫描targetClass(即创建过程的bean所在的类)实现的所有接口和其自身类的每个方法 for (Class<?> clazz : classes) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } } return false; }
上述代码中:Pointcut pc参数是PointcutAdvisor保存的切点的信息,对于BeanFactoryTransactionAttributeSourceAdvisor,它是TransactionAttributeSourcePointcut。MethodMatcher是切点的属性,用于判断一个方法是否适用于advice,TransactionAttributeSourcePointcut在继承体系上实现了MethodMatcher接口,将返回this。上述代码中,methodMatcher.matches(method, targetClass)即是TransactionAttributeSourcePointcut的match方法的调用,代码如下:
public boolean matches(Method method, Class targetClass) { TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
此时会从目标类和方法中获取TransactionAttribute,它包含了事务的定义,对于以标签形式定义的事务,它是AnnotationTransactionAttributeSource。查看AnnotationTransactionAttributeSource的getTransactionAttribute方法,它的定义位于父类:
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) { // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); Object cached = this.attributeCache.get(cacheKey); if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return (TransactionAttribute) cached; } } else { // We need to work it out. TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass); // Put it in the cache. if (txAtt == null) { this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { if (logger.isDebugEnabled()) { Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass()); logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." + method.getName() + "' with attribute: " + txAtt); } this.attributeCache.put(cacheKey, txAtt); } return txAtt; } }
系统将先从Map的缓存查找,若没有,则调用
computeTransactionAttribute,这个方法定义也位于父类:
private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // Ignore CGLIB subclasses - introspect the actual user class. Class<?> userClass = ClassUtils.getUserClass(targetClass); // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); // If we are dealing with method with generic parameters, find the original method. specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); // First try is the method in the target class. TransactionAttribute txAtt = findTransactionAttribute(specificMethod); if (txAtt != null) { return txAtt; } // Second try is the transaction attribute on the target class. txAtt = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAtt != null) { return txAtt; } if (specificMethod != method) { // Fallback is to look at the original method. txAtt = findTransactionAttribute(method); if (txAtt != null) { return txAtt; } // Last fallback is the class of the original method. return findTransactionAttribute(method.getDeclaringClass()); } return null; }
这个函数很好的说明了@Transactional标签的查找顺序。
我们查看方法上的@Transactional标签的查找,调用归为自身的如下方法:
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) { for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae); if (attr != null) { return attr; } } return null; }
可见,@Transactional标签的解析是由TransactionAnnotationParser接口列表解析完成的,这个接口列表默认只有SpringTransactionAnnotationParser。SpringTransactionAnnotationParser的parseTransactionAnnotation方法将解析Transactional标签并将其属性转换到TransactionAttribute的实现类RuleBasedTransactionAttribute。
到此为止,对于具有TransactionAttribute的解析完成并加入缓存。
对于当前bean适用的advisor也判断完成,回到AbstractAutoProxyCreator的wrapIfNecessary方法,如果存在advisor的话,将调用createProxy方法,创建代理的过程最终会归结为CglibAopProxy和JdkDynamicAopProxy两个类上,分别对应两种类型的代理的创建。
代理创建好后,执行代理上的一个方法将会执行特定的代理函数,对于CglibAopProxy创建的代理,这个方法是CglibAopProxy内部的DynamicAdvisedInterceptor类的intercept方法,对于JdkDynamicAopProxy为invoke方法。
这两个方法中都会获取interception链:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
然后追踪函数,发现系统先从缓存中获取,若缓存不存在则调用DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法,贴一段这个方法的代码片段:
if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } }
这里获取的MethodInterceptor[] interceptors是TransactionInterceptor。
而且又看到了MethodMatcher!只是将比较放在了MethodMatchers.matches中了而已:
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(mm, "MethodMatcher must not be null"); return ((mm instanceof IntroductionAwareMethodMatcher && ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) || mm.matches(method, targetClass)); }
上述方法如果判定匹配的话,则将interceptors返回。
TransactionInterceptor的invoke方法将在代理对象的方法被调用前调用:
public Object invoke(final MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } }); }
看到这里,对于在代理对象上调用一个方法时事务是否作用以及如何作用相信已经清楚了。
转载请注明出处!
相关文章推荐
- ACM1005,纸币问题
- Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
- win7系统运行会声会影提示错误代码1317的解决方法
- wamp2.5 配置多端口多站点虚拟主机 新建站点
- 限制文本框只能输入数字及小数点
- EasyUI向后台发送page和rows
- neo4j删除/查看(node/relationship)
- jquery+正則表達式验证邮箱格式的样例
- 网速监控 v1.6.1(C#,源代码)
- padding和layout_margin
- Android之自定义控件深入
- Hive连接Mysql---FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask.
- js实现九九乘法表
- ASCLL表
- Context 上下文
- 【c++】字符串---去除重复字符
- Magic Trackpad 2 on win10 x64
- POJ 2777 Count Color (线段树)
- C语言—sscanf函数使用总结
- 支付宝回调