Анализ исходного кода Spring AOP

Java Spring
ДомойНовую тему можно установить в правом нижнем углу, все желающие могут внести предложения. Анализ исходного кода Spring AOP Время обновления: 24 июля 2018 г.

Я уже писал анализ исходного кода IOC раньше, эта статья действительно немного длинная, и чтобы ее прочитать, нужно немного терпения. Многие читатели надеются написать статью с анализом исходного кода Spring AOP, чтобы у читателей было более глубокое понимание Spring после прочтения IOC + AOP. Сегодня она наконец была написана, и многие читатели, возможно, уже давно не ждали, но в основном она предназначена для опоздавших.

В этой статье не будет анализироваться каждая строка исходного кода Spring AOP очень специфическим образом, как в статье об анализе исходного кода IOC.Целевыми читателями являются читатели, которые уже знают, что такое исходный код Spring IOC, потому что Spring AOP в конечном итоге управляется Контейнер МОК. .

Рекомендации по чтению: 1. Сначала понятьИсходный код контейнера IOC, АОП использует для управления контейнер IOC. 2. Читайте внимательноВведение в использование Spring АОПВ этой статье, сначала разобравшись с различными способами использования, вы сможете «догадаться», как это должно быть реализовано.

Исходный код Spring AOP не прост, потому что их много, поэтому лучший способ прочитать исходный код — найти ветку и следовать ей.Эта статья предназначена для того, чтобы бегло взглянуть на цветы, посмотреть на общую ситуацию, а не вдаваться в каждую деталь.

предисловие

В этом разделе давайте «угадаем», как Spring реализует АОП.

В контейнере Spring объект, с которым мы сталкиваемся, является экземпляром компонента. Что такое компонент? Мы можем просто понимать его как экземпляр BeanDefinition, и Spring сгенерирует для нас подходящие экземпляры компонента на основе информации в BeanDefinition. Когда нам нужно использовать bean-компоненты, мы получаем экземпляры bean-компонентов из контейнера с помощью метода getBean(…) контейнера IOC, но в большинстве сценариев мы используем внедрение зависимостей, поэтому мы редко вызываем метод getBean(…) вручную.

Принцип Spring AOP очень прост, т.Динамический прокси, который отличается от AspectJ, который напрямую изменяет ваш байт-код.

Режим прокси очень прост: интерфейс + класс реальной реализации + класс прокси, в котором класс реальной реализации и класс прокси реализуют интерфейс и используют класс прокси при создании экземпляра. Итак, что нужно сделать Spring AOP, так это сгенерировать такой прокси-класс, а затемзаменятьРеальный класс реализации для предоставления внешних сервисов.

Как понять процесс замены? Это очень легко реализовать в Spring IOC-контейнере, то есть то, что возвращается, когда getBean(…) на самом деле является экземпляром прокси-класса, и этот прокси-класс написан не нами, он динамически генерируется Spring с помощью JDK. Прокси или CGLIB.

Метод getBean(…) используется для поиска или создания экземпляров bean-компонентов в контейнере, поэтому Spring AOP может воздействовать только на bean-компоненты в контейнере Spring.Для объектов, которые не управляются контейнером IOC, Spring AOP бессилен.

Код отладки, использованный в этой статье

Очень полезный способ чтения исходного кода — запускать код для отладки, потому что, если читать его построчно, будет скучно, и вы неизбежно что-то упустите.

Затем мы сначала подготовим простой отладочный код.

Сначала определите два интерфейса службы:

// 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();
}

Затем перейдите к классу реализации интерфейса соответственно:

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

Напишите два совета:

public class LogArgsAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("准备执行方法: " + method.getName() + ", 参数列表:" + 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);
    }
}

Настройте его:

2

Здесь мы используем способ настройки советника, описанный в предыдущей статье, рассмотрим его.

Каждый советник содержит экземпляр совета внутри себя, советник отвечает за сопоставление, а внутренний совет отвечает за реализацию обработки перехвата. После настройки каждого советника настройте DefaultAdvisorAutoProxyCreator, чтобы все настройки советника вступали в силу автоматически.

запускать:

public class SpringAopSourceApplication {

   public static void main(String[] args) {

      // 启动 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", "随便买点什么");
      orderService.queryOrder("Leo");
   }
}

вывод:

准备执行方法: createUser, 参数列表:[Tom, Cruise, 55]
queryUser方法返回:User{firstName='test', lastName='test', age=20, address='null'}
准备执行方法: createOrder, 参数列表:[Leo, 随便买点什么]
queryOrder方法返回:Order{username='test', product='test'}

LogArgsAdvice работает с двумя методами UserService#createUser(…) и OrderService#createOrder(…);

LogResultAdvice воздействует на методы UserService#queryUser() и OrderService#queryOrder(…);

В следующем анализе кода мы представим его на основе этого простого примера.

Контейнер IOC управляет экземплярами AOP

В этом разделе описывается, как Spring AOP работает с bean-компонентами в контейнере IOC.

Введение в использование Spring АОПВ этой статье уже был представлен класс DefaultAdvisorAutoProxyCreator, который автоматически активирует все советники.

Давайте проследим за классом DefaultAdvisorAutoProxyCreator, чтобы увидеть, как он шаг за шагом реализует динамический прокси. Затем на этой основе мы просто трассируем реализацию исходного кода под конфигурацией @AspectJ.

Во-первых, давайте посмотрим на структуру наследования DefaultAdvisorAutoProxyCreator:

1

Мы можем обнаружить, что DefaultAdvisorAutoProxyCreator на самом деле являетсяBeanPostProcessor, как я сказал при анализе исходного кода Spring IOC, два метода BeanPostProcessor выполняются до и после метода init соответственно.

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. 创建实例
        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);
        }
    }
    ...
}

Метод в BeanPostProcessor вызывается в методе initializeBean(...) на шаге 3 выше следующим образом:

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

   try {
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      // 我们关注的重点是这里!!!
      // 2. 执行每一个 BeanPostProcessor 的 postProcessAfterInitialization 方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

То есть Spring AOP будет обрабатывать bean-компонент в конце экземпляра bean-компонента, созданного контейнером IOC. Фактически именно на этом шаге выполняется расширение прокси.

Оглядываясь назад, в структуре наследования DefaultAdvisorAutoProxyCreator метод 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;
}

Переходя к методу 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;
   }

   // 返回匹配当前 bean 的所有的 advisor、advice、interceptor
   // 对于本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 到这边的时候都会返回两个 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;
   }

   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}

Здесь следует упомянуть два момента:

getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null), этот метод получит всекоторый можно использовать для перехвата текущего компонентасоветник, совет, перехватчик.

Другой — это концепция TargetSource, которая используется для инкапсуляции информации реального класса реализации.Выше используется класс реализации SingletonTargetSource.На самом деле, нам не нужно заботиться об этом здесь, просто знайте, что есть такие вещь.

Перейдем к методу createProxy(…):

// 注意看这个方法的几个参数,
//   第三个参数携带了所有的 advisors
//   第四个参数 targetSource 携带了真实实现的信息
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 proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);

   // 在 schema-based 的配置方式中,我们介绍过,如果希望使用 CGLIB 来代理接口,可以配置
   // proxy-target-class="true",这样不管有没有接口,都使用 CGLIB 来生成代理:
   //   <aop:config proxy-target-class="true">......</aop:config>
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 点进去稍微看一下代码就知道了,主要就两句:
         // 1. 有接口的,调用一次或多次:proxyFactory.addInterface(ifc);
         // 2. 没有接口的,调用:proxyFactory.setProxyTargetClass(true);
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   // 这个方法会返回匹配了当前 bean 的 advisors 数组
   // 对于本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 到这边的时候都会返回两个 advisor
   // 注意:如果 specificInterceptors 中有 advice 和 interceptor,它们也会被包装成 advisor,进去看下源码就清楚了
   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());
}

Мы видим, что этот метод в основном создает экземпляр ProxyFactory внутри, а затем устанавливает много контента, а остальная работа выполняется этим экземпляром ProxyFactory, и прокси создается через этот экземпляр:getProxy(classLoader).

Детали ProxyFactory

По приведённому выше исходнику мы подошли к классу ProxyFactory, давайте посмотрим на этот класс.

Следуя указанному выше пути, мы сначала переходим к методу ProxyFactory#getProxy(classLoader):

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

Метод сначала создает экземпляр AopProxy через createAopProxy():

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

Перед созданием AopProxy нам нужен экземпляр AopProxyFactory, а затем посмотрим на конструктор ProxyCreatorSupport:

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

Это приводит нас кDefaultAopProxyFactoryЭтот класс, давайте посмотрим на его метод createAopProxy(...):

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

   @Override
   public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      // (我也没用过这个optimize,默认false) || (proxy-target-class=true) || (没有接口)
      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.");
         }
         // 如果要代理的类本身就是接口,也会用 JDK 动态代理
         // 我也没用过这个。。。
         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         // 如果有接口,会跑到这个分支
         return new JdkDynamicAopProxy(config);
      }
   }
   // 判断是否有实现自定义的接口
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }

}

На данный момент мы знаем, что метод createAopProxy может возвращать экземпляр JdkDynamicAopProxy или экземпляр ObjenesisCglibAopProxy. Вот сводка:

Если целевой класс прокси реализует один или несколько пользовательских интерфейсов, то будет использоваться динамический прокси JDK. Если интерфейс не реализован, для реализации прокси будет использоваться CGLIB. Если установлено значение proxy-target-class="true", то CGLIB будет использоваться.

Динамический прокси JDK основан на интерфейсе, поэтому будут улучшены только методы в интерфейсе, в то время как CGLIB основан на наследовании классов.Следует отметить, что если метод оформлен с помощью final или private, его нельзя улучшить.

Теперь, когда у нас есть экземпляр AopProxy, мы вернулись к этому методу:

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

Давайте рассмотрим реализацию getProxy(classLoader) двух классов реализации AopProxy по отдельности.

Исходный код класса JdkDynamicAopProxy относительно прост, всего более 200 строк.

@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(…) требует трех параметров, первый — ClassLoader, второй параметр представляет, какие интерфейсы необходимо реализовать, а третий параметр является наиболее важным и является экземпляром InvocationHandler. Это связано с тем, что JdkDynamicAopProxy сам реализует интерфейс InvocationHandler.

InvocationHandler имеет только один метод, когда созданный прокси-класс будет предоставлять услуги внешнему миру, он будет импортирован в этот метод:

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

Давайте посмотрим на реализацию JdkDynamicAopProxy:

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

      // 如果设置了 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.
      // 创建一个 chain,包含所有要执行的 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 是空的,说明不需要被增强,这种情况很简单
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         // 执行方法,得到返回值
         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);
      }
   }
}

Я сказал об этом в нескольких словах выше, и заинтересованным читателям нетрудно самостоятельно изучить ее глубже. Проще говоря, при выполнении каждого метода определите, нужно ли доработать метод один или несколько раз (выполнить один или несколько советов).

После разговора о динамическом прокси-сервере JDK JdkDynamicAopProxy#getProxy(classLoader) давайте взглянем на реализацию прокси-сервера CGLIB ObjenesisCglibAopProxy#getProxy(classLoader).

ObjenesisCglibAopProxy расширяет CglibAopProxy, который, в свою очередь, расширяет AopProxy.

ObjenesisCglibAopProxy использует библиотеку Objenesis.Как и cglib, нам не нужно полагаться на maven, потому что spring-core.jar напрямую приносит свой исходный код.

3

Объем кода для генерации прокси через CGLIB немного великоват, поэтому мы не будем проводить глубокий анализ, а взглянем на общий скелет. Его метод 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, который здесь обсуждаться не будет.

Анализ исходного кода Spring AOP на основе аннотаций

Выше мы представили использование DefaultAdvisorAutoProxyCreator для реализации исходного кода Spring AOP Здесь мы также рассмотрим принцип реализации @AspectJ.

Как мы уже говорили, есть два способа включить @AspectJ, один из них<aop:aspectj-autoproxy/>,один@EnableAspectJAutoProxy, их принцип тот же, они достигаются путем регистрации бина.

Разобрать<aop:aspectj-autoproxy/>Необходимо использовать AopNamespaceHandler:

4

Затем в класс AspectJAutoProxyBeanDefinitionParser:

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

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

Перейдите в метод 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);
}

Затем перейдите в AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(...):

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

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

Наконец, мы видим, что Spring зарегистрировал bean-компонент AnnotationAwareAspectJAutoProxyCreator, а beanName: «org.springframework.aop.config.internalAutoProxyCreator».

Давайте посмотрим на структуру наследования AnnotationAwareAspectJAutoProxyCreator:

5

Как и представленный ранее DefaultAdvisorAutoProxyCreator, он также является BeanPostProcessor, и мы не будем говорить об остальном, он и его родительский класс AspectJAwareAdvisorAutoProxyCreator несложны.

Светская беседа

Зачем это говорить? Потому что я обнаружил, что многие люди думают, что Spring AOP действует на прокси-сервер генерации компонентов через этот интерфейс.

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.

Это действительно трудно сказать, если вы не посмотрите внимательно Вот два метода в BeanPostProcessor:

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

Не найдено, InstantiationAwareBeanPostProcessorInstantiation, BeanPostProcessorInitialization, что означает, что экземпляр bean-компонента создан и внедрение свойства завершено до и после выполнения метода init.

И время выполнения InstantiationAwareBeanPostProcessor раньше, вам нужно отключить исходный код IOC:

// AbstractAutowireCapableBeanFactory 447行
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
   ...
   try {
      // 让 InstantiationAwareBeanPostProcessor 在这一步有机会返回代理
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean; 
      }
   }
   // BeanPostProcessor 是在这里面实例化后才能得到执行
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   ...
   return beanInstance;
}

Нажмите и увидите метод resolveBeforeInstantiation(beanName, mbdToUse), а затем он приведет к методу postProcessBeforeInstantiation класса InstantiationAwareBeanPostProcessor.Для анализируемого нами АОП реализация этого метода находится в классе 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;
}

Как мы видим, здесь тоже есть логика для создания прокси, так что многие ошибаются. Действительно, здесь можно создать прокси, но только если у нас есть кастомная реализация TargetSource для соответствующего bean-компонента, и будет понятно, когда мы введем метод getCustomTargetSource(...), нам нужно настроить customTargetSourceCreators, который представляет собой массив TargetSourceCreators.

Я не буду здесь распространяться о TargetSource, обратитесь к справочнику по Spring.Using TargetSources.

резюме

Эта статья действительно беглый взгляд, и она сильно отличается от статей, которые я писал ранее, надеюсь, она не понравится читателям.

Однако, если читатель видел предыдущуюАнализ исходного кода Spring IOCиВведение в использование Spring АОПЕсли вы читали эти две статьи, вы должны иметь хорошее представление о реализации исходного кода Spring AOP, прочитав эту статью.

В этой статье говорится, что подробностей относительно немного.Если вы обнаружите что-то, чего не понимаете, когда смотрите исходный код, вы можете оставить сообщение в области комментариев, чтобы связаться с вами.

(Конец полного текста)