AOP详解之三-创建AOP代理后记,创建AOP代理

Posted 程序员田同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP详解之三-创建AOP代理后记,创建AOP代理相关的知识,希望对你有一定的参考价值。

AOP详解之三-创建AOP代理后记,创建AOP代理。

上篇文章已经获取到了AOP的信息,接下来就是拿着这些AOP的信息去创建代理了。

首先我们看下创建AOP代理的入口处。

//这个方法将返回代理类
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) 
        // 1.判断当前bean是否在targetSourcedBeans缓存中存在(已经处理过),如果存在,则直接返回当前bean
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) 
            return bean;
        
        // 2.在advisedBeans缓存中存在,并且value为false,则代表无需处理
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) 
            return bean;
        
        // 3.bean的类是aop基础设施类 || bean应该跳过,则标记为无需处理,并返回
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) 
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        

        // Create proxy if we have advice.
        // 4.获取当前bean的Advices和Advisors
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        // 5.如果存在增强器则创建代理
        if (specificInterceptors != DO_NOT_PROXY) 
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 创建代理...创建代理...创建代理...
            // 5.1 创建代理对象:这边SingletonTargetSource的target属性存放的就是我们原来的bean实例(也就是被代理对象),
            // 用于最后增加逻辑执行完毕后,通过反射执行我们真正的方法时使用(method.invoke(bean, args))
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            // 5.2 创建完代理后,将cacheKey -> 代理类的class放到缓存
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        
        // 6.标记为无需处理
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    

在5.1的位置开始创建代理对象,我们从此开始深入创建AOP代理的源码。

// 注意看这个方法的几个参数,
    //   第三个参数携带了所有的 advisors
    //   第四个参数 targetSource 携带了真实实现的信息
    protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
            @Nullable Object[] specificInterceptors, TargetSource targetSource) 

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

        // 创建 ProxyFactory 实例
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        // 检查proxyTargetClass属性,判断对于给定的bean使用类代理还是接口代理,
        // proxyTargetClass值默认为false,可以通过proxy-target-class属性设置为true
        if (!proxyFactory.isProxyTargetClass()) 
            if (shouldProxyTargetClass(beanClass, beanName)) 
                proxyFactory.setProxyTargetClass(true);
            
            else 
                evaluateProxyInterfaces(beanClass, proxyFactory);
            
        

        // 获取Advisor顾问对象
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

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

        // 2.使用proxyFactory获取代理
        return proxyFactory.getProxy(getProxyClassLoader());
    

在2位置拿着我们new的代理工厂获取我们的代理对象。

    public Object getProxy(@Nullable ClassLoader classLoader) 
        // 1.createAopProxy:创建AopProxy
        // 2.getProxy(classLoader):获取代理对象实例
        return createAopProxy().getProxy(classLoader);
    

第一步是获取AOP的代理对象

/**
     * 创建AOP对象的真正实例
     * @param config the AOP configuration in the form of an
     * AdvisedSupport object
     * @return
     * @throws AopConfigException
     */
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException 
        // 1.判断使用JDK动态代理还是Cglib代理
        // optimize:用于控制通过cglib创建的代理是否使用激进的优化策略。除非完全了解AOP如何处理代理优化,
        // 否则不推荐使用这个配置,目前这个属性仅用于cglib代理,对jdk动态代理无效
        // proxyTargetClass:默认为false,设置为true时,强制使用cglib代理,设置方式:<aop:aspectj-autoproxy proxy-target-class="true" />
        // hasNoUserSuppliedProxyInterfaces:config是否存在代理接口或者只有SpringProxy一个接口
        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.");
            
            // 要被代理的对象是接口 || targetClass是Proxy class
            // 当且仅当使用getProxyClass方法或newProxyInstance方法动态生成指定的类作为代理类时,才返回true。
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) 
                // JDK动态代理,这边的入参config(AdvisedSupport)实际上是ProxyFactory对象
                // 具体为:AbstractAutoProxyCreator中的proxyFactory.getProxy发起的调用,在ProxyCreatorSupport使用了this作为参数,
                // 调用了的本方法,这边的this就是发起调用的proxyFactory对象,而proxyFactory对象中包含了要执行的的拦截器

                return new JdkDynamicAopProxy(config);
            
            // Cglib代理
            return new ObjenesisCglibAopProxy(config);
        
        else 
            // JDK动态代理
            return new JdkDynamicAopProxy(config);
        
    

第二步是获取真实的对象

我们接着看getProxy这个方法,该方法有两个实现类。

我们实现类也就是我们常说的实现AOP的两种方式,使用cglib和jdk动态代理的方式。

我们简要的介绍一下这两种aop的原理。

动态代理步骤:
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用invoke方法

我们分别看下这两种实现方式。

JDK的方式

@Override
public Object getProxy(@Nullable ClassLoader classLoader) 
   if (logger.isTraceEnabled()) 
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   
   // 1.拿到要被代理对象的所有接口
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   // 2.通过classLoader、接口、InvocationHandler实现类,来获取到代理对象
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

getproxy这个方法已经创建了代理对象,接下来就要执行实现类的invoke方法了。

显而易见,我们这上一步将环绕通知都已经包装好了,这一步代理对象也已经创建好了,接下来肯定就是要处理我们环绕通知里面的方法了。

//当我们调用了被 AOP 代理的方法时,使用 JDK 动态代理会走到 JdkDynamicAopProxy#invoke 方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
   Object oldProxy = null;
   boolean setProxyContext = false;

   // 1.advised就是proxyFactory,而targetSource持有被代理对象的引用
   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try 
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) 
         // The target does not implement the equals(Object) method itself.
         // 目标不实现equals(Object)方法本身。
         return equals(args[0]);
      
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) 
         // The target does not implement the hashCode() method itself.
         return hashCode();
      
      else if (method.getDeclaringClass() == DecoratingProxy.class) 
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         // 只有getDecoratedClass()声明 - > dispatch到代理配置。
         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...
         // ProxyConfig上的服务调用与代理配置..
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      

      Object retVal;

      // 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理
      if (this.advised.exposeProxy) 
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      

      // Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      // 2.拿到我们被代理的对象实例
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      // 3.获取拦截器链:例如使用@Around注解时会找到AspectJAroundAdvice,还有ExposeInvocationInterceptor
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we dont, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      // 4.检查我们是否有任何拦截器(advice)。 如果没有,直接反射调用目标,并避免创建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.
         // 5.不存在拦截器链,则直接进行反射调用
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      
      else 
         // We need to create a method invocation...
         // 6.如果存在拦截器,则创建一个ReflectiveMethodInvocation:代理对象、被代理对象、方法、参数、
         // 被代理对象的Class、拦截器链作为参数创建ReflectiveMethodInvocation
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         // 7.触发ReflectiveMethodInvocation的执行方法
         retVal = invocation.proceed();
      

      // Massage return value if necessary.
      // 8.必要时转换返回值
      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 cant 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);
      
   

cglib方式

@Override
public Object getProxy(@Nullable ClassLoader classLoader) 
   if (logger.isTraceEnabled()) 
      logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
   

   try 
      // 1.拿到要代理目标类
      Class<?> rootClass = this.advised.getTargetClass();
      Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

      Class<?> proxySuperClass = rootClass;
      if (ClassUtils.isCglibProxyClass(rootClass)) 
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) 
            // 将父类的接口也添加到advised的interfaces属性
            this.advised.addInterface(additionalInterface);
         
      

      // Validate the class, writing log messages as necessary.
      // 2.校验proxySuperClass,主要是校验方法是否用final修饰、跨ClassLoader的包可见方法,如果有将警告写入日志
      validateClassIfNecessary(proxySuperClass, classLoader);

      // Configure CGLIB Enhancer...
      // 3.创建和配置Cglib Enhancer
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) 
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) 
            enhancer.setUseCache(false);
         
      
      // superclass为被代理的目标类proxySuperClass,通过名字可以看出,生成的代理类实际上是继承了被代理类
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      // 4.获取所有要回调的拦截器
      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
      // 在上面调用getCallbacks之后,此时仅填充fixedInterceptorMap
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate the proxy class and create a proxy instance.
      // 5.生成代理类并创建代理实例,返回代理实例
      return createProxyClassAndInstance(enhancer, callbacks);
   
   catch (CodeGenerationException | IllegalArgumentException ex) 
      throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
            ": Common causes of this problem include using a final class or a non-visible class",
            ex);
   
   catch (Throwable ex) 
      // TargetSource.getTarget() failed
      throw new AopConfigException("Unexpected AOP exception", ex);
   

总结一下AOP的整个流程,在Spring的核心方法refresh()中,创建单例对象前会执行InstantiationAwareBeanPostProcessor 方法的实现类,类似于Spring的前置处理器。

在实现类中会先将环绕通知包装好,后执行创建代理方法,执行前判断是jdk动态代理还是cglib,在jdk动态代理中,处理我们的环绕通知,以执行切面方法时进行执行。

历时三个月将Spring的IOC和AOP的源码解读就结束了,如果读者想完整的熟悉整个流程,可以看历史文章一步步的揭开Spring的神秘面纱。

以上是关于AOP详解之三-创建AOP代理后记,创建AOP代理的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP详解

Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

基于代理类的AOP实现

AOP源码解析之二-创建AOP代理前传,获取AOP信息。

Spring读源码系列之AOP--07---aop自动代理创建器(拿下AOP的最后一击)

AOP 代理类的创建