spring(五):AOP

AOP(Aspect Oriented Programming)

面向切面編程,是一種編程範式,提供從另外一個角度來考慮程序結構從而完善面向對象編程(OOP)。java

在進行OOP開發時,都是基於對組件(好比類)進行開發,而後對組件進行組合,OOP最大問題就是沒法解耦組件進行開發。spring

AOP爲開發者提供一種進行橫切關注點(好比日誌關注點橫切了支付關注點)分離並織入的機制,把橫切關注點分離,而後經過某種技術織入到系統中,從而無耦合的完成了咱們的功能。編程

橫切關注點可能包含不少,好比非業務的:日誌、事務處理、緩存、性能統計、權限控制等;還多是業務的:如某個業務組件橫切於多個模塊。數組

基本概念

  • 鏈接點(Jointpoint):表示須要在程序中插入橫切關注點的擴展點,鏈接點多是類初始化、方法執行、方法調用、字段調用或處理異常等,Spring只支持方法執行鏈接點;「在哪裏幹」
  • 切入點(Pointcut):選擇一組相關鏈接點的模式,便可以認爲鏈接點的集合,Spring默認使用AspectJ語法;「在哪裏乾的集合」;[ <aop:aspectj-autoproxy/> 開啓spring對@Aspectj的支持]
  • 通知(Advice):在鏈接點上執行的行爲;「幹什麼」
  • 引入/內部類型聲明(inter-type declaration):爲已有的類添加額外新的字段或方法,Spring容許引入新的接口(必須對應一個實現)到全部被代理對象(目標對象);「幹什麼(引入什麼)」
  • 切面(Aspect):橫切關注點的模塊化,好比日誌組件。能夠認爲是通知、引入和切入點的組合,在Spring中可使用Schema和@AspectJ方式進行組織實現;「在哪乾和幹什麼集合」
  • 目標對象(Target Object):須要被織入橫切關注點的對象,被代理對象;「對誰幹」
  • 織入(Weaving):織入是一個過程,是將切面應用到目標對象從而建立出AOP代理對象的過程,織入能夠在編譯期、類裝載期、運行期進行。
    • 編譯時織入,生成完整功能的Java字節碼,需特殊編譯器(AspectJ)
    • 類加載時織入,AspectJ、AspectWerkz
    • 運行時織入,動態代理。@EnableAspectJAutoProxy。[Spring採用運行時]
  • AOP代理(AOP Proxy):AOP框架使用代理模式建立的對象,從而實如今鏈接點處插入通知,就是經過代理來對目標對象應用切面

What-@Aspect緩存

Where-@Pointcutapp

When-@Advice(@Before、@After、@AfterReturning、@AfterThrowing、@Around)框架

在Spring中經過代理模式實現AOP,並經過攔截器模式以環繞鏈接點的攔截器鏈織入通知(即應用切面)jvm

通知類型

  • 前置通知(Before Advice):在切入點選擇的鏈接點處的方法以前執行的通知,該通知不影響正常程序執行流程(除非該通知拋出異常,該異常將中斷當前方法鏈的執行而返回)。
  • 後置通知(After Advice):在切入點選擇的鏈接點處的方法以後執行的通知,包括以下類型的後置通知:
    • 後置返回通知(After returning Advice):在切入點選擇的鏈接點處的方法正常執行完畢時執行的通知,必須是鏈接點處的方法沒拋出任何異常正常返回時才調用後置通知。
    • 後置異常通知(After throwing Advice): 在切入點選擇的鏈接點處的方法拋出異常返回時執行的通知,必須是鏈接點處的方法拋出任何異常返回時才調用異常通知。
    • 後置最終通知(After finally Advice): 在切入點選擇的鏈接點處的方法返回時執行的通知,無論拋沒拋出異常都執行,相似於Java中的finally塊。
  • 環繞通知(Around Advices):環繞着在切入點選擇的鏈接點處的方法所執行的通知,環繞通知能夠在方法調用以前和以後自定義任何行爲,而且能夠決定是否執行鏈接點處的方法、替換返回值、拋出異常等等。

通知順序

Spring中能夠經過在切面實現類上實現org.springframework.core.Ordered接口或使用Order註解來指定切面優先級。在多個切面中,Ordered.getValue()方法返回值(或者註解值)較小值的那個切面擁有較高優先級。ide

@Order(2)

動態代理

若是目標對象實現了接口,默認使用JDK,能夠強制用CGLIB;不然,採用CGLIB。模塊化

JDK動態代理

只能爲接口建立動態代理實例,而不能針對類。

使用java.lang.reflect.Proxy動態代理實現,經過調用目標類的getClass().getInterfaces()方法獲取目標對象的接口信息,並生成一個實現了代理接口的動態代理class,而後經過反射技術得到該class的構造函數,並利用構造函數生成實例,在調用具體方法前調用InvocationHandler處理。

在Proxy這個類當中首先實例化一個對象ProxyClassFactory,而後在get方法中調用了apply方法,完成對代理類的建立:

  • generateProxyClass經過反射收集字段和屬性而後生成字節
  • defineClass0 jvm內部完成對上述字節的load

CGLIB動態代理

主要是對指定的類生成一個子類,覆蓋其中的方法。(不能通知final方法)

利用asm開源包,採用字節碼技術,爲一個類建立子類,在子類中採用方法攔截(MethodInterceptor @override intercept()),攔截全部父類方法的調用,順勢織入橫切邏輯。

會產生兩次構造器調用,第一次是目標類的構造器調用,第二次是CGLIB生成的代理類的構造器調用。

設計分析

1 爲目標對象創建AopProxy代理對象

在依賴注入時,實例化bean後都會調用getObjectForBeanInstance方法,這裏就是處理FactoryBean的入口。

經過配置和調用ProxyFactoryBean來完成代理對象的建立。

配置通知器advisor、proxyFactoryBean(目標對象target、interceptorNames攔截器數組、目標對象接口數組)

// ProxyFactoryBean
    @Nullable
    public Object getObject() throws BeansException {
        // 對通知器鏈進行初始化
        // 通知器鏈封裝了一系列的攔截器(須要從配置中讀取)
        // 而後爲代理對象的生成作準備
        this.initializeAdvisorChain();
        // 區分兩種類型的Bean
        if (this.isSingleton()) {
            return this.getSingletonInstance();
        } else {
            ...
            return this.newPrototypeInstance();
        }
    }

    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        // 通知器鏈未初始化(初始化工做發生在應用第一次經過ProxyFactoryBean獲取代理對象的時候)
        if (!this.advisorChainInitialized) {
            if (!ObjectUtils.isEmpty(this.interceptorNames)) {
                ...
                String[] var1 = this.interceptorNames;
                int var2 = var1.length;
                for(int var3 = 0; var3 < var2; ++var3) {
                    String name = var1[var3];
                    ...
                    if (name.endsWith("*")) {
                        ...
                    } else {
                        Object advice;
                        if (!this.singleton && !this.beanFactory.isSingleton(name)) {
                            // Prototype類型
                            advice = new ProxyFactoryBean.PrototypePlaceholderAdvisor(name);
                        } else {
                            // singleton類型:經過getBean獲取通知器
                            advice = this.beanFactory.getBean(name);
                        }
                        // 將通知器加入攔截器鏈中
                        this.addAdvisorOnChainCreation(advice, name);
                    }
                }
            }

            this.advisorChainInitialized = true;
        }
    }

    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.targetSource = this.freshTargetSource();
            if (this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
                // 判斷須要代理的接口
                Class<?> targetClass = this.getTargetClass();
                ...
                // 設置代理對象調用接口
                this.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
            }

            super.setFrozen(this.freezeProxy);
            // createAopProxy:生成aop代理對象 ★調用父類的createAopProxy()
            // getProxy:<<AopProxy>>接口的兩種實現--JdkDynamicAopProxy、CglibAopProxy
            this.singletonInstance = this.getProxy(this.createAopProxy());
        }

        return this.singletonInstance;
    }

    private synchronized Object newPrototypeInstance() {
        ...
        ProxyCreatorSupport copy = new ProxyCreatorSupport(this.getAopProxyFactory());
        TargetSource targetSource = this.freshTargetSource();
        copy.copyConfigurationFrom(this, targetSource, this.freshAdvisorChain());
        if (this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
            // 和上面如出一轍的套路啊。。。
            Class<?> targetClass = targetSource.getTargetClass();
            if (targetClass != null) {
                copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
            }
        }
        ...
        // 而後經過<<AopProxy>>接口的兩種實現--JdkDynamicAopProxy、CglibAopProxy獲取代理對象
        return this.getProxy(copy.createAopProxy());
    }
// ProxyCreatorSupport
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            this.activate();
        }

        // createAopProxy:<<AopProxyFactory>>接口的方法
        return this.getAopProxyFactory().createAopProxy(this);
    }
// 具體實現:DefaultAopProxyFactory
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 若是目標對象是接口類,使用jdk
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                ...
            } else {
                // ObjenesisCglibAopProxy extends CglibAopProxy 
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
        // new的過程都是先從AdvisedSupport對象中取得配置的目標對象進行檢查
    }
// JdkDynamicAopProxy
    public Object getProxy(@Nullable ClassLoader classLoader) {
        ...
        // 首先從advised對象中獲取代理對象的代理接口配置
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        // 而後調用Proxy的newProxyInstance方法獲得Proxy代理對象
        // 須要三個參數:類加載器、代理接口、回調方法所在對象
        // 回調方法用的是InvokeHandler的invoke回調入口
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
// CglibAopProxy
    public Object getProxy(@Nullable ClassLoader classLoader) {
        ...
        try {
            // 從advised對象中獲取配置的target對象
            Class<?> rootClass = this.advised.getTargetClass();
            ...
            Class<?> proxySuperClass = rootClass;
            int x;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                Class[] var5 = additionalInterfaces;
                int var6 = additionalInterfaces.length;

                for(x = 0; x < var6; ++x) {
                    Class<?> additionalInterface = var5[x];
                    this.advised.addInterface(additionalInterface);
                }
            }
            // 驗證代理對象的接口設置
            this.validateClassIfNecessary(proxySuperClass, classLoader);
            // 建立並配置cglib的enhancer
            Enhancer enhancer = this.createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader && ((SmartClassLoader)classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            // 設置enhancer的代理接口、回調方法等
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new CglibAopProxy.ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
            Callback[] callbacks = this.getCallbacks(rootClass);
            Class<?>[] types = new Class[callbacks.length];

            for(x = 0; x < types.length; ++x) {
                types[x] = callbacks[x].getClass();
            }

            enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
            // 經過enhancer生成代理對象 ★
            // 注意這裏有回調
            return this.createProxyClassAndInstance(enhancer, callbacks);
        }...
    }

    // 這裏是回調方法,經過設置DynamicAdvisedInterceptor攔截器完成AOP功能
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        ...
        Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
        ...
        return callbacks;
    }

2 啓動代理對象的攔截器來完成各類橫切面的織入

在第一步的過程當中,攔截器已經配置到代理對象中,它是經過回調方法起做用。

JdkDynamicAopProxy的invoke攔截
@Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        Boolean var8;
        try {
            if (this.equalsDefined || !AopUtils.isEqualsMethod(method)) {
                ...
                // 獲得目標對象
                target = targetSource.getTarget();
                Class<?> targetClass = target != null ? target.getClass() : null;
                // 這個方法對象註冊了攔截器
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                // 沒有設定攔截器鏈,直接調用target對象的方法
                if (chain.isEmpty()) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    // 對target對象的方法調用是經過反射機制,而後使用invoke調用方法反射對象
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                } else {
                    // 攔截,經過ReflectiveMethodInvocation
                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    // 沿着攔截器鏈繼續前進
                    retVal = invocation.proceed();
                }
                ...
            }
            var8 = this.equals(args[0]);
        }...
        return var8;
    }
CglibAopProxy的DynamicAdvisedInterceptor的intercept攔截
@Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            ...
            try {
                ...
                // 獲得目標對象
                target = targetSource.getTarget();
                Class<?> targetClass = target != null ? target.getClass() : null;
                // 從advised取得配置好的AOP通知
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                // 若沒有,則直接調用target對象的方法
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                } else {
                    // 攔截,經過CglibMethodInvocation啓動advice通知
                    // CglibMethodInvocation extends ReflectiveMethodInvocation
                    // 沿着攔截器鏈繼續前進
                    retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
                }
                retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
                var16 = retVal;
            }...
            return var16;
        }

綜上,都是從advised取得攔截器鏈的。

攔截都是經過ReflectiveMethodInvocation的proceed方法實現的。

如何將攔截器鏈配置進advised的?

攔截器是ReflectiveMethodInvocation類中一個名爲interceptorsAndDynamicMethodMatchers的List中的元素。

this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

advised的getInterceptorsAndDynamicInterceptionAdvice是由advisorChainFactory實現的,它的具體類型是DefaultAdvisorChainFactory。

DefaultAdvisorChainFactory經過AdvisorAdapterRegistry來適配ProxyFactoryBean中獲得的通知器,註冊攔截器。

在ProxyFactoryBean的getObject方法中對advisor進行初始化時,從配置中獲取了通知器。(經過實現BeanFactoryAware接口,設置回調方法委託給IoC容器)

proceed方法
@Nullable
    public Object proceed() throws Throwable {
        // 若是已經到攔截器鏈的末尾,直接調用目標對象的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
            // 不然,獲得下一個攔截器
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            // 經過攔截器進行matches判斷是否適用於橫切加強的場合
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                // 若是是,從攔截器獲得通知器,並啓動invoke方法
                // 不然,迭代調用proceed方法
                return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }
advice通知是如何實現的?

DefaultAdvisorChainFactory經過AdvisorAdapterRegistry來適配ProxyFactoryBean中獲得的通知器,註冊攔截器。

// DefaultAdvisorChainFactory   
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
        // GlobalAdvisorAdapterRegistry是一個單例,做用是適配器
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        Advisor[] advisors = config.getAdvisors();
        ...

        for(int var11 = 0; var11 < var10; ++var11) {
            Advisor advisor = var9[var11];
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    ...
                    if (match) {
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        ...
                    }
                }
            } 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;
    }

MethodInterceptor[] interceptors = registry.getInterceptors(advisor);封裝着advice織入實現的入口。

// DefaultAdvisorAdapterRegistry
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor)advice);
        }
        // 對通知進行適配
        Iterator var4 = this.adapters.iterator();
        while(var4.hasNext()) {
            AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
            // 若是適配器支持某種通知,則從對應的適配器中獲取該類通知器的攔截器
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        ...
    }

咱們知道,proceed處理攔截器的時候是經過dm.interceptor.invoke(this)攔截器的回調方法。下面舉一個例子。

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    MethodBeforeAdviceAdapter() {
    }

    public boolean supportsAdvice(Advice advice) {
        return advice instanceof MethodBeforeAdvice;
    }

    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
}
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    // 先觸發advice的before,而後纔是proceed調用!
    // 由於這是method before!若是是其餘的攔截器,順序、具體實現又不同了
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
}
相關文章
相關標籤/搜索