理解三种代理模式
一、代理模式
代理,顾名思义可以简单理解为代为管理,代理模式就是为其他对象提供额外服务,控制访问(前置处理),或做善后处理(后置处理)。有了代理之后,可以在原来功能的基础上由代理完成另外一部分事情。
常见的代理模式有:
-
-
- 静态代理:这种代理模式需要代理对象和目标对象实现相同的接口。可以在不修改目标对象的基础上扩展功能。
- 缺点:静态代理由于需要和目标对象实现相同的接口,当代理对象变多的时候代理类就会跟着增加,而且一旦更改了接口,那么目标对象和代理对象都要同时做出调整,不方便管理。
- 动态代理:代理对象不需要实现目标对象接口,通过JAVA的API动态生成目标对象的代理对象。Proxy.newProxyInstance(。。。),其中有三个参数:
- ClassLoader loader:目标对象的类加载器
- Class<?>[] interfaces:目标对象的接口类型
- InvocationHandler h:事件处理函数,实现对目标对象的操作。
- CGLIB动态代理:也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
- Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
- Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
- 静态代理:这种代理模式需要代理对象和目标对象实现相同的接口。可以在不修改目标对象的基础上扩展功能。
-
二、静态代理(需要接口)
静态代理需要目标对象和代理对象实现相同的接口:
UserDaoInterface接口类:
1 public interface UserDaoInterface { 2 public void save(); 3 }
目标对象:
1 public class UserDao implements UserDaoInterface { 2 public void save() { 3 System.out.println("保存用户信息中。。。。"); 4 } 5 }
代理对象:
1 /** 2 * 代理对象,和目标对象实现相同接口 3 */ 4 public class UserDaoProxy implements UserDaoInterface { 5 private UserDaoInterface userDao; 6 7 public UserDaoProxy(UserDaoInterface userDao) { 8 this.userDao = userDao; 9 } 10 11 public void save() { 12 System.out.println("开始保存"); 13 userDao.save(); 14 System.out.println("保存成功"); 15 } 16 }
测试类:
1 public class Test { 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 System.out.println("静态代理"); 5 //获取对象 6 UserDaoInterface userDao = new UserDaoProxy(new UserDao()); 7 userDao.save(); 8 } 9 }
实现结果:
如果要增加接口的方法,目标对象和代理对象类都需要修改。
三、动态代理(需要接口)
动态代理,代理对象无需刻意实现目标对象接口。
接口类
1 public interface UserDaoInterface { 2 public void save(); 3 }
目标类
1 public class UserDao implements UserDaoInterface { 2 public void save() { 3 System.out.println("保存用户信息中。。。。"); 4 } 5 }
代理类(动态代理,代理类没有实现和目标对象一样的接口 而是通过javaAPI在内存中为我们动态创建了一个代理对象)
1 /** 2 * 代理工厂类 3 */ 4 public class ProxyFactory { 5 private Object obj; 6 7 public ProxyFactory(Object obj) { 8 this.obj = obj; 9 } 10 11 public Object getInstance(){ 12 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), 13 obj.getClass().getInterfaces(), 14 new InvocationHandler() { 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 System.out.println("开始保存"); 17 Object returnObject = method.invoke(obj,args); 18 System.out.println("保存成功"); 19 return returnObject; 20 } 21 }); 22 } 23 }
测试类:
1 public class Test { 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 System.out.println("动态代理"); 5 UserDaoInterface target = new UserDao(); 6 UserDaoInterface proxy =(UserDaoInterface) new ProxyFactory(target).getInstance(); 7 proxy.save(); 8 System.out.println("原生对象:"+target.getClass()); 9 System.out.println("代理对象:"+proxy.getClass()); 10 } 11 }
运行结果:
从结果中我们可以看出返回的是一个javaAPI的代理对象。
四、CGLIB代理(无需接口)
CGLIB代理不需要目标对象有实现接口,它通过构建目标对象的子类对目标功能进行扩展
目标对象类:
1 public class UserDao{ 2 public void save(){ 3 System.out.println("保存用户信息"); 4 } 5 }
代理对象类:
1 public class CglibProxy implements MethodInterceptor { 2 3 private Object target; 4 5 public CglibProxy(Object target) { 6 this.target = target; 7 } 8 9 //给目标对象创建代理对象 10 public Object getProxyInstance(){ 11 /** 12 * 1.工具类,允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类但是拦截了所有的方法。 13 * 和Proxy不一样的是,不管是接口还是类他都能正常工作 14 */ 15 Enhancer en = new Enhancer(); 16 /** 17 * 2.设置父类 18 */ 19 en.setSuperclass(target.getClass()); 20 /** 21 * 3.设置回掉函数(因为MethodInterceptor继承了Callback类,默认执行intercept方法) 22 */ 23 en.setCallback(this); 24 /** 25 * 4.创建子类 26 */ 27 return en.create(); 28 } 29 30 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 31 System.out.println("开始保存"); 32 Object returnObject = method.invoke(target,objects); 33 System.out.println("保存结束"); 34 return returnObject; 35 } 36 }
测 试类:
1 public class Test { 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 System.out.println("cglib代理"); 5 UserDao userDao =(UserDao) new CglibProxy(new UserDao()).getProxyInstance(); 6 userDao.save(); 7 } 8 }
运行结果: