从InfrastructureAdvisorAutoProxyCreator的层次结构中可以看到,InfrastructureAdvisorAutoProxyCreator间接实现了SmartInstantiationAwareBeanPostProcessor,而SmartInstantiationAwareBeanPostProcessor又继承自InstantiationAwareBeanPostProcessor,也就是说在Spring中,所有bean实例化时Spring都会保证调用其postProcessAfterInitialization方法,其实现是在父类AbstractAutoProxyCreator类中实现。

    @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
//根据给定的bean的class和name构建出个key,beanClassName_beanName
       Object cacheKey = getCacheKey(bean.getClass(), beanName);
       //是否是由于避免循环依赖而创建的bean代理
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

这里实现的主要目的是对指定bean进行封装,当然首先要确定是否需要封装,检测及封装的工作都委托给了wrapIfNecessary函数进行。

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
     //如果已经处理过
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
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;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

wrapIfNecessary函数功能实现起来很复杂,但是逻辑上理解起来还是相对简单的,在wrapIfNecessary函数中主要的工作如下。

(1)找出指定bean对应的增强器。

(2)根据找出的增强器创建代理。

获取对应class/method的增强器

获取指定bean对应的增强器,其中包含两个关键字:增强器与对应。也就是说在getAdvicesAndAdvisorsForBean函数中,不但要找出增强器,而且还需要判断增强器是否满足要求。

    @Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
} protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

渐渐地体会到了 Spring 中代码的优秀,即使是一个很复杂的逻辑,在 Spring中也会被拆分成若干个小的逻辑,然后在每个函数中实现,使得每个函数的逻辑简单到我们能快速地理解,而不会像有些人开发的那样,将一大堆的逻辑都罗列在一个函数中,给后期维护人员造成巨大的困扰。

同样,通过上面的函数,Spring又将任务进行了拆分,分成了获取所有增强器与增强器是否匹配两个功能点。

寻找候选增强器

    protected List<Advisor> findCandidateAdvisors() {
return this.advisorRetrievalHelper.findAdvisorBeans();
}
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}

首先是通过BeanFactoryUtils类提供的工具方法获取所有对应Advisor.class的类,获取办法无非是使用ListableBeanFactory中提供的方法:

String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit);

而当我们知道增强器在容器中的beanName时,获取增强器已经不是问题了,在BeanFactory中提供了这样的方法,可以帮助我们快速定位对应的bean实例。

T getBean(String name, Class requiredType) throws BeansException;

自定义标签曾经注册了一个类型为BeanFactoryTransactionAttributeSourceAdvisor的bean,而在此bean中我们又注入了另外两个Bean,那么此时这个Bean就会被开始使用了。因为BeanFactoryTransactionAttributeSourceAdvisor同样也实现了Advisor接口,那么在获取所有增强器时自然也会将此bean提取出来,并随着其他增强器一起在后续的步骤中被织入代理。

候选增强器中寻找到匹配项

    protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
     //首先处理引介增强
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
//引介增强已经处理
continue;
}
       //对于普通bean的处理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
       //当前的advisor就是之前查找出来的类型为BeanFactoryTransactionAttributeSourceAdvisor的bean实例,
       //而通过类的层次结构我们又知道:BeanFactoryTransactionAttributeSourceAdvisor间接实现了PointcutAdvisor。
       //因此,在canApply函数中的第二个if判断if (advisor instanceof PointcutAdvisor)时就会通过判断,
       //会将BeanFactoryTransactionAttributeSourceAdvisor中的getPointcut()方法返回值作为参数继续调用canApply方法,
       //而getPoint()方法返回的是TransactionAttributeSourcePointcut类型的实例。见下面BeanFactoryTransactionAttributeSourceAdvisor.java
       //对于transactionAttributeSource这个属性是在解析自定义标签时注入进去的,见标签解析。
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
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;
}
     //此时的pc表示TransactionAttributeSourcePointcut,pc.getMethodMatcher()返回的正是自身(this). 
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);
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;
}

BeanFactoryTransactionAttributeSourceAdvisor.java
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
  private TransactionAttributeSource transactionAttributeSource;
  private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
    @Override
    protected TransactionAttributeSource getTransactionAttributeSource() {
      return transactionAttributeSource;
    }
  };
}

对于事务的配置不仅仅局限于在函数上配置,我们都知道,在类活接口上的配置可以延续到类中的每个函数,那么,如果针对每个函数进行检测,在类本身上配置的事务属性岂不是检测不到了吗?带着这个疑问,我们继续探求matcher方法。做匹配的时候methodMatcher.matches(method, targetClass)会使用TransactionAttributeSource Pointcut类的matches方法。

    @Override
public boolean matches(Method method, Class<?> targetClass) {
if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
     //自定义标签解析时注入,AnnotationTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
   //AnnotationTransactionAttributeSource.java
@Override
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;
}
}

很遗憾,在getTransactionAttribute函数中并没有找到我们想要的代码,没有找到在类活接口上的配置可以延续到类中的每个函数的逻辑,这里是指常规的一贯的套路。尝试从缓存加载,如果对应信息没有被缓存的话,工作又委托给了computeTransactionAttribute函数,在computeTransactionAttribute函数中终于的我们看到了事务标签的提取过程。

    protected 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);
//method代表接口中的方法,specificMethod代表实现类中的方法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
     //查看实现方法中是否存在事务声明
TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
if (txAtt != null) {
return txAtt;
}
//查看方法所在类中是否存在事务声明
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAtt != null) {
return txAtt;
}
     //如果存在接口,则到接口中去寻找
if (specificMethod != method) {
//查找接口方法是否存在事务声明
txAtt = findTransactionAttribute(method);
if (txAtt != null) {
return txAtt;
}
//查看接口所在类上面是否存在事务声明
return findTransactionAttribute(method.getDeclaringClass());
}
return null;
}

如果方法中存在事务属性,则使用方法上的属性,否则使用方法所在的类上的属性,如果方法所在类的属性上还是没有搜寻到对应的事务属性,那么再搜寻接口中的方法,再没有的话,最后尝试搜寻接口的类上面的声明。对于函数computeTransactionAttribute中的逻辑与我们所认识的规则并无差别,但是上面函数中并没有真正的去做搜寻事务属性的逻辑,而是搭建了个执行框架,将搜寻事务属性的任务委托给了findTransactionAttribute方法去执行。

    @Override
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
if (ae.getAnnotations().length > 0) {
//this.annotationParsers是在当前类AnnotationTransactionAttributeSource初始化的时候初始化的,
       //其中的值被加入了SpringTransactionAnnotationParser,
//也就是当进行属性获取的时候其实是使用SpringTransactionAnnotationParser类的parseTransactionAnnotation方法进行解析的。
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
if (attr != null) {
return attr;
}
}
}
return null;
}
//首先会判断当前的类是否含有Transactional注解,这是事务属性的基础,当然如果有的话会继续调用parseTransactionAnnotation方法解析详细的属性。
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
//解析propagation
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
//解析isolation
rbta.setIsolationLevel(isolation.value());
//解析timeout
rbta.setTimeout(attributes.getNumber("timeout").intValue());
//解析readOnly
rbta.setReadOnly(attributes.getBoolean("readOnly"));
//解析value
rbta.setQualifier(attributes.getString("value"));
//解析rollbackFor
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//解析rollbackForClassName
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//解析noRollbackFor
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//解析noRollbackForClassName
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}

上面方法中实现了对对应类或者方法的事务属性解析,你会在这个类中看到任何你常用或者不常用的属性提取。

找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性,这个任务至此是完成了。在,我们以UserServiceImpl为例,已经在它的接口UserService中找到了事务属性,所以,它是与事务增强器匹配的,也就是它会被事务功能修饰。

当判断某个bean适用于事务增强时,也就是适用于增强器BeanFactoryTransactionAttributeSourceAdvisor,然后执行最上面的return advisors.toArray();返回,至此完成了Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);增强器的获取。

Spring事务解析3-增强方法的获取的更多相关文章

  1. AOP动态代理解析3-增强方法的获取

    对于指定bean的增强方法的获取一定是包含两个步骤的: 获取所有的增强 寻找所有增强中使用于bean的增强并应用 那么findCandidateAdvisors与findAdvisorsThatCan ...

  2. Spring事务解析4-切面织入

    BeanFactoryTransactionAttributeSourceAdvisor作为Advisor的实现类,自然要遵从Advisor的处理方式,当代理被调用时会调用这个类的增强方法,也就是此b ...

  3. Spring事务解析1-使用介绍

    spring的事务控制让我们从复杂的事务处理中得到解脱,是我们再也不需要去处理获得连接,关闭连接,事务提交和回滚等操作,再也不需要在事务相关的方法中处理大量的try..catch...finally代 ...

  4. spring事务解析

    1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...

  5. Spring事务调用类自己方法失效解决办法和原因

    问题 正常情况下,我们都是在controller里调用service里的方法,这个方法如果需要加事务,就在方法上加上@Transactional,这样是没问题的,事务会生效. 可是如果像下面这样,绕以 ...

  6. SpringBoot CGLIB AOP解决Spring事务,对象调用自己方法事务失效.

    对于像我这种喜欢滥用AOP的程序员,遇到坑也是习惯了,不仅仅是事务,其实只要脱离了Spring容器管理的所有对象,对于SpringAOP的注解都会失效,因为他们不是Spring容器的代理类,Sprin ...

  7. Spring事务解析2-标签解析

    根据自定义标签的使用规则,可以知道会执行AnnotationDrivenBeanDefinitionParser的parse @Override public BeanDefinition parse ...

  8. Spring配置文件解析--集合注入方法

    <bean id="moreComplexObject" class="example.ComplexObject"> <property n ...

  9. Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?

    不知道一些同学有没有这种疑问,为什么Mybtis中要配置dataSource,Spring的事务中也要配置dataSource?那么Mybatis和Spring事务中用的Connection是同一个吗 ...

随机推荐

  1. 数据结构顺序表删除所有特定元素x

    顺序表类定义: template<class T> class SeqList : { public: SeqList(int mSize); ~SeqList() { delete[] ...

  2. ExpandableListView的用法

    ExpandableListView组件是android中一个比较常用的组件,当点击一个父item的时候可以将它的子item显示出来,像手机QQ中的好友列表就是实现的类型效果.使用Expandable ...

  3. jsp通过s:hidden传值给后台,后台数据出现了若干逗号问题

    <s:iterator value="rpActionVO.page.result" id="list" status="st"> ...

  4. 常用js函数整理--common.js

    var h = {}; h.get = function (url, data, ok, error) { $.ajax({ url: url, data: data, dataType: 'json ...

  5. ZooKeeper 配置文件(zoo.cfg)详解

    参数名 说明 clientPort 客户端连接server的端口,即对外服务端口,一般设置为2181吧. dataDir 存储快照文件snapshot的目录.默认情况下,事务日志也会存储在这里.建议同 ...

  6. 实现 Bootstrap 基本布局

    看到了一篇 20 分钟打造 Bootstrap 站点的文章,内容有点老,重新使用 Bootstrap3 实现一下,将涉及的内容也尽可能详细说明. 1. 创建基本的页面 我们先创建一个基本的 HTML ...

  7. Oracle双实例切换

    1.在Linux下切换: export ORACLE_SID=xxx1   sqlplus "/as sysdba" //进入sql   startup   //启动数据库实例1  ...

  8. PostgreSQL中COUNT的各条件下(1亿条数据)例子

    test=# insert into tbl_time1 select generate_series(1,100000000),clock_timestamp(),now(); INSERT 0 1 ...

  9. linux eclipse3.6.1 maven安装

    linux maven安装及 eclipse maven插件安装,有需要的朋友可以参考下. 1. maven的安装(apache-maven-3.0.5为例):  a.官网地址:http://mave ...

  10. elk安装(这个是初级的可以把这个套件安上)

    http://udn.yyuap.com/doc/logstash-best-practice-cn/index.html ELK其实并不是一款软件,而是一整套解决方案,是三个开源软件Elastics ...