Spring AOP實現原理筆記(一) -- 簡單介紹

一、動態代理技術

JDK動態代理只能對實現了接口的類生成代理,而不能針對類

CGLIB是針對類實現代理,利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理,覆蓋其中的方法(繼承)

1. JDK動態代理

定義一個接口及其實現類

public interface UserService {
    void add();
}
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("--------add--------");
    }
}

實現JDK提供的InvocationHandler

public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("------before------");
        Object result = method.invoke(target, args);
        System.out.println("------after------");
        return result;
    }
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}

測試代碼:

@Test
public void proxyTest() {
    UserService userService = new UserServiceImpl();
    MyInvocationHandler handler = new MyInvocationHandler(userService);
    UserService proxy = (UserService) handler.getProxy();
    proxy.add();
}

輸出

------before------
--------add--------
------after------

2. CGLib動態代理

例子如下:

public class EnhancerDemo {
  public static void main(String... args){
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(EnhancerDemo.class);
      enhancer.setCallback(new MethodInterceptorImpl());
      EnhancerDemo proxy = (EnhancerDemo) enhancer.create();
      proxy.test();
      System.out.println(proxy);
  }
  public void test(){
      System.out.println("hello world");
  }
  static class MethodInterceptorImpl implements MethodInterceptor{
      @Override
      public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)
              throws Throwable {
          System.out.println("----before invoke"+method);
          Object result = methodProxy.invokeSuper(o, args);
          System.out.println("****after invoke"+method);
          return result;
      }
  }
}

輸出:

----before invoke public void com.season.aop.EnhancerDemo.test()
hello world
****after invoke public void com.season.aop.EnhancerDemo.test()
----before invoke public java.lang.String java.lang.Object.toString()
----before invoke public native int java.lang.Object.hashCode()
****after invoke public native int java.lang.Object.hashCode()
****after invoke public java.lang.String java.lang.Object.toString()
com.season.aop.EnhancerDemo$$EnhancerByCGLIB$$b010a475@18e6db6
public interface Monitorable {
    void setMonitorActive(boolean active);
}

建一個類實現該接口並繼承DelegatingIntroductionInterceptor

public class MonitorInterceptor extends DelegatingIntroductionInterceptor implements Monitorable {
    ThreadLocal<Boolean> active = new ThreadLocal<>();
    @Override
    public void setMonitorActive(boolean active) {
        this.active.set(active);
    }
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object result;
        if (active.get() != null && active.get()) {
            System.out.println("開始計時");
            long start = System.currentTimeMillis();
            result = super.invoke(mi);
            System.out.println("計時結束,耗時:"+(System.currentTimeMillis()-start)+"ms");
        } else
            result = super.invoke(mi);
        return result;
    }
}

這個類做的事情是,當active中的值爲true時會在調用方法的時候進行計時統計

再建一個類模擬操作

    public class MonitorService {
        public void run(){
            try {
                System.out.println("執行MonitorService - run方法");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

在配置文件beans.xml中加上配置

<bean id="monitorService" class="com.season.aop.MonitorService"/>
<bean id="pMonitor" class="com.season.aop.MonitorInterceptor"/>
<bean id="myTestBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
      p:interceptorNames="pMonitor"
      p:proxyTargetClass="true"
      p:target-ref="monitorService"
      p:interfaces="com.season.aop.Monitorable"
/>

由於只能通過爲目標類創建子類的方式生成引介增強的代理,所以必須把proxyTargetClass設置爲true

測試代碼

@Test
   public void introduceInterceptorTest() {
       ApplicationContext actx = new ClassPathXmlApplicationContext("beans.xml");
       MonitorService bean = (MonitorService) actx.getBean("myTestBeanProxy");
       bean.run();
       ((Monitorable)bean).setMonitorActive(true);
       bean.run();
   }

輸出:

執行MonitorService - run方法
開始計時
執行MonitorService - run方法
計時結束,耗時:2000ms

三、定義一個切面

@Aspect
public class MyAspect {
    @Pointcut(value = "execution(* *.test(..))")
    public void test(){}
    @Before("test()")
    public void beforeTest(){
        System.out.println("test before");
    }
    @After("test()")
    public void afterTest(){
        System.out.println("test after");
    }
}

在beans.xml文件中加上

    <aop:aspectj-autoproxy/>
    <bean id="myAspect" class="com.season.MyAspect"/>

測試代碼

@Test
public void aspectTest() {
    ApplicationContext actx = new ClassPathXmlApplicationContext("beans.xml");
    MyTestBean bean = (MyTestBean) actx.getBean("myTestBean");
    bean.test();
}

輸出:

test before
Hello world
test after
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章