zoukankan      html  css  js  c++  java
  • AOP动态代理解析4-jdk代理的实现

    JDKProxy的使用关键是创建自定义的InvocationHandler,而InvocationHandler中包含了需要覆盖的函数getProxy,而当前的方法正是完成了这个操作。在此确认一下JDKDynamicAopProxy也确实实现了InvocationHandler接口,那么我们就可以推断出,在JdkDynamicAopProxy中一定会有个invoke函数,并且JdkDynamicAopProxy会把AOP的核心逻辑写在其中。查看代码,果然有这样个函数:

    JdkDynamicAopProxy.java  获取代理对象的主要方法

        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);
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }

    主要切面逻辑在InvocationHandler的invoke方法中,而JdkDynamicAopProxy本身就实现了InvocationHandler

        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 {
           //equals方法的处理
    if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); }
           //hash方法的处理
    if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } //Class类的isAssignableFrom(Class cls)方法:如果调用这个方法的class或接口与参数cls表示的类或接口相同,
           //或者参数与cls表示的类或接口的父类,则返回true
    //形象地:自身类.class.isAssignableFrom(自身类或子类.class)返回true。例: //System.out.println(ArrayList.class.isAssignableFrom(Object.class));//false //System.out.println(Object.class.isAssignableFrom(ArrayList.class));//true 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;        //有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理 if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } //获取当前方法的拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { //如果没有发现任何拦截器那么直接调用切点方法 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { //将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链表用拦截器 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); //使用拦截器链 retVal = invocation.proceed(); } // Massage return value if necessary. Class<?> returnType = method.getReturnType();
           //返回结果
    if (retVal != null && retVal == target && 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); } } }

    上面的函数中最主要的工作就是创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用,那么继续来研究,在proceed方法中是怎么实现前置增强在目标方法前调用后置增强在目标方法后调用的逻辑呢?

    public Object proceed() throws Throwable  {  
        //执行完所有增强后执行切点方法  
        if(currentInterceptorIndex == interceptorsAndDynamicMethodMatchers.size() - 1)  
            return invokeJoinpoint();  
        //获取下一个要执行的拦截器  
        Object interceptorOrInterceptionAdvice = interceptorsAndDynamicMethodMatchers.get(++currentInterceptorIndex);  
        if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher)  
        {   //动态匹配  
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;  
            if(dm.methodMatcher.matches(method, targetClass, arguments))  
                return dm.interceptor.invoke(this);  
            else  
                //不匹配则不执行拦截器  
                return proceed();  
        } else  
        {  
              //普通拦截器,直接调用拦截器,如:MethodBeforeAdviceInterceptor,AspectJAroundAdvice,AdpectJAfterAdvice  
              //将this作为参数传递以保证当前实例中调用链的执行  
             return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);  
        }  
    }  

    在proceed方法中,获取代码逻辑并没有那么复杂,ReflectiveMethodInvocation中的主要职责是维护了链接调用的计数器,记录着当前调用链的位置,以便链可以有序地进行下去,那么在这个方法中并没有我们之前设想的维护各种增强的顺序,而是将此工作委托给了各个增强器,使各个增强器在内部进行逻辑实现。

  • 相关阅读:
    【一句日历】2020年4月
    【2020-03-31】思维永远只有一种
    【2020-03-30】事情就怕太容易而看不起
    【2020-03-29】人生有趣的地方在于不断升级自己
    【2020-03-27】球场还在,换了地方而已
    【2020-03-26】人其实是一个系统
    【2020-03-25】没工作是个伪命题
    day 74 vue 2 axios数据请求 以及组件的学习
    day 73 初学vue (1)
    day 72 crm(9) 客户关系系统,整体实现,以及自定制路由内容,客户关系梳理
  • 原文地址:https://www.cnblogs.com/wade-luffy/p/6077414.html
Copyright © 2011-2022 走看看