0x09.動(dòng)態(tài)代理和Spring AOP原理簡(jiǎn)介

[TOC]

動(dòng)態(tài)代理

JDK的動(dòng)態(tài)代理是通過實(shí)現(xiàn)目標(biāo)類的接口來創(chuàng)建代理類,借助里式替換原則通過聚合目標(biāo)類,在接口方法內(nèi)部委托目標(biāo)類的接口方法來達(dá)到控制對(duì)目標(biāo)方法的訪問的目的。

CGLIB則是通過繼承來實(shí)現(xiàn)代理,具體邏輯是繼承目標(biāo)類創(chuàng)建一個(gè)子類,然后重寫目標(biāo)方法,在內(nèi)部調(diào)用父類方法來達(dá)到代理的目的。

CGLIB示例

  • 目標(biāo)類:
public class MyClass {
    public void method() {
        System.out.println("MyClass.method()");
    }
}
  • Testcase
package aop.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class Main {

    @Test
    public void testCGLIB() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyClass.class);
        enhancer.setCallback(new MethodInterceptor() {

            @Override
            public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)
                                                                                 throws Throwable {
                System.out.println("before");
                System.out.println("method Name:" + method.getName());
                // 調(diào)用父類方法來完成實(shí)際業(yè)務(wù)邏輯
                proxy.invokeSuper(target, args);
                System.out.println("after");
                return null;
            }
        });
        MyClass my = (MyClass) enhancer.create();
        my.method();
    }

    
}

JDK動(dòng)態(tài)代理示例

  • 實(shí)現(xiàn)接口的目標(biāo)類
public interface MyInterface {
    void method();

}

public class MyClassWithInterface implements MyInterface {
    @Override
    public void method() {
        System.out.println("MyClassWithInterface.method()");
    }
}

  • TestCase
    @Test
    public void testJDKProxy() {
        final MyClassWithInterface target = new MyClassWithInterface();
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("before");
                        // 實(shí)際的業(yè)務(wù)邏輯還是委托給目標(biāo)類的
                        method.invoke(target, args);
                        System.out.println("after");
                        return null;
                    }
                });
        proxy.method();
    }

Spring AOP

Spring AOP是基于動(dòng)態(tài)代理的,代理方式包括以上兩種,所以只能攔截方法,且不能攔截未實(shí)現(xiàn)接口的final class。

AOP生成代理的入口

在Spring中,bean的創(chuàng)建是交給IOC容器的,從上面動(dòng)態(tài)代理的使用來看,基于接口的JDK代理的代理對(duì)象的生成是需要持有目標(biāo)對(duì)象的。AOP是基于BeanPostProcessor在createBean邏輯中的回調(diào),涉及的主要后處理器為org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator,調(diào)用時(shí)機(jī)是在目標(biāo)bean實(shí)例化之后,執(zhí)行initializeBean()初始化內(nèi)部中執(zhí)行postProcessAfterInitialization()回調(diào)。

調(diào)用棧為:doCreateBean()->initializeBean()->applyBeanPostProcessorsAfterInitialization()->org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization()->wrapIfNecessary()->createProxy.

  • wrapIfNecessary

開啟了AOP自動(dòng)代理之后,所有bean的創(chuàng)建都會(huì)進(jìn)入這一步判斷是否需要wrap,因?yàn)锽eanPostProcessor是全局的。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // Create proxy if we have advice. // 判斷當(dāng)前的Bean是否有相關(guān)的切面
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 有就創(chuàng)建代理對(duì)象并返回
            Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

判斷Bean是否需要代理

是否需要代理的的依據(jù)就是wrapIfNecessary方法中的getAdvicesAndAdvisorsForBean(),通過檢查本bean是否有關(guān)聯(lián)切面來判斷是否需要代理。判斷切面關(guān)聯(lián)的邏輯:

    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

重點(diǎn)在于查找和當(dāng)前bean相關(guān)的aspect,如何查找的?

    protected List<Advisor> findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        // 內(nèi)部邏輯是檢查所有注冊(cè)的Aspect bean,取到其中的Advice定義,封裝到Advisor中(InstantiationModelAwarePointcutAdvisor)
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }

findCandidateAdvisors返回所有備選的advisor,下一步進(jìn)行篩選:findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName),最后進(jìn)行其他處理,返回合格的advisor,繼續(xù)下一步的代理創(chuàng)建。

生成代理

代理對(duì)象的生成入口Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));,詳細(xì)生成過程是通過ProxyFactory工廠對(duì)象生成。

protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);
        }

        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }

        return proxyFactory.getProxy(getProxyClassLoader());
    }

    public Object getProxy(ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }

    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);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

具體的生成策略有兩種:JdkDynamicAopProxyObjenesisCglibAopProxy,就是前述的兩種動(dòng)態(tài)代理方式。

  • cglib
public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB 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 (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            // Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass, classLoader);

            // 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.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));

            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        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);
        }
    }
  • jdk
    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);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.1 Spring IoC容器和bean簡(jiǎn)介 本章介紹了Spring Framework實(shí)現(xiàn)的控制反轉(zhuǎn)(IoC)...
    起名真是難閱讀 2,671評(píng)論 0 8
  • 1.1 spring IoC容器和beans的簡(jiǎn)介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,851評(píng)論 2 22
  • 本博中關(guān)于spring的文章:Spring IOC和AOP原理,Spring事務(wù)原理探究,Spring配置文件屬性...
    Maggie編程去閱讀 4,201評(píng)論 0 34
  • 前言 只有光頭才能變強(qiáng) 上一篇已經(jīng)講解了Spring IOC知識(shí)點(diǎn)一網(wǎng)打盡!,這篇主要是講解Spring的AOP模...
    Java3y閱讀 7,023評(píng)論 8 181
  • 樹上的童話 夢(mèng)想他不假 可是會(huì)受傷 所以才害怕; 背著重重殼 抬頭仰望他; 樹上的童話 一點(diǎn)也不假 只是很美麗。 ...
    南子閱讀 356評(píng)論 0 0

友情鏈接更多精彩內(nèi)容