• spring aop源码实现分析


    1. 先分析Advice

    before执行Cglib2AopProxy的intercept方法:

    /**
         * General purpose AOP callback. Used when the target is dynamic or when the
         * proxy is not frozen.
         */
        private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
    
            private AdvisedSupport advised;
    
            public DynamicAdvisedInterceptor(AdvisedSupport advised) {
                this.advised = advised;
            }
    
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                MethodInvocation invocation = null;
                Object oldProxy = null;
                boolean setProxyContext = false;
                Class targetClass = null;
                Object target = null;
                try {
                    Object retVal = null;
                    if (this.advised.exposeProxy) {
                        // Make invocation available if necessary.
                        oldProxy = AopContext.setCurrentProxy(proxy);
                        setProxyContext = true;
                    }
                    // May be <code>null</code>. Get as late as possible to minimize the time we
                    // "own" the target, in case it comes from a pool.
                    target = getTarget();
                    if (target != null) {
                        targetClass = target.getClass();
                    }
                    List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    // Check whether we only have one InvokerInterceptor: that is,
                    // no real advice, but just reflective invocation of the target.
                    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                        // 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 = methodProxy.invoke(target, args);
                    }
                    else {
                        // We need to create a method invocation...
                        invocation = new CglibMethodInvocation(proxy, target, method, args,
                                targetClass, chain, methodProxy);
                        // If we get here, we need to create a MethodInvocation.
                        retVal = invocation.proceed();
                    }
    
                    retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
                    return retVal;
                }
                finally {
                    if (target != null) {
                        releaseTarget(target);
                    }
                    if (setProxyContext) {
                        // Restore old proxy.
                        AopContext.setCurrentProxy(oldProxy);
                    }
                }
            }

    第一步:获取target  

    target.getClass();

    第二步:获取拦截器和advice,返回定义好的org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor示例

    /**
         * 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 getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
            MethodCacheKey cacheKey = new MethodCacheKey(method);
            List cached = (List) this.methodCache.get(cacheKey);
            if (cached == null) {
                cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                        this, method, targetClass);
                this.methodCache.put(cacheKey, cached);
            }
            return cached;
        }

    第三步创建一个方法的invocation

                        // We need to create a method invocation...
                        invocation = new CglibMethodInvocation(proxy, target, method, args,
                                targetClass, chain, methodProxy);

    第四步 执行aop的before方法

        public void before(Method method, Object[] args, Object target)
                throws Throwable {
            System.out.println(" Before method!");
        }

    第五步 触发MethodBeforeAdviceInterceptor的invoke方法

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

    第六步:触发ReflectiveMethodInvocation的process方法

        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);
            }
        }

    第七步,包装返回值Cglib2AopProxy

    /**
         * Wrap a return of this if necessary to be the proxy
         */
        private static Object massageReturnTypeIfNecessary(Object proxy, Object target, Method method, Object retVal) {
            // Massage return value if necessary
            if (retVal != null && retVal == target &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this".
                // Note that we can't help if the target sets a reference
                // to itself in another returned object.
                retVal = proxy;
            }
            return retVal;
        }

    最后执行finanly方法

    finally {
                    if (target != null) {
                        releaseTarget(target);
                    }
                    if (setProxyContext) {
                        // Restore old proxy.
                        AopContext.setCurrentProxy(oldProxy);
                    }

    before,after,around,throw基本相似,不一一赘述

    2.PointCut和Advisor为例

     2.1 创建代理的过程

    首先是ProxyFactoryBean获取对象代理

        /**
         * Return a proxy. Invoked when clients obtain beans from this factory bean.
         * Create an instance of the AOP proxy to be returned by this factory.
         * The instance will be cached for a singleton, and create on each call to
         * <code>getObject()</code> for a proxy.
         * @return a fresh AOP proxy reflecting the current state of this factory
         */
        public Object getObject() throws BeansException {
            initializeAdvisorChain();
            if (isSingleton()) {
                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.");
                }
                return newPrototypeInstance();
            }
        }

    获取过程如下:

        /**
         * 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
         */
        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.
                    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);
                this.singletonInstance = getProxy(createAopProxy());
            }
            return this.singletonInstance;
        } 

    父类创建代理的过程

        /**
         * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
         * create an AOP proxy with <code>this</code> as an argument.
         */
        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }

    调用代理工厂创建代理的过程

        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            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.");
                }
                if (targetClass.isInterface()) {
                    return new JdkDynamicAopProxy(config);
                }
                if (!cglibAvailable) {
                    throw new AopConfigException(
                            "Cannot proxy target class because CGLIB2 is not available. " +
                            "Add CGLIB to the class path or specify proxy interfaces.");
                }
                return CglibProxyFactory.createCglibProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }

    可以看出,代理的实现主要是jdk本身自带的动态代理和cglib提供的代理。

    2.2 获取代理的过程

    this.singletonInstance = getProxy(createAopProxy());

    Cglib2AopProxy类的Object getProxy(ClassLoader classLoader)

        public Object getProxy(ClassLoader classLoader) {
            if (logger.isDebugEnabled()) {
                logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.getTargetSource());
            }
    
            try {
                Class rootClass = this.advised.getTargetClass();
                Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
    
                Class proxySuperClass = rootClass;
                if (AopUtils.isCglibProxyClass(rootClass)) {
                    proxySuperClass = rootClass.getSuperclass();
                    Class[] additionalInterfaces = rootClass.getInterfaces();
                    for (int i = 0; i < additionalInterfaces.length; i++) {
                        Class additionalInterface = additionalInterfaces[i];
                        this.advised.addInterface(additionalInterface);
                    }
                }
    
                // Validate the class, writing log messages as necessary.
                validateClassIfNecessary(proxySuperClass);
    
                // Configure CGLIB Enhancer...
                Enhancer enhancer = createEnhancer();
                if (classLoader != null) {
                    enhancer.setClassLoader(classLoader);
                    if (classLoader instanceof SmartClassLoader &&
                            ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                        enhancer.setUseCache(false);
                    }
                }
                enhancer.setSuperclass(proxySuperClass);
                enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
                enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
                enhancer.setInterceptDuringConstruction(false);
    
                Callback[] callbacks = getCallbacks(rootClass);
                enhancer.setCallbacks(callbacks);
                enhancer.setCallbackFilter(new ProxyCallbackFilter(
                        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    
                Class[] types = new Class[callbacks.length];
                for (int x = 0; x < types.length; x++) {
                    types[x] = callbacks[x].getClass();
                }
                enhancer.setCallbackTypes(types);
    
                // Generate the proxy class and create a proxy instance.
                Object proxy;
                if (this.constructorArgs != null) {
                    proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
                }
                else {
                    proxy = enhancer.create();
                }
    
                return proxy;
            }
            catch (CodeGenerationException ex) {
                throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                        this.advised.getTargetClass() + "]: " +
                        "Common causes of this problem include using a final class or a non-visible class",
                        ex);
            }
            catch (IllegalArgumentException ex) {
                throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                        this.advised.getTargetClass() + "]: " +
                        "Common causes of this problem include using a final class or a non-visible class",
                        ex);
            }
            catch (Exception ex) {
                // TargetSource.getTarget() failed
                throw new AopConfigException("Unexpected AOP exception", ex);
            }
        }

    获取回调方法

        private Callback[] getCallbacks(Class rootClass) throws Exception {
            // Parameters used for optimisation choices...
            boolean exposeProxy = this.advised.isExposeProxy();
            boolean isFrozen = this.advised.isFrozen();
            boolean isStatic = this.advised.getTargetSource().isStatic();
    
            // Choose an "aop" interceptor (used for AOP calls).
            Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    
            // Choose a "straight to target" interceptor. (used for calls that are
            // unadvised but can return this). May be required to expose the proxy.
            Callback targetInterceptor = null;
    
            if (exposeProxy) {
                targetInterceptor = isStatic ?
                        (Callback) new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                        (Callback) new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
            }
            else {
                targetInterceptor = isStatic ?
                        (Callback) new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                        (Callback) new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
            }
    
            // Choose a "direct to target" dispatcher (used for
            // unadvised calls to static targets that cannot return this).
            Callback targetDispatcher = isStatic ?
                    (Callback) new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
    
            Callback[] mainCallbacks = new Callback[]{
                aopInterceptor, // for normal advice
                targetInterceptor, // invoke target without considering advice, if optimized
                new SerializableNoOp(), // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
            };
    
            Callback[] callbacks;
    
            // If the target is a static one and the advice chain is frozen,
            // then we can make some optimisations by sending the AOP calls
            // direct to the target using the fixed chain for that method.
            if (isStatic && isFrozen) {
                Method[] methods = rootClass.getMethods();
                Callback[] fixedCallbacks = new Callback[methods.length];
                this.fixedInterceptorMap = new HashMap(methods.length);
    
                // TODO: small memory optimisation here (can skip creation for
                // methods with no advice)
                for (int x = 0; x < methods.length; x++) {
                    List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                    fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                            chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                    this.fixedInterceptorMap.put(methods[x].toString(), new Integer(x));
                }
    
                // Now copy both the callbacks from mainCallbacks
                // and fixedCallbacks into the callbacks array.
                callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
    
                for (int x = 0; x < mainCallbacks.length; x++) {
                    callbacks[x] = mainCallbacks[x];
                }
    
                for (int x = 0; x < fixedCallbacks.length; x++) {
                    callbacks[x + mainCallbacks.length] = fixedCallbacks[x];
                }
    
                this.fixedInterceptorOffset = mainCallbacks.length;
            }
            else {
                callbacks = mainCallbacks;
            }
            return callbacks;
        }

    获取拦截器和动态拦截器Advice

        /**
         * 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 getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
            MethodCacheKey cacheKey = new MethodCacheKey(method);
            List cached = (List) this.methodCache.get(cacheKey);
            if (cached == null) {
                cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                        this, method, targetClass);
                this.methodCache.put(cacheKey, cached);
            }
            return cached;
        }

    继续调用DefaultAdvisorChainFactory:

    public List 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 interceptorList = new ArrayList(config.getAdvisors().length);
            boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
            AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
            Advisor[] advisors = config.getAdvisors();
            for (int i = 0; i < advisors.length; i++) {
                Advisor advisor = advisors[i];
                if (advisor instanceof PointcutAdvisor) {
                    // Add it conditionally.
                    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                    if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        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 (int j = 0; j < interceptors.length; j++) {
                                    interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j], mm));
                                }
                            }
                            else {
                                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;
        }

    NameMatchMethodPointcut

        public boolean matches(Method method, Class targetClass) {
            for (int i = 0; i < this.mappedNames.size(); i++) {
                String mappedName = (String) this.mappedNames.get(i);
                if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {
                    return true;
                }
            }
            return false;
        }
  • 相关阅读:
    atom那些事儿
    浙江省和杭州市
    Web API之indexedDB和Web SQL
    绝对定位元素居中
    多列等高布局
    git生成ssh key及github ssh key对接
    vuejs模板使用方法
    css3动画图片波纹效果
    sticky footer布局,定位底部footer
    css3圆环闪烁动画
  • 原文地址:https://www.cnblogs.com/davidwang456/p/5534090.html
Copyright © 2020-2023  润新知