zoukankan      html  css  js  c++  java
  • spring aop 源码解读之我见

    spring aop 都是动态代理,分为jdk代理和cglib代理。默认的情况下,如果类有实现了接口,使用jdk代理。如果没有实现接口,则使用cglib代理。在下面的代码中,我会标明对应的这段代码。

    和以前一样,关键代码我会标红色。

    首先,分析jdk代理。之前一直找不到jdk代理的源码入口。后来网上看大神的源码分析,在结合自己写的例子,终于是发现了入口,入口的关键点,是InvocationHandler。由于jdk代理也实现了这个接口,所以也实现了自己的invoke方法。代码如下:

    /**
         * Implementation of {@code InvocationHandler.invoke}.
         * <p>Callers will see exactly the exception thrown by the target,
         * unless a hook method throws an exception.
         */
        @Override
        @Nullable
    //实现invoke方法。
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; 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方法
    return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself.
                    //不实现hasCode方法                
    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...

    //使用代理配置对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. 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.
    // 允许直接执行目标类,而不创建方法调用invocation。注意,最终的调用者依然是InvokerInterceptor,尽管只是直接反射操作,没有任何的拦截。
    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); } } }

     先跟进 getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

    /**
         * 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 a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
         */
    //基于方法的配置,获取它的拦截器 集合。这里可以看出,拦截器 集合是一个list,放在map中,map的key则是方法名称和hascode组成
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { 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; }
    @Override
        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
                Advised config, Method method, @Nullable Class<?> targetClass) {
    
            // This is somewhat tricky... We have to process introductions first,
            // but we need to preserve order in the ultimate list.
            List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
            Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
            boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);        //检查是否有匹配配置的类
            AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    
            for (Advisor advisor : config.getAdvisors()) {          //遍历advisor
                if (advisor instanceof PointcutAdvisor) {            //如果是切入点的的advisor(方法级别)
                    // Add it conditionally.
                    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                    if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {     //检查经过过滤的类是否还匹配advisor
                        MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();     
                        if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {    //检查匹配的方法 
                            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);    //获取方法拦截器
                            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 {
                                interceptorList.addAll(Arrays.asList(interceptors));       //如果不是运行时起作业给作用的拦截器,则直接添加到拦截器链中
                            } 
                        }
                    }
                }
                else if (advisor instanceof IntroductionAdvisor) {     //类级别的拦截器
                    IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                    if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                        Interceptor[] interceptors = registry.getInterceptors(advisor);
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
                else {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
    
            return interceptorList;
        }

    下面看下:invocation.proceed() 。这个方法真正地使拦截器起作用。代码如下:

    @Override
        @Nullable
        public Object proceed() throws Throwable {
            //    We start with an index of -1 and increment early.
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return invokeJoinpoint();
            }
    
            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.
                return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
            }
        }
     //orgspringframeworkaopframeworkReflectiveMethodInvocation.class
    public Object proceed() throws Throwable { if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { //如果是自后一个匹配的拦截器,则直接调用 return this.invokeJoinpoint(); //可以看出,这里有反射和cglig两种实现方法,也就是,对应jdk和cglib } else { Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { //如果是匹配的拦截器&方法 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice; return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed(); //如果类的方法完全匹配,则直接执行,否则执行回调 } else { return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this); } } }

    jdk和cglib其实都是一样的意思,简单看下cglib的invokeJoinPoint()

    protected Object invokeJoinpoint() throws Throwable {
                return this.publicMethod ? this.methodProxy.invoke(this.target, this.arguments) : super.invokeJoinpoint();
            }
    public Object invoke(Object obj, Object[] args) throws Throwable {
            try {
                this.init();
                MethodProxy.FastClassInfo fci = this.fastClassInfo;
                return fci.f1.invoke(fci.i1, obj, args);
            } catch (InvocationTargetException var4) {
                throw var4.getTargetException();
            } catch (IllegalArgumentException var5) {
                if (this.fastClassInfo.i1 < 0) {
                    throw new IllegalArgumentException("Protected method: " + this.sig1);
                } else {
                    throw var5;
                }
            }
        }

    在这里看到 fci.f1.invoke(fci.i1, obj, args)。也就是我们的拦截器织入的方法执行。这里又个有意义的现象,就是使用fci.f1.invoke ,这中fastclass的方式来执行,之所以使用这种方式,是因为cglib生成动态代理的子类的时候,已经为每一个方法增加了一个独一无二的索引,有了索引之后,这样执行会比直接调用快,具体的可以去百度下。

    -------------------------------------------------------------------------------------------------

    总结:spring aop的执行流程,分为两步:1、生成拦截器链  2、切入点(方法)织入代码,进行拦截

  • 相关阅读:
    hdu_5718_Oracle(大数模拟)
    hdu_2222_Keywords Search(AC自动机板子)
    hdu_5616_Jam's balance(暴力枚举子集||母函数)
    hdu_2255_奔小康赚大钱(KM带权二分匹配板子)
    hdu_2544_最短路(spfa版子)
    hdu_2457_DNA repair(AC自动机+DP)
    hdu_5555_Immortality of Frog(状压DP)
    hdu_2159_FATE(完全背包)
    [USACO2002][poj1944]Fiber Communications(枚举)
    [AHOI2013]打地鼠(网络流)
  • 原文地址:https://www.cnblogs.com/drafire/p/9637349.html
Copyright © 2011-2022 走看看