死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator

导航

死磕Spring AOP系列1:编程式实现AOP

死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator

这是<死磕Spring AOP系列>的第三篇。经过前面的讲解,已经掌握了以下知识点

  1. Spring AOP的底层支持,是基于ProxyFactory+ProxyConfig+Advisor生成的
  2. Spring容器的代理对象生成:在Bean生命周期过长中调用BeanPostProcessor,将对象进行包装,生成代理对象。
  3. Advisor的指定:不管编程式指定,还是自动匹配指定。虽然形式不同,但本质是相同的。

如果,还对上面的问题存疑,请回看以上内容。

本篇主要对剖析另外一个BeanPostProcessor,他就是DefaultAdvisorAutoProxyCreator,他是BeanNameAutoProxyCreator的升级版。形象点说:如果ProxyFactory是弓箭的话,代表原始,BeanNameAutoProxyCreator就是步枪,需要自己装配,DefaultAdvisorAutoProxyCreator就是自动步枪了,Spring可以完成自动匹配的部分工作了。

本章主要内容

  1. 使用DefaultAdvisorAutoProxyCreator,完成一个“AOP"例子,讲解下如何配置
  2. 对比BeanNameAutoProxyCreator,对DefaultAdvisorAutoProxyCreator进行剖析
  3. 分析DefaultAdvisorAutoProxyCreator的Advisor的匹配过程
  4. 体会自动化

1.使用DefaultAdvisorAutoProxyCreator,完成一个“AOP"例子

/**
 *模拟业务接口
 */
public interface UserService {
    public void updateUser();
}
 
/**
 *模拟具体业务
 */
public class UserServiceImpl implements UserService{
 
    @Override
    public void updateUser() {
        System.out.println("$$$$$$执行业务逻辑$$$$$");
    }
}
 
/**
 * 模拟切面1
 */
public class SecurityInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("==========执行安全校验====================");
        return methodInvocation.proceed();
    }
}
 
/**
 * 模拟切面2
 */
public class LoggerBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("=======保存更新日志=========");
    }
}

xml(proxy_test.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans>
   <bean class="org.springaop.chap01.UserServiceImpl" id="userService"></bean>
   <bean class="org.springaop.chap01.LoggerBeforeAdvice" id="loggerBeforeAdvice"></bean>
   <bean class="org.springaop.chap01.SecurityInterceptor" id="securityInterceptor"></bean>

   <!-- 自动代理所有的advisor -->
   <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
      <property name="usePrefix" value="true"></property>
      <property name="advisorBeanNamePrefix" value="advisor"></property>
   </bean>

   <bean id="advisor1" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="pattern">
         <value>.*update.*</value>  <!-- 业务实现方法名匹配 -->
      </property>
      <property name="advice">
         <ref bean="loggerBeforeAdvice"/>
      </property>
   </bean>

   <bean id="advisor2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="pattern">
         <value>.*update.*</value>  <!-- 业务实现方法名匹配 -->
      </property>
      <property name="advice">
         <ref bean="securityInterceptor"/>
      </property>
   </bean>
</beans>

Main

public class ContextMain {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("org/springaop/chap03/proxy_test.xml");
        UserService userService =(UserService) ctx.getBean("userService");
//        UserService userService2 =(UserService) ctx.getBean("userService2");
        userService.updateUser();
//        userService2.updateUser();
    }
}

执行结果

=======保存更新日志=========
==========执行安全校验====================
$$$$$$执行业务逻辑$$$$$



说明:usePrefix和advisorBeanNamePrefix配合使用,如果usePrefix设置为false,advisorBeanNamePrefix设置没有作用。通过上面的设置配置,advisor2和advisor都有效果。

2.剖析DefaultAdvisorAutoProxyCreator类

2.1 结构层次图

可知,DefaultAdvisorAutoProxyCreator,BeanNameAutoProxyCreator是AbstractAutoProxyCreator的子类。通过前面讲解,知道AbstractAutoProxyCreator有个抽象方法。

方法声明如下

//是否被代理?返回interceptors
//Return whether the given bean is to be proxied, what additional advices (e.g. AOP Alliance interceptors) and advisors to apply.
protected abstract Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;

DefaultAdvisorAutoProxyCreator 和BeanNameAutoProxyCreator分别实现各自逻辑。BeanNameAutoProxyCreator的实现不再赘述,在死磕Spring AOP系列2已经讲过,代码很简单。

2.2 剖析getAdvicesAndAdvisorsForBean方法

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
...
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
   List 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();//获取所有的Advisors
   //获取可以应用于beanName的Advisor(逻辑尽在此)
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}
//Find all candidate Advisors to use in auto-proxying.
protected List<Advisor> findCandidateAdvisors() {
   //委托给BeanFactoryAdvisorRetrievalHelper处理
   return this.advisorRetrievalHelper.findAdvisorBeans();
}

}
public class BeanFactoryAdvisorRetrievalHelper {
    public List<Advisor> findAdvisorBeans() {

...
          if (advisorNames == null) {
              //获取容器中声明的Advisor
             // Do not initialize FactoryBeans here: We need to leave all regular beans
             // uninitialized to let the auto-proxy creator apply to them!
             advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                   this.beanFactory, Advisor.class, true, false);
...
       }
       if (advisorNames.length == 0) {
          return new LinkedList<Advisor>();
       }
    
       List<Advisor> advisors = new LinkedList<Advisor>();
       for (String name : advisorNames) {
           //判断返回
          if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) {
             try {
                advisors.add(this.beanFactory.getBean(name, Advisor.class));
             }
             catch (BeanCreationException ex) {
                ...
                throw ex;
             }
          }
       }
       return advisors;
    }
}

通过层层抽丝剥茧,定位到了AopUtils.findAdvisorsThatCanApply,负责具体的Advisor匹配工作。

3.剖析AopUtils.findAdvisorsThatCanApply方法,(匹配逻辑)

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)) {
      //是否IntroductionAdvisor
         eligibleAdvisors.add(candidate);
      }
   }
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      if (canApply(candidate, clazz, hasIntroductions)) {//执行
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

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) {
      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;
   }

   MethodMatcher methodMatcher = pc.getMethodMatcher();
   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
      introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
   }

   Set<Class> classes = new HashSet<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)) {//methodMatcher具体完成匹配
            return true;
         }
      }
   }

   return false;
}

通过图得知Advisor,持有Advice的聚合信息和PointCut对象,而PointCut接口持有MethodMatcher。

最后MethodMatcher完成方法匹配工作。以当前例子为例,AbstractRegexpMethodPointcut同时也是MethodMatcher.

public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut
      implements Serializable {
public boolean matches(Method method, Class targetClass) {
   return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
         matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
}
}

protected boolean matchesPattern(String signatureString) {
   for (int i = 0; i < this.patterns.length; i++) {
      boolean matched = matches(signatureString, i);
      if (matched) {
         for (int j = 0; j < this.excludedPatterns.length; j++) {
            boolean excluded = matchesExclusion(signatureString, j);
            if (excluded) {
               return false;
            }
         }
         return true;
      }
   }
   return false;
}

public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {
/**
 * Returns {@code true} if the {@link Pattern} at index {@code patternIndex}
 * matches the supplied candidate {@code String}.
 */
@Override
protected boolean matches(String pattern, int patternIndex) {
   Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
   return matcher.matches();
}

/**
 * Returns {@code true} if the exclusion {@link Pattern} at index {@code patternIndex}
 * matches the supplied candidate {@code String}.
 */
@Override
protected boolean matchesExclusion(String candidate, int patternIndex) {
   Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);
   return matcher.matches();
}

/**
 * Compiles the supplied {@code String[]} into an array of
 * {@link Pattern} objects and returns that array.
 */
private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {
   Pattern[] destination = new Pattern[source.length];
   for (int i = 0; i < source.length; i++) {
      destination[i] = Pattern.compile(source[i]);
   }
   return destination;
}
}

4.自动化

比起BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator有一个非常优越的地方。那就是advisor已有了自动匹配方法的能力。具体实现逻辑,通过上面的分析就是正则表达式的使用。其实很简单,确定一个方法是否被应用于advice,其实就是讲方法的签名字符串与定义PointCut的pattern进行匹配。今天提到的JdkRegexpMethodPointcut,只是实现之一。另外一个更强大的PointCut是什么?下次再说。

时间: 2024-10-03 02:38:40

死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator的相关文章

死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator

通过前一篇<死磕Spring AOP系列1:编程式实现AOP>,学习了Spring对代理的底层支持,认识了ProxyFactory对象,及从类设计层面认识了PointCut&Advisor&Advice&Interceptor,还认识了AdvisorChainFactory对象,知道了底层Advisor的底层链式结构.但是,上篇我们仅仅是通过Spring编程式实现的"AOP"效果,这种方式,实际开发时,如果这样用就太LOW了.今天,主要认识一个生成代

死磕Spring AOP系列4:剖析AOP schema方式原理

这个是<死磕Spring AOP系列>第4个.已经讲过的内容 死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator 死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator 死磕Spring AOP系列1:编程式实现AOP 通过前3篇,大家应该可以清楚的知道:AOP代理原理有3元素 BeanPostProcessor,作为代理对象初始入口 Advisor&Pointcut&M

死磕Spring AOP系列5:设计模式在AOP中的使用

死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator 死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator 死磕Spring AOP系列1:编程式实现AOP 死磕Spring AOP系列4:剖析AOP schema方式原理 通过前面的死磕,应该对AOP的原理都掌握了.annotation配置AOP,再没有讲的必要了.annotation和xml schema两种方式,仅仅是声明方式不同而已

死磕Spring AOP系列1:编程式实现AOP

作为[死磕Spring AOP]系列的第一篇, 这个系列是AOP源码分析级别的文章.由于现在AOP已经不是什么高深的技术,网上的例子也比比皆是,不论是xml schema,还是annotation声明式.相信用过Spring的朋友,都可以信手拈来. 本系列文章的原则 如何配置AOP不是重点 AOP相关概念讲解不是重点 AOP 底层代码设计才是重点 本篇的主要内容 认识ProxyFactory,并通过该工厂类,将"日志"和"安全校验"代码切入到业务逻辑中 分析代理对象

死磕Spring系列之一:准备阅读Spring源码环境

死磕Spring系列前言 死磕spring系列博客,是对Spring进行源码级阅读.工作以来,一直接触spring框架,可以说对spring框架的配置使用已经非常熟练了.个人感觉:Spring技术非常强大,简单的xml标签配置,就可以开启非常强大的支持功能,囊括J2EE企业应用的方方面面.使用归使用,但是却对spring底层设计和实现,一知半解."到底是什么优秀的设计,能让Spring无所不能,无所不包".最后,就有了我想研读Spring 源码的动力. 阅读任何任何一门框架源码,其实和

【死磕 Spring】----- IOC 之 加载 Bean

先看一段熟悉的代码: ClassPathResourceresource new ClassPathResource("bean.xml");DefaultListableBeanFactoryfactory new DefaultListableBeanFactory();XmlBeanDefinitionReaderreader new XmlBeanDefinitionReader(factory);reader.loadBeanDefinitions(resource);这段代

死磕 java同步系列之redis分布式锁进化史

问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 本章我们将介绍如何基于redis实现分布式锁,并把其实现的进化史从头到尾讲明白,以便大家在面试的时候能讲清楚

【死磕 Spring】----- IOC 之 获取验证模型

原文出自:http://cmsblogs.com 在上篇博客[死磕Spring]----- IOC 之 加载 Bean 中提到,在核心逻辑方法 doLoadBeanDefinitions()中主要是做三件事情. 调用 getValidationModeForResource() 获取 xml 文件的验证模式 调用 loadDocument() 根据 xml 文件获取相应的 Document 实例. 调用 registerBeanDefinitions() 注册 Bean 实例. 这篇博客主要分析

死磕 java同步系列之volatile解析

问题 (1)volatile是如何保证可见性的? (2)volatile是如何禁止重排序的? (3)volatile的实现原理? (4)volatile的缺陷? 简介 volatile可以说是Java虚拟机提供的最轻量级的同步机制了,但是它并不容易被正确地理解,以至于很多人不习惯使用它,遇到多线程问题一律使用synchronized或其它锁来解决. 了解volatile的语义对理解多线程的特性具有很重要的意义,所以彤哥专门写了一篇文章来解释volatile的语义到底是什么. 语义一:可见性 前面