一步一步教你寫 SPRING AOP

源碼地址:
https://github.com/yixuaz/myspring
如看在開始前,你還不知道動態(tài)代理在JAVA里的2種實現(xiàn)方式,不知道BEAN POST PROCESSOR的作用。
請先看SPRING AOP 準備工作

我們開始吧。
首先同樣我們要定一個目標。
AOP 的XML 應該是什么樣的呢?

Step1. 在IOC 的XML 基礎上加上這3行, 構建代理接口,實現(xiàn)2種代理

<bean id="autoProxyCreator" class="com.myspring.aop.AspectJAwareAdvisorAutoProxyCreator"></bean>

    <bean id="timeInterceptor" class="com.myspring.aop.TimerInterceptor"></bean>

    <bean id="aspectjAspect" class="com.myspring.aop.AspectJExpressionPointcutAdvisor">
        <property name="advice" ref="timeInterceptor"></property>
        <property name="expression" value="execution(* com.myspring.*.*(..))"></property>
    </bean>

把該有的類創(chuàng)建出來。
現(xiàn)在XML 如下


image.png

這里的TIME INTERCEPTOR, 就是一個代理方法,也稱增強方法,它的作用就是讓被切到的方法,都做一個計時的增強。
為了方面我們需要引入2個AOP提供的接口。當然自己實現(xiàn)也是可以的。因為是接口。所以我們?yōu)榱送祽兄苯右?br> POM.XML 加上

<dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>2.2</version>
    </dependency>
<dependency>
          <groupId>aopalliance</groupId>
          <artifactId>aopalliance</artifactId>
          <version>1.0</version>
      </dependency>

這個類寫出來

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class TimerInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long time = System.nanoTime();
        System.out.println("Invocation of Method " + invocation.getMethod().getName() + " start!");
        Object proceed = invocation.proceed();
        System.out.println("Invocation of Method " + invocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time)
                + " nanoseconds.");
        return proceed;
    }
}

因為AOP需要代理所以我們定一個代理接口,因為代理有2種實現(xiàn),一種是JDK,一種是CGLIB。所以我們需要一個接口來屏幕底層實現(xiàn)。因為用戶不需要關心底層SPRING用了什么實現(xiàn)。

public interface AopProxy {
    Object getProxy();
}

下面在實現(xiàn)JDK的代理類前我們要思考,因為JDK的實現(xiàn)里,就是INVOKE里面,一個反射調用,在INVOKE方法位置做增強


image.png

我們寫AOP為了通用一點,我們應該用methodInterceptor這個接口表示增強方法。然后調用這個INVOKE方法。
那這個方法又是傳入一個METHOD INVOCATION,里面封裝了,這個增強方法要的一切參數(shù),不如我們先把這個實現(xiàn)類給寫掉。

public class ReflectiveMethodInvocation implements MethodInvocation {
    private Object target;

    private Method method;

    private Object[] args;

    public ReflectiveMethodInvocation(Object target, Method method, Object[] args) {
        this.target = target;
        this.method = method;
        this.args = args;
    }

    @Override
    public Method getMethod() {
        return method;
    }

    @Override
    public Object[] getArguments() {
        return args;
    }

    @Override
    public Object proceed() throws Throwable {
        return method.invoke(target, args);
    }

    @Override
    public Object getThis() {
        return target;
    }

    @Override
    public AccessibleObject getStaticPart() {
        return method;
    }
}

解決了INVOCATION的問題,下面看還缺什么
在取得代理對象的時候,我們需要一個TAR 的CLASS 還有 INTERFACES。


image.png

所以增強方法和要代理的元數(shù)據(jù),我們可以封裝在一起,作為一個類,傳入JDK動態(tài)代理PROXY里
這個類就叫AdvisedSupport

public class TargetSource {
    private Class targetClass;

    private Class[] interfaces;
    private Object target;

    public TargetSource(Object target, Class<?> targetClass,Class<?>[] interfaces) {
        this.target = target;
        this.targetClass = targetClass;
        this.interfaces = interfaces;
    }

    public Class getTargetClass() {
        return targetClass;
    }

    public Object getTarget() {
        return target;
    }

    public Class[] getInterfaces() {
        return interfaces;
    }
}
public class AdvisedSupport {
    MethodInterceptor methodInterceptor;
    TargetSource targetSource;

    public MethodInterceptor getMethodInterceptor() {
        return methodInterceptor;
    }

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    public TargetSource getTargetSource() {
        return targetSource;
    }

    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }
}

有了這個類之后,我們就可以把JDK PROXY寫掉了。

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
    AdvisedSupport advisedSupport;

    public JdkDynamicAopProxy(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    @Override
    public Object getProxy() {
        return Proxy.newProxyInstance(getClass().getClassLoader(),
                advisedSupport.getTargetSource().getInterfaces()}, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor();
        return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(), method, args));
    }
}

來做個簡單的測試
為了測試JDK,必須要有INTERFACE,我們就為HELLOWORLD,建一個接口

public interface HelloWorldService {

    void helloWorld();
}

測試

@Test
    public void testInterceptor() throws Exception {
        // --------- helloWorldService without AOP
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
        helloWorldService.helloWorld();

        // --------- helloWorldService with AOP
        // 1. 設置被代理對象(Joinpoint)
        AdvisedSupport advisedSupport = new AdvisedSupport();
        TargetSource targetSource = new TargetSource(helloWorldService,  helloWorldService.getClass(), helloWorldService.getClass().getInterfaces());
        advisedSupport.setTargetSource(targetSource);

        // 2. 設置攔截器(Advice)
        TimerInterceptor timerInterceptor = new TimerInterceptor();
        advisedSupport.setMethodInterceptor(timerInterceptor);

        // 3. 創(chuàng)建代理(Proxy)
        JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
        HelloWorldService helloWorldServiceProxy = (HelloWorldService) jdkDynamicAopProxy.getProxy();

        // 4. 基于AOP的調用
        helloWorldServiceProxy.helloWorld();

    }

測試成功:
output:Hello World!
Invocation of Method helloWorld start!
output:Hello World!
Invocation of Method helloWorld end! takes 89181 nanoseconds.

當前項目結構:


image.png

Step2 上述代碼解決了怎么代理增強的問題,我們下面要解決怎么切的問題

還記得XML里* com.myspring..(..) 嗎?
這個就是表示,切面的范圍。
對于“在哪切”這一問題的定義,我們又叫做“Pointcut”。Spring中關于Pointcut包含兩個角色:ClassFilter和MethodMatcher,分別是對類和方法做匹配。Pointcut有很多種定義方法,例如類名匹配、正則匹配等,但是應用比較廣泛的應該是和AspectJ表達式的方式。

根據(jù)上述定義,我們先寫一個POINTCUT 接口

public interface ClassFilter {
    boolean matches(Class targetClass);
}
public interface MethodMatcher {

    boolean matches(Method method, Class targetClass);
}
public interface Pointcut {

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();

}

我們有了切面的接口,下面是怎么切的定義,這就是ADVISE()
在AOP里有環(huán)繞通知,前置通知,后置通知,異常通知,返回通知等。
定義一個獲取通知類型的接口

import org.aopalliance.aop.Advice;//這里偷懶

public interface Advisor {
    Advice getAdvice();
}

再來一個接口去獲取切面和通知的的

public interface PointcutAdvisor extends Advisor{

   Pointcut getPointcut();
}

接口全部定義好啦!

Step3 實現(xiàn)切面

首先把三個接口都實現(xiàn)下。
隨后對于這個類來說,我們肯定會拿到一個ASPECJ表達式。所以這個表達式,要注入進來的。加一個expression 變量。
隨后,我們要解析這個表達式,需要用到AOP里的PARSER了。
最后匹配方法的時候,要么全MATCH 就OK,其他都返回FALSE。
這個類的大多數(shù)代碼,都是參考著org.springframework.aop.aspectj.AspectJExpressionPointcut
來寫
然后做了簡化如下

public class AspectJExpressionPointcut implements PointCut,ClassFilter,MethodMatcher {

    private String expression;
    private PointcutParser pointCutParser;
    private PointcutExpression pointcutExpression;

    public AspectJExpressionPointcut() {
        pointCutParser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
    }

    public String getExpression() {
        return expression;
    }

    public void setExpression(String expression) {
        this.expression = expression;
    }

    @Override
    public boolean matches(Class targetClass) {
        checkReady();
        return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    }
    
    private void checkReady() {
        if(pointcutExpression == null)
            pointcutExpression = pointCutParser.parsePointcutExpression(expression);
    }

    @Override
    public boolean matches(Method method, Class targetClass) {
        checkReady();
        ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
        if (shadowMatch.alwaysMatches()) {
            return true;
        }
        return false;
    }

    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }
}

然后實現(xiàn)下AspectJExpressionPointcutAdvisor
這個類,主要就是對外提供ADVICE,和我們前面實現(xiàn)好的POINTCUT

public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {
    private AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();

    private Advice advice;

    public void setAdvice(Advice advice) {
        this.advice = advice;
    }

    public void setExpression(String expression) {
        this.pointcut.setExpression(expression);
    }


    @Override
    public PointCut getPointCut() {
        return pointcut;
    }

    @Override
    public Advice getAdvice() {
        return advice;
    }
}

下面測試,
當然你可以學一下ASPECTJ EXPRESION,寫出更多表達式來測試。
http://sishuok.com/forum/posts/list/281.html

image.png

Step4 實現(xiàn)融入Bean的創(chuàng)建過程,實現(xiàn)自己的BEAN POST PROCESSOR邏輯

現(xiàn)在我們有了Pointcut和Weave技術,一個AOP已經(jīng)算是完成了,但是它還沒有結合到Spring中去。怎么進行結合呢?Spring給了一個巧妙的答案:使用BeanPostProcessor。

BeanPostProcessor是BeanFactory提供的,在Bean初始化過程中進行擴展的接口。只要你的Bean實現(xiàn)了BeanPostProcessor接口,那么Spring在初始化時,會優(yōu)先找到它們,并且在Bean的初始化過程中,調用這個接口,從而實現(xiàn)對BeanFactory核心無侵入的擴展。

那么我們的AOP是怎么實現(xiàn)的呢?我們知道,在AOP的xml配置中,我們會寫這樣一句話:

<aop:aspectj-autoproxy/>
它其實相當于:

<bean id="autoProxyCreator" class="org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator"></bean>

AspectJAwareAdvisorAutoProxyCreator就是AspectJ方式實現(xiàn)織入的核心。它其實是一個BeanPostProcessor。在這里它會掃描所有Pointcut,并對bean做織入。

先定義出BEAN POST PROCESSOR 這個接口

public interface BeanPostProcessor {

    Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception;

    Object postProcessAfterInitialization(Object bean, String beanName) throws Exception;

}

隨后根據(jù)我們上篇文章的分析,在實例化BEAN前,要把這個PROCESSOR給注冊上去。
所以我們找到AbstractApplicationContext 的 refresh方法 開始加上一步

隨后我們要在BEAN FACTORY 里維護所有的BEAN POST PROCESSOR

隨后在BEAN 完成doCreateBean() 后 ,還需要做一個initializeBean()

更新后的BEAN FACTORY
1。實現(xiàn)2個新方法
第一個方法是為了提前找到并且初始化一些特定CLASS TYPE的BEAN
第二個就是維護所有的BEAN POST PROCESSOR 的BEAN

public List getBeansForType(Class<?> type) throws Exception {
        List beans = new ArrayList<Object>();
        for (String beanDefinitionName : beanDefinitionMap.keySet()) {
            if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
                beans.add(getBean(beanDefinitionName));
            }
        }
        return beans;
    }

    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        beanPostProcessors.add(beanPostProcessor);
    }

隨后
修改這邊

@Override
    public Object getBean(String beanName) throws Exception {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition == null)
            throw new IllegalArgumentException("No bean named " + beanName + " is defined");

        Object bean = beanDefinition.getBean();
        if(bean == null){
            bean = doCreateBean(bean,beanDefinition);
            bean = initializeBean(bean, beanName);
            beanDefinition.setBean(bean);
        }


        return bean;
    }

    private Object initializeBean(Object bean, String beanName) throws Exception {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
        }

        // TODO:call initialize method
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
        }
        return bean;
    }

完整代碼

public abstract class AbstractBeanFactory implements BeanFactory {
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    private List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

    @Override
    public Object getBean(String beanName) throws Exception {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition == null)
            throw new IllegalArgumentException("No bean named " + beanName + " is defined");

        Object bean = beanDefinition.getBean();
        if(bean == null){
            bean = doCreateBean(bean,beanDefinition);
            bean = initializeBean(bean, beanName);
            beanDefinition.setBean(bean);
        }


        return bean;
    }

    private Object initializeBean(Object bean, String beanName) throws Exception {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
        }

        // TODO:call initialize method
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
        }
        return bean;
    }

    protected abstract  Object doCreateBean(Object bean, BeanDefinition beanDefinition) throws Exception;

    public void preInstantiateSingletons() throws Exception {
        for(String name : beanDefinitionMap.keySet())
            getBean(name);
    }

    public void registerBeanDefinition(String key, BeanDefinition value) {
        beanDefinitionMap.put(key, value);
    }


    public List getBeansForType(Class<?> type) throws Exception {
        List beans = new ArrayList<Object>();
        for (String beanDefinitionName : beanDefinitionMap.keySet()) {
            if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
                beans.add(getBean(beanDefinitionName));
            }
        }
        return beans;
    }

    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        beanPostProcessors.add(beanPostProcessor);
    }
}

增加ABSTRACT APPLICATION CONTEXT 邏輯

public abstract class AbstractApplicationContext implements  ApplicationContext {
    protected AbstractBeanFactory beanFactory;

    public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
    
    public void refresh() throws  Exception {
        loadBeanDefinitions();
        registerBeanPostProcessors(beanFactory); // new added
        finishBeanFactoryInitialization();
    }

    private void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception {
        List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class);
        for (Object beanPostProcessor : beanPostProcessors) {
            beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor);
        }
    }

    protected void finishBeanFactoryInitialization() throws Exception {
        beanFactory.preInstantiateSingletons();
    }

    protected abstract void loadBeanDefinitions() throws Exception;

    @Override
    public Object getBean(String beanName) throws Exception {
        return beanFactory.getBean(beanName);
    }
}

Step5 開始實現(xiàn)一開始新建出來一直沒實現(xiàn)的BEAN AspectJAwareAdvisorAutoProxyCreator

在實現(xiàn)前,我們再理一下整個流程。

  1. AutoProxyCreator(實現(xiàn)了 BeanPostProcessor 接口)在實例化所有的 Bean 前,最先被實例化。因為registerBeanPostProcessor 在 finishInitiliazingBean 之前。

2.這個時候,他被BEAN FACTORY 通過getBeansForType 找到,并且調用了getBean(beanDefinitionName),最先實例化。

3.隨后在getBEAN實例化的時候,他會先doCreateBean,這個時候,他就應該把BEAN FACTORY 給注冊進去。因為之后要做postProcessAfterInitialization,來找到所有的切面我們需要用到BEAN FACTORY。
為了實現(xiàn)這個效果。我們搞一個接口出來。

public interface BeanFactoryAware {
    public void setBeanFactory(BeanFactory beanFactory);
}

讓AutoProxyCreator實現(xiàn)一下。
隨后在doCreateBean 的 applyProPertyValues,注入BEAN FACTORY。
代碼如下

 private void applyProPertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
        if(bean instanceof BeanFactoryAware){
            ((BeanFactoryAware) bean).setBeanFactory(this);
        }
        PropertyValues propertyValues = beanDefinition.getPropertyValues();
....

隨后要實現(xiàn)BeanPostProcessor 的2個方法。
我們在后置處理器里實現(xiàn)的效果應該是,找到所有‘切面通知BEAN’(實現(xiàn)了這個AspectJExpressionPointcutAdvisor )或者‘’增強方法BEAN’(實現(xiàn)了這個MethodInterceptor),隨后依次加載他們。因為他們不要被代理,所以直接RETURN。

@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
        if (bean instanceof AspectJExpressionPointcutAdvisor) {
            return bean;
        }
        if (bean instanceof MethodInterceptor) {
            return bean;
        }
        List<AspectJExpressionPointcutAdvisor> advisors = beanFactory
                .getBeansForType(AspectJExpressionPointcutAdvisor.class);
...
  1. 其他普通 Bean 被實例化、初始化,在初始化的過程中,AutoProxyCreator 加載 BeanFactory 中所有的 PointcutAdvisor(這也保證了 PointcutAdvisor 的實例化順序優(yōu)于普通 Bean。),然后依次使用 PointcutAdvisor 內(nèi)置的 ClassFilter,判斷當前對象是不是要攔截的類。

  2. 如果是,則生成一個 TargetSource(要攔截的對象和其類型),并取出 AutoProxyCreator 的 MethodMatcher(對哪些方法進行攔截)、Advice(攔截的具體操作),再,交給 AopProxy 去生成代理對象。

//繼續(xù)上面的代碼
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            if (advisor.getPointCut().getClassFilter().matches(bean.getClass())) {
                AdvisedSupport advisedSupport = new AdvisedSupport();
                advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
                advisedSupport.setMethodMatcher(advisor.getPointCut().getMethodMatcher());
//這里往AdvisedSupport  多加個MethodMatcher屬性
                TargetSource targetSource = new TargetSource(bean, bean.getClass(),bean.getClass().getInterfaces());
                advisedSupport.setTargetSource(targetSource);

                return new JdkDynamicAopProxy(advisedSupport).getProxy();
            }
        }
        return bean;
}
  1. AopProxy 生成一個 InvocationHandler,在它的 invoke 函數(shù)中,首先使用 MethodMatcher 判斷是不是要攔截的方法,如果是則交給 Advice 來執(zhí)行(Advice 由用戶來編寫,其中也要手動/自動調用原始對象的方法),如果不是,則直接交給 TargetSource 的原始對象來執(zhí)行。

修改JDKDynamicProxy代碼

 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor();
        if (advisedSupport.getMethodMatcher() != null
                && advisedSupport.getMethodMatcher().matches(method, advisedSupport.getTargetSource().getTarget().getClass())) {
            return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(),
                    method, args));
        } else {
            return method.invoke(advisedSupport.getTargetSource().getTarget(), args);
        }
    }

總結:

BeanPostProcessor :在 postProcessorAfterInitialization 方法中,使用動態(tài)代理的方式,返回一個對象的代理對象。解決了 在 IoC 容器的何處植入 AOP 的問題。
BeanFactoryAware :這個接口提供了對 BeanFactory 的感知,這樣,盡管它是容器中的一個 Bean,卻可以獲取容器的引用,進而獲取容器中所有的切點對象,決定對哪些對象的哪些方法進行代理。解決了 為哪些對象提供 AOP 的植入 的問題。

打開XML的AOP的注釋
開始測試
出錯了

java.lang.IllegalArgumentException: Can not set com.myspring.OutputService field com.myspring.HelloWorldServiceImpl.outputService to com.sun.proxy.$Proxy2

    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
    at java.lang.reflect.Field.set(Field.java:758)
    at com.myspring.context.AutowireCapableBeanFactory.applyProPertyValues(AutowireCapableBeanFactory.java:40)
    at com.myspring.context.AutowireCapableBeanFactory.doCreateBean(AutowireCapableBeanFactory.java:13)
    at com.myspring.context.AbstractBeanFactory.getBean(AbstractBeanFactory.java:24)
    at com.myspring.context.AbstractBeanFactory.preInstantiateSingletons(AbstractBeanFactory.java:49)
    at com.myspring.context.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:28)
    at com.myspring.context.AbstractApplicationContext.refresh(AbstractApplicationContext.java:17)
    at com.myspring.context.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:19)
    at com.myspring.context.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:13)
    at test.HelloWorldServiceImplTest.helloWorld(HelloWorldServiceImplTest.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

猜測是JDK 動態(tài)代理沒法代理非接口的OutputService

所以把這個改成接口,成功了。


image.png

Step6 我們不要接口,用CGLIB 來代理實現(xiàn)下吧

用一個代理工廠來智能選擇代理

public interface AopProxy {

    Object getProxy();
}

代理工廠,如果一個代理類有接口 就用JDK動態(tài)代理。否則就用CGLIB動態(tài)代理。

public class ProxyFactory extends AdvisedSupport implements AopProxy {
    @Override
    public Object getProxy() {
        return createAopProxy().getProxy();
    }

    protected final AopProxy createAopProxy() {
        if(getTargetSource().getInterfaces() == null || getTargetSource().getInterfaces().length == 0)
            return new Cglib2AopProxy(this);
        return new JdkDynamicAopProxy(this);
    }
}

根據(jù)上一章的知識,這邊不難看懂。

public class Cglib2AopProxy implements AopProxy {

    AdvisedSupport advised;

    public Cglib2AopProxy(AdvisedSupport advised) {

        this.advised = advised;
    }

    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(advised.getTargetSource().getTargetClass());
        enhancer.setInterfaces(advised.getTargetSource().getInterfaces());
        enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
        Object enhanced = enhancer.create();
        return enhanced;
    }

    private static class DynamicAdvisedInterceptor implements MethodInterceptor {

        private AdvisedSupport advised;

        private org.aopalliance.intercept.MethodInterceptor delegateMethodInterceptor;

        private DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
            this.delegateMethodInterceptor = advised.getMethodInterceptor();
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            if (advised.getMethodMatcher() == null
                    || advised.getMethodMatcher().matches(method, advised.getTargetSource().getTargetClass())) {
                return delegateMethodInterceptor.invoke(new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy));
            }
            return new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy).proceed();
        }
    }

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

        private final MethodProxy methodProxy;

        public CglibMethodInvocation(Object target, Method method, Object[] args, MethodProxy methodProxy) {
            super(target, method, args);
            this.methodProxy = methodProxy;
        }

        @Override
        public Object proceed() throws Throwable {
            return this.methodProxy.invoke(this.getThis(), this.getArguments());
        }
    }

}

最后修改AspectJAwareAdvisorAutoProxyCreator的這里

for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            if (advisor.getPointCut().getClassFilter().matches(bean.getClass())) {
                ProxyFactory advisedSupport = new ProxyFactory();
                advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
                advisedSupport.setMethodMatcher(advisor.getPointCut().getMethodMatcher());

                TargetSource targetSource = new TargetSource(bean, bean.getClass(),bean.getClass().getInterfaces());
                advisedSupport.setTargetSource(targetSource);

                return advisedSupport.getProxy();
            }
        }
        return bean;

去掉OUTPUTSERVICE 這個接口
測試成功,OUTPUT SERVICE 由CGLIB 動態(tài)代理
HELLO WORLD SERVICE 由JDK動態(tài)代理


image.png
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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