给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问.
按照代理对象的创建时期
,可分为静态代理和动态代理。
静态代理:静态代理在编译时
就已经实现,编译完成后代理类是一个实际的class文件
动态代理:动态代理是在运行时
动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
举例:我想卖车,但我很忙,不想被电话骚扰,于是交给二手车交易所来帮我卖车
卖车子接口
interface SaleCar{ void sale(); }
张三真正卖车子的实现类(委托类
)
class ZhangSanTrade implements SaleCar{ @Override public void sale() { System.out.println("zhangsan sale his car"); } }
二手车交易类(代理类
)
class CarTradeProxy implements SaleCar{ private ZhangSanTrade owner; public CarTradeProxy(ZhangSanTrade owner){ this.owner=owner; } @Override public void sale() { System.out.println("proxy add price"); owner.sale(); } }
测试
疑问:代理类和委托类差别不大,直接创建委托类调用sale方法不就可以了吗?
解答:代理类在真正调用委托类的方法之前做了中间加价的操作。即代理模式实现在委托类的基础上增加了额外的逻辑操作
需求增加:
我想用卖车的钱加自己的一些存款买个房子,自己也不想东奔西跑,于是把买房委托房产中介
在定义一个买房的接口
interface BuyHouse{ void buy(); }
重写委托类,实现卖车和买房两个接口
class ZhangSanTrade implements SaleCar,BuyHouse{ @Override public void sale() { System.out.println("zhangsan sale his car"); } @Override public void buy() { System.out.println("zhangsan buy house"); } }
可以看到,我现在既要卖车,也要买房子
在创建一个买房子的中介代理类
class HouseTradeProxy implements BuyHouse{ private ZhangSanTrade owner; public HouseTradeProxy(ZhangSanTrade owner){ this.owner=owner; } @Override public void buy() { System.out.println("proxy add price"); owner.buy(); } }
测试类
public static void main(String[] args) { //委托类 ZhangSanTrade zhangSanSaleCar=new ZhangSanTrade(); //代理类 CarTradeProxy carTradeProxy=new CarTradeProxy(zhangSanSaleCar); carTradeProxy.sale(); System.out.println("------------------------------"); HouseTradeProxy houseTradeProxy=new HouseTradeProxy(zhangSanSaleCar); houseTradeProxy.buy(); }
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:
冗余
。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。不易维护
。一旦接口增加方法,目标对象与代理对象都要进行修改。通过静态代理的方式,可以完美解决我们的问题,但当越来越多的委托类需要代理,而且代理做的工作又一样,会多出很多的代理类。此时想,我们可以只做一次,代理一类委托类,此时动态代理应运而生,它可以只定义一次就能为一类委托类做代理
动态代理常见JDK 动态代理与 CGLIB 动态代理
区别:
使用场景:
AOP 的实现原理、RPC远程调用、Java 注解对象获取、日志框架、全局性异常处理、事务处理
UserService接口
public interface UserService { void addUser(); void updateUser(String str); }
UserServiceImpl实现类
public class UserServiceImpl implements UserService{ @Override public void addUser() { System.out.println("添加用户"); } @Override public void updateUser(String str) { System.out.println("更新用户信息" + str); } }
UserProxy代理类,实现InvocationHandler接口重写invoke方法
public class UserProxy implements InvocationHandler { private Object target; public UserProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object res = method.invoke(target, args); System.out.println("记录日志"); return res; } }
测试 ,实现了增强,打印出了日志
Proxy.newProxyInstance 方法得到的也是 UserService 的实现类对象,那么其实这是一种基于接口的动态代理。也叫做 JDK 动态代理
JDK 动态代理是基于接口的代理
,而 CGLIB 动态代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
,也就是说 CGLIB 动态代理采用类继承 -> 方法重写的方式进行的,下面我们先来看一下 CGLIB 动态代理的结构。
如上图所示,代理类继承于目标类,每次调用代理类的方法都会在拦截器中进行拦截,拦截器中再会调用目标类的方法。
CGlib需要导入Jar包,那么我用SpringBoot直接导入依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
UserServiceImpl被代理类
public class UserServiceImpl implements UserService{ @Override public void addUser() { System.out.println("添加用户"); } @Override public void updateUser(String str) { System.out.println("更新用户信息" + str); } }
UserServiceCGlib代理
public class UserServiceCGlib implements MethodInterceptor { private Object target; public UserServiceCGlib() { } public UserServiceCGlib(Object target) { this.target = target; } //返回一个代理对象: 是 target对象的代理对象 public Object getProxyInstance() { //1. 创建一个工具类 Enhancer enhancer = new Enhancer(); //2. 设置父类 enhancer.setSuperclass(target.getClass()); //3. 设置回调函数 enhancer.setCallback(this); //4. 创建子类对象,即代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("增强开始~~~"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("增强结束~~~"); return result; } }
测试类
注:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
总结: