声明:
本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。
本博客已标明出处,如有侵权请告知,马上删除。
1. 代理模式讲解
-
定义:为其他对象提供一种代理,以控制对这个对象的访问
-
代理对象在客户端和目标对象之间起到中介的作用
-
类型:结构型
-
适用场景
- 保护目标对象
- 增强目标对象
-
优点
- 代理模式能将代理对象与真实被调用的目标对象分离
- 一定程度上降低了系统的耦合度,扩展性好
- 保护目标对象
- 增强目标对象
-
缺点
- 代理模式会造成系统设计中类的数目增加
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
- 增加系统的复杂度
-
扩展
- 静态代理:在代码中显示指定的代理
- 动态代理:动态代理无法代理类,但是可以代理接口,所以被代理类最少实现一个接口,并且接口中没有声明的方法不能被代理。动态代理用到的代理类是在程序调用到代理类对象时,才由 JVM 真正创建的。
- CGlib 代理:CGlib 是可以代理类的,它是针对类实现进行代理。如果我们代理一个类,CGlib 会生成被代理类的子类,并覆盖其中的方法。在使用 CGLib 代理的时候,因为要用到继承,还有重写,所以被代理类是不能用 final 修饰的类,被代理类中用 final 修饰的方法也不能被代理。
-
Spring 代理选择
- 当 Bean 有实现接口时,Spring 就会用 JDK 的动态代理
- 当 Bean 没有实现接口时,Spring 使用 CGlib
- 可以在 Spring 中配置,强制使用 CGlib
-
相关设计模式
-
代理模式和装饰者模式
装饰者模式是为对象加上行为,而代理模式是控制访问,代理模式更加注重通过设置代理人的方式,来增强目标对象。
-
代理模式和适配器模式
适配器模式主要改变所考虑对象的接口,而代理模式是不能改变被代理类的接口的。
-
2. 静态代理 Coding
下面引入一个根据用户 Id 进行分库的业务场景
-
创建订单类
public class Order { private Object orderInfo; private Integer userId; public Object getOrderInfo() { return orderInfo; } public void setOrderInfo(Object orderInfo) { this.orderInfo = orderInfo; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } }
-
创建 Dao 层接口和实现类
public interface IOrderDao { int insert(Order order); }
public class OrderDaoImpl implements IOrderDao { @Override public int insert(Order order) { System.out.println("Dao层添加order成功"); return 1; } }
-
创建 Service 层接口和实现类
public interface IOrderService { int saveOrder(Order order); }
public class OrderServiceImpl implements IOrderService { private IOrderDao iOrderDao; @Override public int saveOrder(Order order) { iOrderDao = new OrderDaoImpl(); System.out.println("Service调用Dao层添加Order层"); return iOrderDao.insert(order); } }
-
创建静态代理类,对 OrderService 中的 saveOrder 方法进行增强,实现分库功能
package princinple.structural.proxy.staticproxy; import princinple.structural.proxy.IOrderService; import princinple.structural.proxy.Order; import princinple.structural.proxy.OrderServiceImpl; public class OrderServiceStaticProxy { private IOrderService iOrderService; public int saveOrder(Order order) { beforeMethod(order); int result = iOrderService.saveOrder(order); afterMethod(); return result; } private void beforeMethod(Order order) { System.out.println("静态代理 before code"); iOrderService = new OrderServiceImpl(); int userId = order.getUserId(); // 实现分库的功能 int dbRouter = userId % 2; System.out.println("静态代理分配到【db" + dbRouter + "】处理数据"); } private void afterMethod() { System.out.println("静态代理 after code"); } }
-
测试类
public class Test { public static void main(String[] args) { Order order = new Order(); order.setUserId(1); OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy(); orderServiceStaticProxy.saveOrder(order); } }
运行结果:
静态代理 before code 静态代理分配到【db1】处理数据 Service调用Dao层添加Order层 Dao层添加order成功 静态代理 after code
将 userId 改为 2 后,运行结果:
静态代理 before code 静态代理分配到【db0】处理数据 Service调用Dao层添加Order层 Dao层添加order成功 静态代理 after code
现在类图如下所示:
3. 动态代理 Coding
还是上面的业务场景,我们使用动态代理实现。
-
创建一个动态代理类
public class OrderServiceDynamicProxy implements InvocationHandler { private Object target; public OrderServiceDynamicProxy(Object target) { this.target = target; } public Object bind() { Class cls = target.getClass(); return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object argObject = args[0]; beforeMethod(argObject); Object object = method.invoke(target, args); afterMethod(); return object; } public void beforeMethod(Object obj) { int userId = 0; System.out.println("动态代理before code"); if (obj instanceof Order) { Order order = (Order) obj; userId = order.getUserId(); } int dbRouter = userId % 2; System.out.println("动态代理分配到【db" + dbRouter + "】处理数据"); } public void afterMethod() { System.out.println("动态代理after code"); } }
-
测试类
public class Test { public static void main(String[] args) { Order order = new Order(); order.setUserId(1); IOrderService orderService = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind(); orderService.saveOrder(order); } }
运行结果:
动态代理before code 动态代理分配到【db1】处理数据 Service调用Dao层添加Order层 Dao层添加order成功 动态代理after code
将 userId 改为 2 后,运行结果:
动态代理before code 动态代理分配到【db0】处理数据 Service调用Dao层添加Order层 Dao层添加order成功 动态代理after code