美文网首页
spring--aop_1_源码分析之JdkDynamicAop

spring--aop_1_源码分析之JdkDynamicAop

作者: 达微 | 来源:发表于2021-11-04 11:29 被阅读0次

    aop 实现有两种方式

    1. ProxyFactoryBean方式: 这种方式是通过配置实现
    2. ProxyFactory方式:这种方式是通过编程实现

    这里说 ProxyFactoryBean ,先上一张ProxyFactoryBean 的关系图,后面能用到。

    示例代码:

    /**

    • 代理接口,如果不是接口使用CGLIB代理
      /
      public interface ProxyInterface {
      void m();
      void t();
      }
      /
      *

    • 目标对象,接口的实现类
      */
      public class Target implements ProxyInterface {
      @Override
      public void m() {
      System.out.println("m");
      }

      @Override
      public void t() {
      System.out.println("t");
      }
      }

    /**

    • 通知器
      /
      public class BeforeAdvice implements MethodBeforeAdvice {
      @Override
      public void before(Method method, Object[] args, Object target) throws Throwable {
      System.out.println("BeforeAdvice.....");
      }
      }
      /
      *
    • 通知器
      */
      public class AfterAdvice implements AfterReturningAdvice {
      @Override
      public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
      System.out.println("AfterAdvice.....");
      }
      }
      定义一个接口ProxyInterface, 实现类为 Target,声明了两个advice,用来增强Target 方法。配置文件如下(advice 配置的顺序就是调用的顺序):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 目标类 -->
    <bean id="target" class="com.masz.springtest.aop.proxy.Target"/>
    
    <!-- advice -->
    <bean id="beforeAdvice" class="com.masz.springtest.aop.proxy.BeforeAdvice"/>
    <bean id="afterAdvice" class="com.masz.springtest.aop.proxy.AfterAdvice"/>
    
    <!-- 增强代理对象,ProxyFactoryBean 是一个FactoryBean , getBean() 时会调用它的getObject() 方法 -->
    <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    
        <!-- 代理接口,如果没有接口使用CGLIB生成代理类-->
        <property name="proxyInterfaces">
            <list>
                <value>com.masz.springtest.aop.proxy.ProxyInterface</value>
            </list>
        </property>
        <property name="singleton" value="true"/>  <!-- 是否是单例 -->
        <property name="target" ref="target"/>  <!-- 指定增强目标bean -->
    
        <!-- 拦截器名称 -->
        <property name="interceptorNames">
            <list>
                <value>beforeAdvice</value>
                <value>afterAdvice</value>
            </list>
        </property>
    </bean>
    

    </beans>
    测试:

    public static void main(String[] args) {
    ConfigurableApplicationContext applicationContext = SpringApplication.run(AopTest.class, args);

    //直接获取目标类
    Target t = applicationContext.getBean(Target.class);
    t.m();
    
    //获取目标的代理。 关键的是:ProxyFactoryBean  是一个FactoryBean
    ProxyInterface  proxy = (ProxyInterface)applicationContext.getBean("targetProxy");
    proxy.m();
    System.exit(0);
    

    }
    运行结果:

    m
    BeforeAdvice.....
    m
    AfterAdvice.....

    第一个方法没有被增强,第二个方法被增强了。

    源码分析:

    从代码中可以看到,通过applicationContext.getBean()获取ProxyFactoryBean, ProxyFactoryBean 是一个FactoryBean 所以getObject() 方法就是获取代理对象的入口方法。

    ProxyFactoryBean.getObject() 源码:

    @Override
    @Nullable
    public Object getObject() throws BeansException {
    //初始化advisor 链
    initializeAdvisorChain();

    //对singleton 和 prototype 类型区分,生成相应的proxy
    if (isSingleton()) {
        //是singleton,调用此方法生成代理对象
        return getSingletonInstance();
    }
    else {
        if (this.targetName == null) {
            logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                    "Enable prototype proxies by setting the 'targetName' property.");
        }
        //不是singleton,创建一个Prototype 的实例的代理对象
        return newPrototypeInstance();
    }
    

    }
    initializeAdvisorChain() 初始化 advisor chain:

    /**

    • 创建advisor 链。
    • advisor 信息从BeanFactory 来的,每当创建一个新的prototype实例被创建时,BeanFactory 就会被刷新。
    • 拦截器通过factory api 以编程的方式被添加,而且不受advisor改变的影响。

    过程:
    这个初始化advisor 链,是应用第一次通过 ProxyFactoryBean 获取代理对象时触发的,
    advisor 链初始化完成之后,会读取配置中所有的通知器,这个读取比较简单就是调用容器的getBean()方法;
    然后把获取的advice 加入到 advisor 链中,这个过程是addAdvisorOnChainCreation() 方法实现

    */
    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
    //这个是个标识位,标记通知器链是否已经初始化过了,如果已经初始化完了就直接返回。
    if (this.advisorChainInitialized) {
    return;
    }

    //配置的advice 不能是空的,如果没有配置advice就不用增强了。
    if (!ObjectUtils.isEmpty(this.interceptorNames)) {
    
        //所有的bean 都是BeanFactory 管理的,所以BeanFactory不能是空
        if (this.beanFactory == null) {
            throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                    "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
        }
    
        // Globals can't be last unless we specified a targetSource using the property...
        if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
                this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("Target required after globals");
        }
    
        //遍历所有的advice 名称配置,获取advice bean 并且添加到 advisor 链
        for (String name : this.interceptorNames) {
            if (logger.isTraceEnabled()) {
                logger.trace("Configuring advisor or advice '" + name + "'");
            }
    
            //interceptor name 是 * 结尾的
            if (name.endsWith(GLOBAL_SUFFIX)) {
                if (!(this.beanFactory instanceof ListableBeanFactory)) {
                    throw new AopConfigException(
                            "Can only use global advisors or interceptors with a ListableBeanFactory");
                }
                addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                        name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
            }
    
            else {
                // If we get here, we need to add a named interceptor.
                // We must check if it's a singleton or prototype.
                //程序运行到这里就要检查添加的 interceptor 是 singleton 还是 prototype 类型。
                
                Object advice;
                if (this.singleton || this.beanFactory.isSingleton(name)) {
                    // Add the real Advisor/Advice to the chain.
                    //单例的 advice,就从beanFactory 中get bean 了。
                    advice = this.beanFactory.getBean(name);
                }
                else {
                    // It's a prototype Advice or Advisor: replace with a prototype.
                    // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                    //prototype advice,要创建一个新的advice
                    advice = new PrototypePlaceholderAdvisor(name);
                }
                //添加advice 到 advisor chain
                addAdvisorOnChainCreation(advice, name);
            }
        }
    }
    this.advisorChainInitialized = true;
    

    }
    上面方法中的 addAdvisorOnChainCreation() 方法:
    把配置 advice 封装成一个 DefaultPointcutAdvisor 对象,包含了PointCut(默认是Pointcut.TRUE) 和 advice。
    然后把封装成的 advisor 放到 advisors 集合中,这个过程是在 类AdvisedSupport 中实现的,ProxyFactoryBean 是这个类的子类,看上图。

    getSingletonInstance() 方法, 生成 singleton 代理对象。

    /**

    • Return the singleton instance of this class's proxy object,
    • lazily creating it if it hasn't been created already.
    • @return the shared singleton proxy

    返回一个单例的代理对象,如果没有创建则会进行懒加载。

    过程:首先读取ProxyFactoryBean 的配置,为生成代理对象做好准备,如:代理接口,目录对象等。
    再通过AopProxy 生成代理对象。

    */
    private synchronized Object getSingletonInstance() {
    //如果已经创建了,就直接返回
    if (this.singletonInstance == null) {

        this.targetSource = freshTargetSource();
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
            // Rely on AOP infrastructure to tell us what interfaces to proxy.
            //根据AOP 框架来判断需要代理的接口
            Class<?> targetClass = getTargetClass();
            
            if (targetClass == null) {
                throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
            }
            //设置代理对象的接口
            setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
        }
        // Initialize the shared singleton instance.
        super.setFrozen(this.freezeProxy);
        //getProxy()方法,通过createAopProxy() 方法返回的AopProxy 得到代理对象。
        this.singletonInstance = getProxy(createAopProxy());
    }
    return this.singletonInstance;
    

    }
    /**

    • getProxy() 方法出现了AopProxy 接口对象。
      */
      protected Object getProxy(AopProxy aopProxy) {
      return aopProxy.getProxy(this.proxyClassLoader);
      }
      上面代码中 createAopProxy() 返回的是一个AopProxy对象,这个对象有两个实现类:JdkDynamicAopProxy,CglibAopProxy,看到名字就很清楚了分别对应生成代理类不同的实现方式。getProxy() 方法调用AopProxy 类的getProxy() 方法返回代理对象。
      Spring 使用AopProxy 接口对象把AOP代理的实现和框架其它部分区分开,体现面向接口编程。

    createAopProxy() 方法是在ProxyFactoryBean 父类 ProxyCreatorSupport 中实现的,ProxyCreatorSupport 中又调用了AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。

    /**

    • Subclasses should call this to get a new AOP proxy. They should <b>not</b>
    • create an AOP proxy with {@code this} as an argument.

    子类调用这个方法生成 AOP proxy。

    在 AdvisedProxy 子类 ProxyFactoryBean 中通过 AopProxyFactory 来生成代理类,AdvisedProxy 封装了所有的生成代理对象信息,如:实现接口,目录类等。
    AopProxyFactory 使用的是 DefaultAopProxyFactory,这个对象在 ProxyFactoryBean 父类 ProxyCreatorSupport 中被创建。
    createAopProxy() 方法参数就是 AdvisedProxy 类型,这里传的是this,就是 ProxyFactoryBean,ProxyFactoryBean也是AdvisedProxy子类(可以查看上面的类关系图)。

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

    //这里是调用 AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {

        //目录对象的class
        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 是接口类,使用 JDK来生成 Proxy
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        //如果不是接口类,使用CGLIB 生成代理对象
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
    

    }
    JdkDynamicAopProxy 源码分析:

    JdkDynamicAopProxy 本身实现了 InvocationHandler 接口和 AopProxy 接口所以 JdkDynamicAopProxy实现的InvocationHandler.invoker() 方法就是Proxy 对象回调的方法。
    实现的AopProxy.getProxy() 方法就是通过JDK动态代理生成的代理对象,传递的InvocationHandler 对象就是 JdkDynamicAopProxy 自身。
    这就是动态代理了,切面的实惠就是在 invoke() 方法中体现的。后面再分析如何实现AOP。

    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
    logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }
    //获取目标类上的接口并且判断是否需要添加SpringProxy Advised DecoratingProxy(spring4.3 新增) 接口
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);

    //判断的目标对象实现的接口是否定义了equals或hashCode方法,
    //在invoke() 方法调用的时候会对 equals 和 equals 做特殊的处理,参考后面
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    
    //返回动态代理对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    

    }
    总结:
    通过AopProxy 对象封装target 目标对象之后,ProxyFactoryBean方法得到的对象已经是一个AopProxy代理对象了,在ProxyFactoryBean 中配置的target目标对象不会让应用直接调用其方法的实现,对target目标对象的方法调用会被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。对于 JDK的AopProxy代理对象,使用的是InvocationHander的invoker 回调入口。对于CGLIB的AopProxy代理对象,使用的是设置好的callbak 回调,在这里callback回调中,对于AOP的实现是通过DynamicAdvisedInterceptor 来完成的,DynamicAdvisedInterceptor 的回调入口是 intercept 方法(后面再分析CGLIB)。
    这里只是AopProxy 代理对象的生成,通过这个过程把代理对象和拦截器待调用的部分都准备好。下面就分析AOP运行过程中对这些拦截器和代理对象的调用过程。

    AOP 拦截器调用实现:

    如果是JDK实现的代理对象就会通过InvocationHandler 来完成拦截器回调,如果是CGLIB 就通过DynamicAdvisedInterceptor 来完成回调。
    JdkDynamicAopProxy 的 invoke 拦截:
    在 JdkDynamicAopProxy.getProxy() 方法中,调用的的JDK动态代理生成代理类,JdkDynamicAopProxy 自身实现了InvocationHandler 接口,那么代理对象调用目标对象方法时会被invoke() 方法拦截

    JdkDynamicAopProxy.invoke() 源码:

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

    //从advised中获取目标对象
    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.
            //目标对象没有重写Object 的equals() 方法
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            //目标对象没有重写 Object的 hashCode() 方法
            return hashCode();
        }
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            // 如果方法是在DecoratingProxy声明的,
            // DecoratingProxy 只有getDecoratedClass() 一个方法,所有在这里直接调用
            // 返回代理类的终极目标类。
            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...
            //Spring AOP不会增强直接实现Advised接口的目标对象。
            //这里直接通过反射调用。
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }
    
        //返回值
        Object retVal;
    
        //是否暴露代理对象,如果暴露意味着在线程内共享代理对象,在线程内可通过AopContext 获取代理对象。就是通过ThreadLocal 实现的。
        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.
        // 目标对象
        target = targetSource.getTarget();
        // 目标对象类
        Class<?> targetClass = (target != null ? target.getClass() : null);
    
        // Get the interception chain for this method.
        //获取目标方法的拦截器链
        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.
        // 检查是否的拦截器,如果没有那么就直接通过反射调用目标方法,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.
            //如果没有拦截器,就不用创建 MethodInvocation,直接在目标对象上反射调用方法
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // We need to create a method invocation...
            //创建一个 ReflectiveMethodInvocation,这个类是实现AOP的功能的封装
            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();
        // retVal不空 并且和目标方法的返回类型一致,就返回。
        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);
        }
    }
    

    }
    注:
    invoke 方法中获取调用拦截器链方法
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    这个方法把 PintcutAdvice 封装成 MethodInterceptor。MethodInterceptor 有两个实现类具体的为 MethodBeforeAdviceInterceptor 和 AfterReturningAdviceInterceptor
    MethodInterceptor.invoke() 方法,将的 ReflectiveMethodInvocation.proceed() 中被调用,MethodInterceptor.invoke()方法的参数就是 MethodInvocation 类型,而 ReflectiveMethodInvocation 是 MethodInvocation 的子类,在invoke() 方法中又回调了 MethodInvocation.proceed()方法,这样就又回调回去了,当 "this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1" 时也就是拦截器调用完了,就通过反射调用目标方法。
    ReflectiveMethodInvocation 和 MethodInterceptor 就是实现Spring AOP 的核心所在。具体查看MethodBeforeAdviceInterceptor 和 AfterReturningAdviceInterceptor 这个两个实现源码就

    JdkDynamicAopProxy AOP功能,就是通过 ReflectiveMethodInvocation 类实现的

    ReflectiveMethodInvocation.proceed() 源码分析:

    //这个方法是递归方法,当所有拦截器都执行完毕了,就通过反射调用目标方法返回。
    @Override
    @Nullable
    public Object proceed() throws Throwable {

    //  We start with an index of -1 and increment early.
    //使用 currentInterceptorIndex 记录拦截器调用的下标,当所有拦截器都调用完毕后,通过反射调用目标方法。
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        //反射调用目标方法
        return invokeJoinpoint();
    }
    
    //从拦截器链中获取一个拦截器,下标是  ++this.currentInterceptorIndex
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        
        //动态匹配
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                
        //如果方法和定义的切点匹配成功就执行
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        //执行到这里就是一个 MethodInterceptor , 则直接调用
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    

    }
    在示例代码中配置的是通知器,不是切面,如果配置的是切面就要走动态匹配了(动态匹配就是走jdk的正则匹配 MethodMatcher ,不扩展了)。

    总结:每个 MethodInterceptor 对应的都有实现AfterReturningAdviceInterceptor, MethodBeforeAdviceInterceptor, ThrowsAdviceInterceptor。如 MethodBeforeAdviceInterceptor

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
    

    则是调用完invoke() 方法后,就又调用了MethodInvocation.proceed() 方法,又回到了上一步方法中,这样一直循环调用,直到所有的interceptor 调用完毕。

    总结:ProxyFactoryBean 通过jdk动态代理机制生成代理对象,当调用代理对象方法时,会被invoke() 方法拦截。在invoke() 方法中又获取了此方法的拦截器,通过对拦截器的调用实现了spring aop功能。CGLIB的实现只是生成代理对象的方式不同,这就让拦截器的入口有了变化。拦截器的生成和调用机制是一样的。看第二篇。

    注:这里通过 initializeAdvisorChain(); 把advice 封装成了advisor,又如何把advisor 封装成具体的interceptor 呢? 看后续...
    ————————————————
    版权声明:本文为CSDN博主「Jamin_Ma」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/convict_eva/article/details/81084833

    相关文章

      网友评论

          本文标题:spring--aop_1_源码分析之JdkDynamicAop

          本文链接:https://www.haomeiwen.com/subject/sizhzltx.html