`

jdk动态代理的情况下 前后置advice的调用过程分析 part1

阅读更多

这次要分析的是JdkDynamicAopProxy 中的invoke方法 因为AOP中 在target方法调用的前后 以及 异常时 调用各种advice的逻辑都在这个方法里

所以主要分析这个方法.

这个方法主要分两个步骤

1.获取到Interceptor链

2.执行方法调用

其中获取到Interceptor链是通过从advisor里面获取到advice的引用 用MethodInterceptor的实现类包装起来,存放在一个数组里

前置通知 用的是MethodBeforeAdviceInterceptor类   后置通知用的是AfterReturningAdviceInterceptor类

 

执行方法调用则是调用了org.springframework.aop.framework.ReflectiveMethodInvocation 里面的proceed方法

递归的去处理每一个Interceptor  很巧妙的实现了前置advice在target方法之前执行   后置advice在target方法之后执行


下面就来分析一下这个过程 我可能有删减一些代码 

我们的分析从JdkDynamicAopProxy 类的invoke方法方法开始

 

至于advice对象和advisor对象以及pointcut对象的生成 是Ioc的内容  具体这些对象的引用又是如何设置到AdvisedSupport类对象里面去的

下次再做分析 这些都不是很核心的逻辑


org.springframework.aop.framework.JdkDynamicAopProxy 是AopProxy的一个实现类

用于获取AOP代理后的对象

invoke方法 就是代理后执行的方法

/**
     * Implementation of <code>InvocationHandler.invoke</code>.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    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 {
            Object retVal;
            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();
            }
  
            //获取Interceptor链 这是比较核心的一步
            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.
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                  
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //执行Interceptor链 这里是一个递归的过程
                retVal = invocation.proceed(); 
            }
            return retVal;
        }
    }

 主要分析标黄的两行代码

1.获取Interceptor chain  用于在方法执行之前 或者之后执行

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

 

2.方法调用 

retVal = invocation.proceed();

 

 


先看获取Interceptor chain

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

进入到org.springframework.aop.framework.AdvisedSupport类中  这个类AOP的一个根配置管理类 存储了AOP创建代理对象和执行interceptors所需的各种属性

比如 

interfaces  创建代理对象所要实现的接口,

targetSource  持有真实对象引用的一个包装类 也是创建代理对象要用到的,

methodCache 一个list 存放了每个方法对应的interceptor链,

advisors 所有的advisor的一个集合

等等...

 

 首先进入getInterceptorsAndDynamicInterceptionAdvice方法

 

 

/**
     * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
     * for the given method, based on this configuration.
     * @param method the proxied method
     * @param targetClass the target class
     * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
     */
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
        根据方法对象 生成cachekey  然后在缓存methodCache里面获取 如果能够获取到当前执行的这个方法对于的advisor chain 那么直接返回
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            如果获取不到 那么就要重新创建
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }

 

 下面进入到org.springframework.aop.framework.DefaultAdvisorChainFactory

这是一个工厂类 专门生成advice chain 

 

这里传进来的config参数 就是上面讲到的 AdvisedSupport实例 
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class targetClass) {
  
        // This is somewhat tricky... we have to process introductions first,
        // but we need to preserve order in the ultimate list.
        创建一个list 长度就和AdvisedSupport实例 里面存储的advisors集合长度一样
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
  
        //获取一个AdvisorAdapterRegistry 实例 用于后面把advice包装成Interceptor用的
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        //开始遍历
        for (Advisor advisor : config.getAdvisors()) {
        在beans.xml里面配置的advisor 是DefaultPointcutAdvisor类型 也就是PointcutAdvisor的子类 所以这里是符合的
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
                    开始把advisor的集合 转换成MethodInterceptor的数组 这里就用到AdvisorAdapterRegistry 了
具体转换的过程 后面会写到
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    开始做pointcut的方法名称匹配 用的是正则表达式
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            判断成功 但是mm.isRuntime()是false  这个isRuntime的含义还有待研究  然后 把每个method对于的interceptors添加到一个总的集合
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        最后返回这个集合
        return interceptorList;
    }

 可以看到 返回的4个interceptor对象的集合

 

 

 两个前置 两个后置 因为我在xml里是这样配置的

 

   <bean id="studentProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

            <property name="proxyInterfaces">
                <value>com.test.aop.IStudent</value>
            </property>
            <property name="target">
                <ref bean="targetStudent"/>
            </property>
            <property name="interceptorNames">
                <list>
                    <value>ReadingAdvisorBefore</value>
                    <value>ReadingAdvisorBefore</value>
                    <value>ReadingAdvisorAfter</value>
                    <value>ReadingAdvisorAfter</value>
                </list>
            </property>
        </bean>

 

 另外 这个过程中有一个advisor转换成Interceptor数组的过程  是这样的

 

 

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }

 

/**
 * Adapter to enable {@link org.springframework.aop.MethodBeforeAdvice}
 * to be used in the Spring AOP framework.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
  
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }
  
    public MethodInterceptor getInterceptor(Advisor advisor) {
        获取出advisor里面持有的advice对象 
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        然后用MethodBeforeAdviceInterceptor这个类包装起来
        return new MethodBeforeAdviceInterceptor(advice);
    }
  
}

 

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
  
    private MethodBeforeAdvice advice;
 
    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    MethodBeforeAdviceInterceptor的构造方法很简单 就是把advice的引用传进来即可    
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }
    这里就是后面调用前置后置通知的关键了 this.advice.before()调用了前置通知  
    mi.proceed(); 则重新回到proceed方法 开始执行下一个Interceptor  是递归的
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        return mi.proceed();
    }
  
}

 好了至此就已经获取到 Interceptor chain  可以开始做调用了

 

 

 

 

 

 

 

 

 

 

  • 大小: 6.2 KB
  • 大小: 7.9 KB
分享到:
评论

相关推荐

    JDK动态代理_JDK动态代理

    下面是一个简单的示例,演示了如何使用JDK动态代理为一个接口创建代理对象,并在方法调用前后添加日志记录功能。 ```java /** * 业务接口 */ public interface IHello { void hello(String name); } /** * ...

    关于jdk动态代理的源码剖析

    ### 关于JDK动态代理的源码剖析 #### 一、引言 在Java开发过程中,动态代理技术是一项非常实用的技术,它可以帮助我们实现在不修改原有代码的基础上为方法增加额外的功能,比如日志记录、权限校验等。本文将深入...

    浅谈JDK动态代理与CGLIB代理去区别

    在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...

    Spring框架中JDK动态代理和cglib动态代理

    在 Spring AOP 框架中,默认情况下,Spring 会选择使用 JDK 动态代理,但是如果目标对象没有实现接口,Spring 就会选择使用 CGLIB 动态代理。这种机制可以确保 Spring AOP 框架可以代理任何类型的对象,无论它是否...

    JDK动态代理源码

    1. **Java.lang.reflect.Proxy**:这是JDK动态代理的关键类,它提供了创建动态代理对象的工厂方法`newProxyInstance()`。这个方法接收三个参数:`ClassLoader`用于加载代理类,`Interface[]`表示代理对象需要实现的...

    jdk动态代理技术详解

    动态代理的优点在于可以在不修改原有代码的情况下,增加新的功能,从而提高软件的灵活性和扩展性。 结论 JDK 动态代理技术是 Java 语言自身对动态代理的支持,提供了一种灵活和高效的方式来实现动态代理。通过...

    JDK动态代理简单示例

    总之,JDK动态代理为我们提供了一种灵活的代码扩展机制,使得在不修改原有代码的情况下,可以方便地添加额外的功能或者监控代码行为。在实际项目中,如日志记录、性能监控、事务管理等方面,JDK动态代理都有广泛的...

    JDK动态代理 spring aop 的原理

    在Java编程领域,JDK动态代理是实现动态创建代理对象的一种技术,它是Java标准库提供的一种强大工具。Spring AOP(面向切面编程)则是一种流行的应用框架,它利用动态代理来实现对业务代码的切面增强,如日志、事务...

    java代理机制 JDK动态代理和cglib代理 详解

    Java代理机制为我们提供了在运行时扩展功能的能力,无论是JDK动态代理还是CGLIB代理,都是为了在不修改源代码的前提下,增加新的行为或者监控已有行为。选择哪种代理方式取决于具体需求,如果目标类实现了接口,优先...

    AOP之JDK动态代理和CGLib动态代理

    Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...

    jdk动态代理和CGlib动态代理

    JDK动态代理适用于目标类已经实现了接口的情况,而CGlib则可以处理未实现接口的类。两者都可以在运行时增加额外的行为,但实现方式和性能特性有所不同。JDK动态代理通常更简洁,因为不需要生成子类,但对目标类的...

    Jdk动态代理和cglib动态代理原理

    - **CGLIB代理**适用于目标类没有接口或者不希望修改原有接口的情况,其性能通常优于JDK代理,因为它是基于字节码生成的子类,而JDK代理需要反射调用接口方法。 在实际开发中,如Spring AOP框架就同时支持JDK和...

    代理模式,JDK动态代理,SpringAOP来龙去脉

    - 分析JDK动态代理的源码,可以了解其内部如何生成代理类和调用处理程序的工作机制。 - Spring AOP的源码解析有助于理解其是如何创建代理、匹配切点并执行相应通知的过程。 5. **工具应用**: - JDK动态代理和...

    spring jdk动态代理

    这个代理对象实现了目标对象的所有接口,因此可以在不修改原有代码的情况下,对方法调用进行拦截。当我们通过代理调用方法时,实际上是在调用`InvocationHandler`的`invoke`方法。 `InvocationHandler`接口有一个`...

    模拟JDK动态代理内部实现

    在Java编程中,动态代理是一种强大的技术,...通过阅读和分析提供的代码文件(3-1代码、3-2代码、3-3代码),我们可以看到具体的实现细节,如方法的调用链路、参数处理和异常处理等,从而进一步巩固对动态代理的理解。

    jdk 的动态代理和CGLIB代理

    jdk 的动态代理和CGLIB代理

    java jdk 动态代理 演示demo

    总结,Java JDK的动态代理为我们提供了一种灵活的方式,可以在不修改原始代码的情况下扩展或修改对象的行为。通过创建代理对象,我们可以方便地实现如日志记录、事务管理、权限验证等附加功能,极大地提高了代码的可...

    JDK动态代理和CGLIB代理

    总结起来,JDK动态代理适用于目标对象实现了接口的情况,而CGLIB代理则可以在没有接口的情况下进行代理。两者都可以实现运行时的代理,但适用场景不同,开发者可以根据具体需求选择适合的代理方式。在实际开发中,...

    JDK动态代理理解

    这个过程展示了动态代理如何帮助我们在不修改原始业务代码的情况下,增加日志记录功能。这种机制对于开发灵活、可扩展的应用程序非常有用,尤其是在需要实现横切关注点的场景下。 #### 五、动态代理的局限性与扩展 ...

Global site tag (gtag.js) - Google Analytics