Spring AOP 源碼解析

轉(zhuǎn)自:https://javadoop.com/post/spring-aop-source

之前寫過(guò) IOC 的源碼分析碘勉,那篇文章真的有點(diǎn)長(zhǎng)罩扇,看完需要點(diǎn)耐心梧奢。很多讀者希望能寫一寫 Spring AOP 的源碼分析文章担神,這樣讀者看完 IOC + AOP 也就對(duì) Spring 會(huì)有比較深的理解了楼吃。今天終于成文了,可能很多讀者早就不再等待了,不過(guò)主要為了后來(lái)者吧孩锡。

本文不會(huì)像 IOC 源碼分析那篇文章一樣酷宵,很具體地分析每一行 Spring AOP 的源碼,目標(biāo)讀者是已經(jīng)知道 Spring IOC 源碼是怎么回事的讀者躬窜,因?yàn)?Spring AOP 終歸是依賴于 IOC 容器來(lái)管理的浇垦。

閱讀建議:1、先搞懂 IOC 容器的源碼荣挨,AOP 依賴于 IOC 容器來(lái)管理男韧。2、仔細(xì)看完 Spring AOP 使用介紹 這篇文章默垄,先搞懂各種使用方式此虑,你才能"猜到"應(yīng)該怎么實(shí)現(xiàn)。

Spring AOP 的源碼并不簡(jiǎn)單口锭,因?yàn)樗喙炎常蚤喿x源碼最好就是找到一個(gè)分支,追蹤下去讹弯。本文定位為走馬觀花,看個(gè)大概这溅,不具體到每一個(gè)細(xì)節(jié)组民。

前言

這一節(jié),我們先來(lái)"猜猜" Spring 是怎么實(shí)現(xiàn) AOP 的悲靴。

在 Spring 的容器中臭胜,我們面向的對(duì)象是一個(gè)個(gè)的 bean 實(shí)例,bean 是什么癞尚?我們可以簡(jiǎn)單理解為是 BeanDefinition 的實(shí)例耸三,Spring 會(huì)根據(jù) BeanDefinition 中的信息為我們生產(chǎn)合適的 bean 實(shí)例出來(lái)。

當(dāng)我們需要使用 bean 的時(shí)候浇揩,通過(guò) IOC 容器的 getBean(…) 方法從容器中獲取 bean 實(shí)例仪壮,只不過(guò)大部分的場(chǎng)景下,我們都用了依賴注入胳徽,所以很少手動(dòng)調(diào)用 getBean(...) 方法积锅。

Spring AOP 的原理很簡(jiǎn)單,就是動(dòng)態(tài)代理养盗,它和 AspectJ 不一樣缚陷,AspectJ 是直接修改掉你的字節(jié)碼。

代理模式很簡(jiǎn)單往核,接口 + 真實(shí)實(shí)現(xiàn)類 + 代理類箫爷,其中 真實(shí)實(shí)現(xiàn)類 和 代理類 都要實(shí)現(xiàn)接口,實(shí)例化的時(shí)候要使用代理類。所以虎锚,Spring AOP 需要做的是生成這么一個(gè)代理類硫痰,然后替換掉真實(shí)實(shí)現(xiàn)類來(lái)對(duì)外提供服務(wù)。

替換的過(guò)程怎么理解呢翁都?在 Spring IOC 容器中非常容易實(shí)現(xiàn)碍论,就是在 getBean(…) 的時(shí)候返回的實(shí)際上是代理類的實(shí)例,而這個(gè)代理類我們自己沒(méi)寫代碼柄慰,它是 Spring 采用 JDK Proxy 或 CGLIB 動(dòng)態(tài)生成的鳍悠。

getBean(…) 方法用于查找或?qū)嵗萜髦械?bean,這也是為什么 Spring AOP 只能作用于 Spring 容器中的 bean 的原因坐搔,對(duì)于不是使用 IOC 容器管理的對(duì)象藏研,Spring AOP 是無(wú)能為力的。

本文使用的調(diào)試代碼

閱讀源碼很好用的一個(gè)方法就是跑代碼來(lái)調(diào)試概行,因?yàn)樽约阂恍幸恍械乜吹脑挻赖玻容^枯燥,而且難免會(huì)漏掉一些東西凳忙。

下面业踏,我們先準(zhǔn)備一些簡(jiǎn)單的調(diào)試用的代碼。

首先先定義兩個(gè) Service 接口:

// OrderService.java
public interface OrderService {

    Order createOrder(String username, String product);

    Order queryOrder(String username);
}
// UserService.java
public interface UserService {

    User createUser(String firstName, String lastName, int age);

    User queryUser();
}

然后涧卵,分別來(lái)一個(gè)接口實(shí)現(xiàn)類:

// OrderServiceImpl.java
public class OrderServiceImpl implements OrderService {

    @Override
    public Order createOrder(String username, String product) {
        Order order = new Order();
        order.setUsername(username);
        order.setProduct(product);
        return order;
    }

    @Override
    public Order queryOrder(String username) {
        Order order = new Order();
        order.setUsername("test");
        order.setProduct("test");
        return order;
    }
}

// UserServiceImpl.java
public class UserServiceImpl implements UserService {

    @Override
    public User createUser(String firstName, String lastName, int age) {
        User user = new User();
        user.setFirstName(firstName);
        user.setLastName(lastName);
        user.setAge(age);
        return user;
    }

    @Override
    public User queryUser() {
        User user = new User();
        user.setFirstName("test");
        user.setLastName("test");
        user.setAge(20);
        return user;
    }
}

寫兩個(gè) Advice:

public class LogArgsAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("準(zhǔn)備執(zhí)行方法: " + method.getName() + ", 參數(shù)列表:" + Arrays.toString(args));
    }
}

public class LogResultAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println(method.getName() + "方法返回:" + returnValue);
    }
}

配置一下:


image.png

我們這邊使用了前面文章介紹的配置 Advisor 的方式勤家,我們回顧一下。

每個(gè) advisor 內(nèi)部持有 advice 實(shí)例柳恐,advisor 負(fù)責(zé)匹配伐脖,內(nèi)部的 advice 負(fù)責(zé)實(shí)現(xiàn)攔截處理。配置了各個(gè) advisor 后乐设,配置 DefaultAdvisorAutoProxyCreator 使得所有的 advisor 配置自動(dòng)生效讼庇。

啟動(dòng):

public class SpringAopSourceApplication {

   public static void main(String[] args) {

      // 啟動(dòng) Spring 的 IOC 容器
      ApplicationContext context = new ClassPathXmlApplicationContext("classpath:DefaultAdvisorAutoProxy.xml");

      UserService userService = context.getBean(UserService.class);
      OrderService orderService = context.getBean(OrderService.class);

      userService.createUser("Tom", "Cruise", 55);
      userService.queryUser();

      orderService.createOrder("Leo", "隨便買點(diǎn)什么");
      orderService.queryOrder("Leo");
   }
}

準(zhǔn)備執(zhí)行方法: createUser, 參數(shù)列表:[Tom, Cruise, 55]
queryUser方法返回:User{firstName='test', lastName='test', age=20, address='null'}
準(zhǔn)備執(zhí)行方法: createOrder, 參數(shù)列表:[Leo, 隨便買點(diǎn)什么]
queryOrder方法返回:Order{username='test', product='test'}

從輸出結(jié)果,我們可以看到:

LogArgsAdvice 作用于 UserService#createUser(…) 和 OrderService#createOrder(…) 兩個(gè)方法近尚;
LogResultAdvice 作用于 UserService#queryUser() 和 OrderService#queryOrder(…) 兩個(gè)方法蠕啄;

下面的代碼分析中,我們將基于這個(gè)簡(jiǎn)單的例子來(lái)介紹戈锻。

IOC 容器管理 AOP 實(shí)例

本節(jié)介紹 Spring AOP 是怎么作用于 IOC 容器中的 bean 的介汹。

Spring AOP 的使用介紹 那篇文章已經(jīng)介紹過(guò) DefaultAdvisorAutoProxyCreator 類了,它能實(shí)現(xiàn)自動(dòng)將所有的 advisor 生效舶沛。

我們來(lái)追蹤下 DefaultAdvisorAutoProxyCreator 類嘹承,看看它是怎么一步步實(shí)現(xiàn)的動(dòng)態(tài)代理。然后在這個(gè)基礎(chǔ)上如庭,我們?cè)俸?jiǎn)單追蹤下 @AspectJ 配置方式下的源碼實(shí)現(xiàn)叹卷。

首先撼港,先看下 DefaultAdvisorAutoProxyCreator 的繼承結(jié)構(gòu):


image.png

我們可以發(fā)現(xiàn),DefaultAdvisorAutoProxyCreator 最后居然是一個(gè) BeanPostProcessor骤竹,在 Spring IOC 源碼分析的時(shí)候說(shuō)過(guò)帝牡,BeanPostProcessor 的兩個(gè)方法,分別在 init-method 的前后得到執(zhí)行蒙揣。

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

這里再貼一下 IOC 的源碼靶溜,我們回顧一下:

// AbstractAutowireCapableBeanFactory

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 創(chuàng)建實(shí)例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ...

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 2. 裝載屬性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    ...
}

在上面第 3 步 initializeBean(...) 方法中會(huì)調(diào)用 BeanPostProcessor 中的方法,如下:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   ...
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 1. 執(zhí)行每一個(gè) BeanPostProcessor 的 postProcessBeforeInitialization 方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 調(diào)用 bean 配置中的 init-method="xxx"
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      // 我們關(guān)注的重點(diǎn)是這里@琳稹U窒ⅰ!
      // 2. 執(zhí)行每一個(gè) BeanPostProcessor 的 postProcessAfterInitialization 方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

也就是說(shuō)个扰,Spring AOP 會(huì)在 IOC 容器創(chuàng)建 bean 實(shí)例的最后對(duì) bean 進(jìn)行處理瓷炮。其實(shí)就是在這一步進(jìn)行代理增強(qiáng)。

我們回過(guò)頭來(lái)递宅,DefaultAdvisorAutoProxyCreator 的繼承結(jié)構(gòu)中娘香,postProcessAfterInitialization() 方法在其父類 AbstractAutoProxyCreator 這一層被覆寫了:

// AbstractAutoProxyCreator

@Override
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;
}

繼續(xù)往里看 wrapIfNecessary(...) 方法,這個(gè)方法將返回代理類(如果需要的話):

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

   // 返回匹配當(dāng)前 bean 的所有的 advisor办龄、advice烘绽、interceptor
   // 對(duì)于本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 這兩個(gè) bean 創(chuàng)建過(guò)程中俐填,
   //   到這邊的時(shí)候都會(huì)返回兩個(gè) advisor
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 創(chuàng)建代理...創(chuàng)建代理...創(chuàng)建代理...
      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;
}

這里有兩個(gè)點(diǎn)提一下:

getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null)安接,這個(gè)方法將得到所有的可用于攔截當(dāng)前 bean 的 advisor、advice玷禽、interceptor。

另一個(gè)就是 TargetSource 這個(gè)概念呀打,它用于封裝真實(shí)實(shí)現(xiàn)類的信息矢赁,上面用了 SingletonTargetSource 這個(gè)實(shí)現(xiàn)類,其實(shí)我們這里也不太需要關(guān)心這個(gè)贬丛,知道有這么回事就可以了撩银。

我們繼續(xù)往下看 createProxy(…) 方法:

// 注意看這個(gè)方法的幾個(gè)參數(shù),
// 第三個(gè)參數(shù)攜帶了所有的 advisors
// 第四個(gè)參數(shù) targetSource 攜帶了真實(shí)實(shí)現(xiàn)的信息
protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   // 創(chuàng)建 ProxyFactory 實(shí)例
   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);

   // 在 schema-based 的配置方式中豺憔,我們介紹過(guò)额获,如果希望使用 CGLIB 來(lái)代理接口,可以配置
   // proxy-target-class="true",這樣不管有沒(méi)有接口恭应,都使用 CGLIB 來(lái)生成代理:
   //   <aop:config proxy-target-class="true">......</aop:config>
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 點(diǎn)進(jìn)去稍微看一下代碼就知道了抄邀,主要就兩句:
         // 1. 有接口的,調(diào)用一次或多次:proxyFactory.addInterface(ifc);
         // 2. 沒(méi)有接口的昼榛,調(diào)用:proxyFactory.setProxyTargetClass(true);
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   // 這個(gè)方法會(huì)返回匹配了當(dāng)前 bean 的 advisors 數(shù)組
   // 對(duì)于本文的例子境肾,"userServiceImpl" 和 "OrderServiceImpl" 到這邊的時(shí)候都會(huì)返回兩個(gè) advisor
   // 注意:如果 specificInterceptors 中有 advice 和 interceptor,它們也會(huì)被包裝成 advisor,進(jìn)去看下源碼就清楚了
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      proxyFactory.addAdvisor(advisor);
   }

   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);

   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }

   return proxyFactory.getProxy(getProxyClassLoader());
}

我們看到奥喻,這個(gè)方法主要是在內(nèi)部創(chuàng)建了一個(gè) ProxyFactory 的實(shí)例偶宫,然后 set 了一大堆內(nèi)容,剩下的工作就都是這個(gè) ProxyFactory 實(shí)例的了环鲤,通過(guò)這個(gè)實(shí)例來(lái)創(chuàng)建代理: getProxy(classLoader)纯趋。

ProxyFactory 詳解

根據(jù)上面的源碼,我們走到了 ProxyFactory 這個(gè)類了冷离,我們到這個(gè)類來(lái)一看究竟吵冒。

順著上面的路子,我們首先到 ProxyFactory#getProxy(classLoader) 方法:

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

該方法首先通過(guò) createAopProxy() 創(chuàng)建一個(gè) AopProxy 的實(shí)例:

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}

創(chuàng)建 AopProxy 之前酒朵,我們需要一個(gè) AopProxyFactory 實(shí)例桦锄,然后看 ProxyCreatorSupport 的構(gòu)造方法:

public ProxyCreatorSupport() {
   this.aopProxyFactory = new DefaultAopProxyFactory();
}

這樣就將我們導(dǎo)到 DefaultAopProxyFactory 這個(gè)類了,我們看它的 createAopProxy(…) 方法:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

   @Override
   public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      // (我也沒(méi)用過(guò)這個(gè)optimize蔫耽,默認(rèn)false) || (proxy-target-class=true) || (沒(méi)有接口)
      if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
         Class<?> targetClass = config.getTargetClass();
         if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                  "Either an interface or a target is required for proxy creation.");
         }
         // 如果要代理的類本身就是接口结耀,也會(huì)用 JDK 動(dòng)態(tài)代理
         // mybatis,dao層只有接口的情況
         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         // 如果有接口匙铡,會(huì)跑到這個(gè)分支
         return new JdkDynamicAopProxy(config);
      }
   }
   // 判斷是否有實(shí)現(xiàn)自定義的接口
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }
}

到這里图甜,我們知道 createAopProxy 方法有可能返回 JdkDynamicAopProxy 實(shí)例,也有可能返回 ObjenesisCglibAopProxy 實(shí)例鳖眼,這里總結(jié)一下:

  • 被代理的目標(biāo)類實(shí)現(xiàn)了一個(gè)或多個(gè)自定義的接口黑毅,那么就會(huì)使用 JDK 動(dòng)態(tài)代理,
  • 只有接口沒(méi)有實(shí)現(xiàn)類钦讳,那么就會(huì)使用 JDK 動(dòng)態(tài)代理矿瘦。
  • 如果沒(méi)有實(shí)現(xiàn)任何接口,會(huì)使用 CGLIB 實(shí)現(xiàn)代理愿卒,
  • 如果設(shè)置了 proxy-target-class="true"缚去,那么都會(huì)使用 CGLIB。

JDK 動(dòng)態(tài)代理基于接口琼开,所以只有接口中的方法會(huì)被增強(qiáng)易结,而 CGLIB 基于類繼承,需要注意就是如果方法使用了 final 修飾柜候,或者是 private 方法搞动,是不能被增強(qiáng)的。

有了 AopProxy 實(shí)例以后渣刷,我們就回到這個(gè)方法了:

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

我們分別來(lái)看下兩個(gè) AopProxy 實(shí)現(xiàn)類的 getProxy(classLoader) 實(shí)現(xiàn)鹦肿。

JdkDynamicAopProxy 類的源碼比較簡(jiǎn)單,總共兩百多行辅柴,

@Override
public Object getProxy(ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
   }
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

java.lang.reflect.Proxy.newProxyInstance(…) 方法需要三個(gè)參數(shù)狮惜,第一個(gè)是 ClassLoader高诺,第二個(gè)參數(shù)代表需要實(shí)現(xiàn)哪些接口制圈,第三個(gè)參數(shù)最重要膨报,是 InvocationHandler 實(shí)例蒿涎,我們看到這里傳了 this汽纠,因?yàn)?JdkDynamicAopProxy 本身實(shí)現(xiàn)了 InvocationHandler 接口媳危。

InvocationHandler 只有一個(gè)方法烦周,當(dāng)生成的代理類對(duì)外提供服務(wù)的時(shí)候帚稠,都會(huì)導(dǎo)到這個(gè)方法中:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

下面來(lái)看看 JdkDynamicAopProxy 對(duì)其的實(shí)現(xiàn):

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   MethodInvocation invocation;
   Object oldProxy = null;
   boolean setProxyContext = false;

   TargetSource targetSource = this.advised.targetSource;
   Class<?> targetClass = null;
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         // 代理的 equals 方法
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         // 代理的 hashCode 方法
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         // 
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

      // 如果設(shè)置了 exposeProxy孵运,那么將 proxy 放到 ThreadLocal 中
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }

      // May be null. Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      target = targetSource.getTarget();
      if (target != null) {
         targetClass = target.getClass();
      }

      // Get the interception chain for this method.
      // 創(chuàng)建一個(gè) chain穆律,包含所有要執(zhí)行的 advice
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
         // chain 是空的惠呼,說(shuō)明不需要被增強(qiáng),這種情況很簡(jiǎn)單
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         // 執(zhí)行方法峦耘,得到返回值
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

上面就三言兩語(yǔ)說(shuō)了一下剔蹋,感興趣的讀者自己去深入探索下,不是很難辅髓。簡(jiǎn)單地說(shuō)泣崩,就是在執(zhí)行每個(gè)方法的時(shí)候,判斷下該方法是否需要被一次或多次增強(qiáng)(執(zhí)行一個(gè)或多個(gè) advice)洛口。

說(shuō)完了 JDK 動(dòng)態(tài)代理 JdkDynamicAopProxy#getProxy(classLoader)矫付,我們?cè)賮?lái)瞄一眼 CGLIB 的代理實(shí)現(xiàn) ObjenesisCglibAopProxy#getProxy(classLoader)。

ObjenesisCglibAopProxy 繼承了 CglibAopProxy第焰,而 CglibAopProxy 繼承了 AopProxy买优。

ObjenesisCglibAopProxy 使用了 Objenesis 這個(gè)庫(kù),和 cglib 一樣挺举,我們不需要在 maven 中進(jìn)行依賴杀赢,因?yàn)?spring-core.jar 直接把它的源代碼也搞過(guò)來(lái)了。


image.png

通過(guò) CGLIB 生成代理的代碼量有點(diǎn)大湘纵,我們就不進(jìn)行深入分析了脂崔,我們看下大體的骨架。它的 getProxy(classLoader) 方法在父類 CglibAopProxy 類中:

// CglibAopProxy#getProxy(classLoader)

@Override
public Object getProxy(ClassLoader classLoader) {
      ...
      // Configure CGLIB Enhancer...
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate the proxy class and create a proxy instance.
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException ex) {
      ...
   }
   catch (IllegalArgumentException ex) {
      ...
   }
   catch (Throwable ex) {
      ...
   }
}

CGLIB 生成代理的核心類是 Enhancer 類瞻佛,這里就不展開(kāi)說(shuō)了脱篙。

基于注解的 Spring AOP 源碼分析

上面我們走馬觀花地介紹了使用 DefaultAdvisorAutoProxyCreator 來(lái)實(shí)現(xiàn) Spring AOP 的源碼娇钱,這里伤柄,我們也同樣走馬觀花地來(lái)看下 @AspectJ 的實(shí)現(xiàn)原理。

我們之前說(shuō)過(guò)文搂,開(kāi)啟 @AspectJ 的兩種方式适刀,一個(gè)是 <aop:aspectj-autoproxy/>,一個(gè)是 @EnableAspectJAutoProxy煤蹭,它們的原理是一樣的笔喉,都是通過(guò)注冊(cè)一個(gè) bean 來(lái)實(shí)現(xiàn)的取视。

解析 <aop:aspectj-autoproxy/> 需要用到 AopNamespaceHandler:


image.png

然后到類 AspectJAutoProxyBeanDefinitionParser:

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

   @Override
   @Nullable
   public BeanDefinition parse(Element element, ParserContext parserContext) {
      AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
      extendBeanDefinition(element, parserContext);
      return null;
   }
   ...
}

進(jìn)去 registerAspectJAnnotationAutoProxyCreatorIfNecessary(...) 方法:

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      ParserContext parserContext, Element sourceElement) {

   BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
         parserContext.getRegistry(), parserContext.extractSource(sourceElement));
   useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
   registerComponentIfNecessary(beanDefinition, parserContext);
}

再進(jìn)去 AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(...):

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
      @Nullable Object source) {

   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

最終我們看到,Spring 注冊(cè)了一個(gè) AnnotationAwareAspectJAutoProxyCreator 的 bean常挚,beanName 為:"org.springframework.aop.config.internalAutoProxyCreator"作谭。

我們看下 AnnotationAwareAspectJAutoProxyCreator 的繼承結(jié)構(gòu):


image.png

和前面介紹的 DefaultAdvisorAutoProxyCreator 一樣,它也是一個(gè) BeanPostProcessor奄毡,剩下的我們就不說(shuō)了折欠,它和它的父類 AspectJAwareAdvisorAutoProxyCreator 都不復(fù)雜。

閑聊 InstantiationAwareBeanPostProcessor

為什么要說(shuō)這個(gè)呢吼过?因?yàn)槲野l(fā)現(xiàn)锐秦,很多人都以為 Spring AOP 是通過(guò)這個(gè)接口來(lái)作用于 bean 生成代理的。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

   Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

   boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

   PropertyValues postProcessPropertyValues(
         PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

}

它和 BeanPostProcessor 的方法非常相似盗忱,而且它還繼承了 BeanPostProcessor酱床。

不仔細(xì)看還真的不好區(qū)分,下面是 BeanPostProcessor 中的兩個(gè)方法:

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

發(fā)現(xiàn)沒(méi)有趟佃,InstantiationAwareBeanPostProcessor 是 Instantiation扇谣,BeanPostProcessor 是 Initialization,它代表的是 bean 在實(shí)例化完成并且屬性注入完成揖闸,在執(zhí)行 init-method 的前后進(jìn)行作用的揍堕。

而 InstantiationAwareBeanPostProcessor 的執(zhí)行時(shí)機(jī)要前面一些,大家需要翻下 IOC 的源碼:

// AbstractAutowireCapableBeanFactory 447行
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
   ...
   try {
      // 讓 InstantiationAwareBeanPostProcessor 在這一步有機(jī)會(huì)返回代理
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean; 
      }
   }
   // BeanPostProcessor 是在這里面實(shí)例化后才能得到執(zhí)行
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   ...
   return beanInstance;
}

點(diǎn)進(jìn)去看 resolveBeforeInstantiation(beanName, mbdToUse) 方法汤纸,然后就會(huì)導(dǎo)到 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法衩茸,對(duì)于我們分析的 AOP 來(lái)說(shuō),該方法的實(shí)現(xiàn)在 AbstractAutoProxyCreator 類中:

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    ...
    if (beanName != null) {
      TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
      if (targetSource != null) {
         this.targetSourcedBeans.add(beanName);
         Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
         Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
         this.proxyTypes.put(cacheKey, proxy.getClass());
         return proxy;
      }
   }

   return null;
}

我們可以看到贮泞,這里也有創(chuàng)建代理的邏輯楞慈,以至于很多人會(huì)搞錯(cuò)。確實(shí)啃擦,這里是有可能創(chuàng)建代理的囊蓝,但前提是對(duì)于相應(yīng)的 bean 我們有自定義的 TargetSource 實(shí)現(xiàn),進(jìn)到 getCustomTargetSource(...) 方法就清楚了令蛉,我們需要配置一個(gè) customTargetSourceCreators聚霜,它是一個(gè) TargetSourceCreator 數(shù)組。

這里就不再展開(kāi)說(shuō) TargetSource 了珠叔,請(qǐng)參考 Spring Reference 中的 Using TargetSources蝎宇。

小結(jié)

本文真的是走馬觀花,和我之前寫的文章有很大的不同祷安,希望讀者不會(huì)嫌棄姥芥。

不過(guò)如果讀者有看過(guò)之前的 Spring IOC 源碼分析Spring AOP 使用介紹 這兩篇文章的話,通過(guò)看本文應(yīng)該能對(duì) Spring AOP 的源碼實(shí)現(xiàn)有比較好的理解了汇鞭。

本文說(shuō)細(xì)節(jié)說(shuō)得比較少凉唐,如果你在看源碼的時(shí)候碰到不懂的庸追,歡迎在評(píng)論區(qū)留言與大家進(jìn)行交流。

(全文完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末台囱,一起剝皮案震驚了整個(gè)濱河市淡溯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌簿训,老刑警劉巖血筑,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異煎楣,居然都是意外死亡豺总,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門择懂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喻喳,“玉大人,你說(shuō)我怎么就攤上這事困曙”砺祝” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵慷丽,是天一觀的道長(zhǎng)蹦哼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)要糊,這世上最難降的妖魔是什么纲熏? 我笑而不...
    開(kāi)封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮锄俄,結(jié)果婚禮上局劲,老公的妹妹穿的比我還像新娘。我一直安慰自己奶赠,他們只是感情好鱼填,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著毅戈,像睡著了一般苹丸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上苇经,一...
    開(kāi)封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天赘理,我揣著相機(jī)與錄音,去河邊找鬼塑陵。 笑死感憾,一個(gè)胖子當(dāng)著我的面吹牛蜡励,可吹牛的內(nèi)容都是我干的令花。 我是一名探鬼主播阻桅,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兼都!你這毒婦竟也來(lái)了嫂沉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤扮碧,失蹤者是張志新(化名)和其女友劉穎趟章,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體慎王,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚓土,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赖淤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜀漆。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咱旱,靈堂內(nèi)的尸體忽然破棺而出确丢,到底是詐尸還是另有隱情,我是刑警寧澤吐限,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布鲜侥,位于F島的核電站,受9級(jí)特大地震影響诸典,放射性物質(zhì)發(fā)生泄漏描函。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一狐粱、第九天 我趴在偏房一處隱蔽的房頂上張望赘阀。 院中可真熱鬧,春花似錦脑奠、人聲如沸基公。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)轰豆。三九已至,卻和暖如春齿诞,著一層夾襖步出監(jiān)牢的瞬間酸休,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工祷杈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斑司,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓但汞,卻偏偏與公主長(zhǎng)得像宿刮,于是被迫代替她去往敵國(guó)和親互站。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容