动态代理中最主要的两种实现方式
文章目录
前言
过去在学习AOP(切面编程)时了解到了动态代理,而动态代理是AOP的主要实现手段之一,AOP是动态代理的一种应用深化。本文就浅谈一下动态代理中最常用也是大家最熟悉的两种动态代理方式,JDK代理和Cglib代理。
正文
一:何为动态代理
动态代理是一种基于反射的技术,其原理是运行时动态生成一个代理类,这个代理类与原对象实现同一接口或者是继承同一父类,然后在代理类中生成被代理对象的引用,当代理类的方法被调用时,实际上是通过调用被代理对象的方法来实现原有的功能,同时可以在调用被代理对象的方法前后进行一些额外的操作,比如记录日志、权限控制、缓存等。
讲大白话就是就像房主(委托)和中介(受委托)的关系,中介替房主物色买家(方法执行前),房主签定卖房合约过户等(方法执行),中介替你完成余下的手续(方法执行后)。解耦之处在于:房主从头到尾只需要完成签合约,其他琐事交给中介。
二:动态代理的两种实现方式
1. JDK代理
JDK动态代理是有JDK提供的工具类Proxy实现的,动态代理类是在运行时生成指定接口的代理类,每个代理实例(实现需要代理的接口)都有一个关联的调用处理程序对象,此对象实现了java.lang.reflect下的InvocationHandler接口,最终的业务逻辑是在InvocationHandler实现类的invoke方法上。也即是在invoke方法上可以实现原方法中没有的业务逻辑,相当于spring aop的@Before、@After等注解。
前提:需要代理的类必须实现接口,如果没有实现接口只能通过CGLIB来实现
1.1环境搭建
-
创建service接口
-
public interface studentService { /*添加学生*/ void add(Student student); /*通过id查找学生*/ Student query(long id); }
-
创建service实现类(需要被代理的目标类)
-
public class studentServiceImpl implements studentService { public void add(Student student) { System.out.println("添加学生信息"); } public Student query(long id) { System.out.println("查询学生操作"); Student student=new Student(); student.setName("测试"); student.setAge(18); return student; } }
-
增强类
-
public class DaoTransaction { public void before(){ System.out.println("前置增强"); } public void after(){ System.out.println("后置增强"); } }
1.2InvocationHandler接口
- 实现接口
-
public class TransactionHandler implements InvocationHandler { //增强类对象 private DaoTransaction transaction; //需要代理的目标对象 private Object object; public TransactionHandler(DaoTransaction transaction, Object object) { this.transaction=transaction; this.object=object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj=null; //判断当前方法是否是add,是才做事务操作 if("add".equals(method.getName())) { transaction.before(); obj= method.invoke(object,args); transaction.after(); } else { obj= method.invoke(object,args); } return obj; } }
-
参数介绍
-
Proxy:代理实例,可以通过newProxyInstance创建代理实例
-
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- ClassLoader:类加载器,直接通过需要代理的类获取即可
- Class<?>[]:目标类所实现的所有接口
- InvocationHandler:方法拦截处理器,可以在里面实现方法增强
-
Method:执行目标方法的方法,invoke方法执行
-
args:参数数组
-
1.3测试
-
public class test { @Test public void test1(){ Student student=new Student(); //增强类对象 DaoTransaction transaction=new DaoTransaction(); //目标执行类 StudentService service=new StudentServiceImpl(); //方法拦截处理器 TransactionHandler transactionHandler=new TransactionHandler(transaction,service); //获取代理实例对象 StudentService proxyStudentService=(StudentService) Proxy.newProxyInstance(StudentServiceImpl.class.getClassLoader(), StudentServiceImpl.class.getInterfaces(), transactionHandler); proxyStudentService.add(student); proxyStudentService.query(1); } }
-
测试结果
-
2:Cglib动态代理
Cglib 代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。
2.1环境搭建
因为cglib是第三方的,所以首先要导包
-
导包
-
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
-
其余环境准备与上文jdk动态代理中相同
2.2实现方法拦截MethodInterceptor接口
-
实现方法拦截
-
public class CglibInterceptor implements MethodInterceptor { DaoTransaction transaction; public CglibInterceptor(DaoTransaction transaction){ this.transaction=transaction; } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //事务增强 transaction.before(); Object obj = methodProxy.invokeSuper(o, objects); //事务增强 transaction.after(); return obj; } }
2.3测试
-
public class test { @Test public void test1(){ //得到方法拦截器 CglibInterceptor interceptor=new CglibInterceptor(new DaoTransaction()); //使用cglib框架生成目标类的子类(代理类)实现增强 Enhancer enhancer=new Enhancer(); //设置父类字节码 enhancer.setSuperclass(StudentServiceImpl.class); //设置拦截处理 enhancer.setCallback(interceptor); StudentService service=(StudentService) enhancer.create(); service.add(new Student()); } }
-
测试结果
总结
Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。总之,Java动态代理是一种非常有用的技术,可以在很多场景中发挥作用。通过巧妙地运用代理对象,我们可以实现各种自定义的逻辑,为我们的应用带来更多的灵活性和可定制性。
本文只是简单的谈谈这两种动态代理方式,想要更深层次的了解动态代理还需自行查阅。谢谢!