Spring Aop基礎: 動態代理

重要概念:

通知(advice)

用來定義切面方法(如:日誌方法;事務方法;加密解密方法等)調用時機。

  • 前置通知:@Before 目標方法調用前執行
  • 後置通知: @After 目標方法返回或拋出異常後調用
  • 返回通知: @AfterReturning 目標方法返回後調用
  • 異常通知: @AfterThrowing 目標方法拋出異常後調用
  • 環繞通知: @Around 目標方法封裝起來(方法前後都調用)
連接點(joinpoint)

目標對象的方法。目標對象需要插入通知方法的方法

切面(aspect)

包含切點和通知方法的類

切點(pointcut)

定義切面和連接點,連接規則

織入(wave)

是把切面應用到目標對象並創建新的代理對象的過程。 切面在指定的連接點被織入到目標對象中。在目標對象的生命週期裏有多個點可以織入:

  • 編譯器:切面在目標類編譯期被織入。
  • 類加載期:切面在目標類被類加載器加載到JVM時被織入。
  • 運行期:切面在應用運行的某個時刻被織入。 一般情況下,在織入切面時,AOP容器會爲目標對象動態的創建一個代理對象。SpringAOP就是以這種方式織入切面的。 如下圖所示:

在這裏插入圖片描述

Understanding Dynamic Proxy : Spring AOP Basics

Proxy Pattern:

We can create a proxy of the object , which will take care of the cross cutting concern code.There are two kind of proxy patterns :

  • Static Proxy :

Where we create a proxy object for every class. This is not feasible and practical

  • Dynamic Proxy :

In this , proxies are created dynamically through reflection . This functionality is added from JDK 1.3 . dynamic Proxy form the basic building block of Spring AOP

package com.somaniab.blog.ex;

public interface Basicfunc{

 public void method1();       
 
}
package com.somaniab.blog.ex;

public class Example1 implements Basicfunc{

 @Override
 public void method1() {
  System.out.println("executing method 1");  
 }
     
}

Now if we want to calculate execution time of method1 , we have to write that code in method itself , or we can create a proxy object. For creating proxy object , we create a Invocationhandler like this :

package com.somaniab.blog.ex;

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

public class MyInvocationHandler implements InvocationHandler{

 private Object target ;
  
        public MyInvocationHandler(Object target)
 {
  this.target = target;
 }
 
 
 public Object getTarget() {
  return target;
 }

 public void setTarget(Object target) {
  this.target = target;
 }

 @Override
 public Object invoke(Object proxy, Method method, Object[] params)
   throws Throwable {
  long a = System.currentTimeMillis();
  Object result =method.invoke(target ,params);
  System.out.println("total time taken  "+
                         (System.currentTimeMillis()-a));
  return result;
 }

}

In this invocation handler , we call the actual method as well as calculate the time taken.Now , in main class we create the proxy object by using Proxy class.

package com.somaniab.blog.ex;

import java.lang.reflect.Proxy;

public class MainClass {
      public static void main(String[] args) {
  
       Example1 ex = new Example1();
       
       Basicfunc proxied =(Basicfunc)Proxy
                           .newProxyInstance(MainClass.class.getClassLoader(),
         ex.getClass().getInterfaces() ,new MyInvocationHandler(ex));
       proxied.method1();
 }
}

For creating Proxy we pass classloader[mostly the same classloader as origin class],interfaces,and the invocationHandler (pass the original target object in the invocation handler ). The original class must implement a interface ,only those method declared in interface get proxied and then we cast the proxy to the interface type .

If you get Exception like this : java.lang.ClassCastException: $Proxy0 cannot be cast to com.somaniab.blog.ex.Example1 , it means your target class does not implement the interface.

In CGLib Proxy , there is no necessity of declaring interface.
So , this is how we made sure that our Example class write code for only method1 and we kept execution time calculation code out of it.

it is a very basic example , but it is the basic of Spring AOP.

參考1
參考2

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