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

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