spring AOP的代理机制

使用AOP实现日志的例子:
https://www.cnblogs.com/qlqwjy/p/8747476.html

AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强 !

AOP应用场景
场景一: 记录日志
场景二: 监控方法运行时间 (监控性能)
场景三: 权限控制
场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
场景五: 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 )

Spirng的AOP的动态代理实现机制有两种,分别是:

1)JDK动态代理:

具体实现原理:

1、通过实现InvocationHandlet接口创建自己的调用处理器

2、通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理

3、通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型

4、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入

JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,

Spring通过java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。

2、CGLib动态代理

CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。

两者对比:

JDK动态代理是面向接口,在创建代理实现类时比CGLib要快,创建代理速度快。

CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么抱歉会失败),在创建代理这一块没有JDK动态代理快,但是运行速度比JDK动态代理要快。

使用注意:

如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制)

如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

那么如何选择的使用代理机制了?

1.JDK动态代理 2.cglib代理

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

注:JDK动态代理要比cglib代理执行速度快,但性能不如cglib好。所以在选择用哪种代理还是要看具体情况,一般单例模式用cglib比较好,具体原因请自行百度。

一 JDK动态代理实现(原理是使用反射机制)
首先定义接口,并实现
1.引入依赖,有spring,单元测,日志管理

org.springframework
spring-context

<!-- 单元测试 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
<!-- 日志 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
</dependency>
public interface TestService { public int add(); }

public class TestServiceImpl implements TestService {
@Override
public int add() {
System.out.println(“开始执行add…”);
return 0;
}
}
定义代理类,这里要注意导入的包是import java.lang.reflect.*

public class JDKDynamicProxy implements InvocationHandler {

//被代理的目标对象
private Object proxyObj;

/**
  * Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  * loader    :类加载器 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
  * interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
   * h         :一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
 */
   public Object newProxy(Object proxyObj){  
         this.proxyObj = proxyObj;
        //返回一个代理对象  
       return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),   
                                  proxyObj.getClass().getInterfaces(),   
                                  this);  
   }

/**
* 执行目标对象
* Object proxy:被代理的对象
* Method method:要调用的方法
* Object args[]:方法调用时所需要的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
before();
Object object = method.invoke(this.proxyObj,args); // 通过反射机制调用目标对象的方法
after();
return object;
}

     public void before(){
          System.out.println(“开始执行目标对象之前…”); 
     }

     public void after(){
         System.out.println(“开始执行目标对象之后…”); 
     }
 }

测试类:

public static void main(String[] args) {

      //我们要代理的真实对象
      TestService testService = new TestServiceImpl();        
      //testJDKProxyService.add();//不用代理    
    
     JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy();
     TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService);
     //执行代理类的方法  
     testServiceProxy.add();

}
控制台显示

二 CGLIB代理
需要导入 cglib-nodep-2.1_3.jar
spring已经集成了cglib,我们已经导入了spring包,所以不需要再导入其它包了。
先说下cglib,CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

先定义一个实现类(注意并没有实现接口)

public class TestCGLIBServiceImpl {

public int add() {
System.out.println(“开始执行add…”);
return 0;
}
}
定义cglib代理类,此时导入的包应该是import net.sf.cglib.proxy.*

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGLIBProxy implements MethodInterceptor{

private Object targetObject ;//被代理的目标对象

public Object createProxyInstance(Object targetObject) {

this.targetObject = targetObject;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(targetObject.getClass());// 设置代理目标

enhancer.setCallback(this);// 设置回调

return enhancer.create();

}

/**
* 在代理实例上处理方法调用并返回结果
* @param object : 代理类
* @param method :被代理的方法
* @param args :该方法的参数数组
* @param methodProxy
*/
@Override
public Object intercept(Object object, Method method, Object[] args,
MethodProxy methodproxy) throws Throwable {
Object result = null;
try {
System.out.println(“前置处理开始 …”);
result = methodproxy.invoke( targetObject , args);//执行目标对象的方法
System.out.println(“后置处理开始 …”);
} catch (Exception e) {
System.out.println(“异常处理 …”);
} finally {
System.out.println(“调用结束 …”);
}
return result;
}
}
测试类:

public class TestCGLIBProxy {

public static void main(String[] args) {

      //我们要代理的真实对象
      TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl();
       CGLIBProxy CGLIBproxy = new CGLIBProxy();
       TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB);
       testCGLIBProxy.add();
   }

}
结果图:

写在后面:spring AOP的两种代理实现代码就写到这,这里只是实现了,如果你要想真正明白,还得熟悉其中原理机制,比如反射机制,newProxyInstance(…),Enhancer()原理,invoke()原理等等。

参考:
https://blog.csdn.net/u010452388/article/details/80868392
https://blog.csdn.net/ctwy291314/article/details/82017408
https://blog.csdn.net/qq1723205668/article/details/56481476

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值