概述
代理(Proxy) 是一种设计模式,提供了对目标对象的另外一种访问方式,即通过代理访问目标对象,这样的好处是,可以在目标对象的基础上,增强额外的功能操作,扩展目标对象的功能。
举例:明星(邓紫棋)<-----经纪人<------用户
目标对象 代理对象
静态代理(一般不用)
- 代理对象要实现与目标对象一样的接口
- 可以做到在不修改目标对象的功能前提下,对目标对象功能进行扩展
- 缺点
- 因为代理对象,需要与目标对象实现一样的接口,所有会有很多代理类,
- 一旦接口增加方法,目标对象与代理对象都要维护
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.fuyi.a_static; 2 3 public interface IUserDao { 4 void save(); 5 } 6 7 package cn.fuyi.a_static; 8 9 public class UserDao implements IUserDao{ 10 11 public void save() { 12 System.out.println("=====已经保存数据====-"); 13 } 14 } 15 16 package cn.fuyi.a_static; 17 18 public class UserProxy implements IUserDao{ 19 20 private IUserDao target; 21 public UserProxy(IUserDao target) { 22 this.target = target; 23 } 24 25 @Override 26 public void save() { 27 System.out.println("开始事务"); 28 target.save(); 29 System.out.println("提交事务"); 30 } 31 32 } 33 34 35 package cn.fuyi.a_static; 36 37 import static org.junit.Assert.*; 38 39 import org.junit.Test; 40 41 public class App { 42 43 @Test 44 public void testStaticProxy() throws Exception { 45 //目标对象 46 IUserDao userDao = new UserDao(); 47 48 //代理对象 49 IUserDao userDaoProxy = new UserProxy(userDao); 50 51 userDaoProxy.save(); 52 } 53 } 54 55 56 /**Output 57 开启事务 58 =====已经保存数据====- 59 关闭事务 60 61 62 */
动态代理
- 代理对象不需要实现接口
- 目标对象一定要实现接口
- 代理对象的生成是利用JDKAPI,动态的在内存中构建代理对象(需要我们指定目标对象实现的接口)
- 也称JDK代理,接口代理
- JDK中生成代理对象的API
static Object newProxyInstance(
ClassLoader loader, 指定当前目标对象使用的类加载器
Class<?>[] interfaces, 目标对象实现的接口的类型
InvocationHandler h) 事件处理器
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.fuyi.b_dynamic; 2 3 public interface IUserDao { 4 void save(); 5 } 6 7 package cn.fuyi.b_dynamic; 8 9 public class UserDao implements IUserDao{ 10 11 public void save() { 12 System.out.println("=====已经保存数据====-"); 13 } 14 } 15 16 package cn.fuyi.b_dynamic; 17 18 import java.lang.reflect.InvocationHandler; 19 import java.lang.reflect.Method; 20 import java.lang.reflect.Proxy; 21 22 public class ProxyFactory { 23 24 private Object target; 25 public ProxyFactory(Object target) { 26 this.target = target; 27 } 28 29 public Object getProxyInstance() { 30 return Proxy.newProxyInstance(target.getClass().getClassLoader(), 31 target.getClass().getInterfaces(), 32 new InvocationHandler() { 33 34 @Override 35 public Object invoke(Object proxy, Method method, Object[] args) 36 throws Throwable { 37 System.out.println("开启事务"); 38 39 //执行目标对象的方法 40 Object returnValue = method.invoke(target, args); 41 42 System.out.println("关闭事务"); 43 return returnValue; 44 } 45 }); 46 } 47 } 48 49 package cn.fuyi.b_dynamic; 50 51 import static org.junit.Assert.*; 52 53 import org.junit.Test; 54 55 public class App { 56 57 @Test 58 public void testDynamicProxy() throws Exception { 59 //目标对象 60 IUserDao target = new UserDao(); 61 62 //代理对象 63 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); 64 65 proxy.save(); 66 } 67 } 68 69 /*** 70 开启事务 71 =====已经保存数据====- 72 关闭事务 73 74 */
Cglib代理
- Cglib代理,也叫作子类代理,在内存中构建一个子类对象从而实现对目标对象功能的扩展
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以用cglib实现
- Cglib是一个强大的高性能的代码生成包,它可以在运行期间扩展Java类与实现Java接口,它广泛的被许多AOP的框架使用,如:spring AOP,为他们提供方法的interception(拦截);
- Cglib包的底层通过使用一个小而快的字节码处理框架ASM,来装换字节码并生成新的类,不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉
- spring-Core中包含了cglibg功能
- 目标对象不能为final
- 目标对象的方法如果为final/static,那么就不会别拦截,即不会执行目标对象额外的业务方法
- 在spring的AOP编程中
- 如果加入容器的目标对象有实现接口,就用JDK代理
- 如果目标对象没有实现接口,就用Cglib代理
1 package cn.fuyi.c_cglib; 2 3 public class UserDao { 4 5 public void save() { 6 System.out.println("=====已经保存数据====-"); 7 } 8 } 9 10 package cn.fuyi.c_cglib; 11 12 import java.lang.reflect.InvocationHandler; 13 import java.lang.reflect.Method; 14 import java.lang.reflect.Proxy; 15 16 import org.springframework.cglib.proxy.Enhancer; 17 import org.springframework.cglib.proxy.MethodInterceptor; 18 import org.springframework.cglib.proxy.MethodProxy; 19 20 public class ProxyFactory implements MethodInterceptor{ 21 22 private Object target; 23 public ProxyFactory(Object target) { 24 this.target = target; 25 } 26 27 public Object getProxyInstance() { 28 //1.工具类 29 Enhancer enhancer = new Enhancer(); 30 31 //2.设置父类,即目标对象 32 enhancer.setSuperclass(target.getClass()); 33 34 //3.设置回调对象,即实现MethodInterceptor的类的对象 35 enhancer.setCallback(this); 36 37 //4.创建子类 38 return enhancer.create(); 39 } 40 41 @Override 42 public Object intercept(Object obj, Method method, Object[] args, 43 MethodProxy proxy) throws Throwable { 44 45 System.out.println("开启事务"); 46 47 //执行目标对象的方法 48 Object returnValue = method.invoke(target, args); 49 50 System.out.println("提交事务"); 51 return returnValue; 52 } 53 } 54 55 package cn.fuyi.c_cglib; 56 57 import static org.junit.Assert.*; 58 59 import org.junit.Test; 60 61 public class App { 62 63 @Test 64 public void testDynamicProxy() throws Exception { 65 //目标对象 66 UserDao target = new UserDao(); 67 System.out.println(target.getClass()); 68 69 //代理对象 70 UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance(); 71 System.out.println(proxy.getClass()); 72 73 proxy.save(); 74 } 75 } 76 77 /***Output 78 class cn.fuyi.c_cglib.UserDao 79 class cn.fuyi.c_cglib.UserDao$$EnhancerByCGLIB$$b9ff5e0 80 开启事务 81 =====已经保存数据====- 82 提交事务 83 84 */