设计模式-代理模式
Posted 一菜一汤
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-代理模式相关的知识,希望对你有一定的参考价值。
代理模式
1.定义与类型
- 为其他对象提供一种代理,以控制这么对象的访问
- 代理对象在客户端和目标对象之间起中介作用
- 类型:增强型
2.适用场景
- 保护目标对象
- 增强目标对象
3.优点
- 代理模式能将代理对象与真实对象被调用的目标对象分离
- 一定程度上降低了代码的耦合度,扩展性好
- 保护目标对象
- 增强目标对象
4.缺点
- 代理模式会造成系统设计中类的数目增加
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
- 增加系统的复杂度
5.扩展
- 静态代理
- 动态代理(Jdk中只有实现接口的类代理)
- CGlib代理
6.相关设计模式
- 代理模式和装饰者模式
- 代理模式和适配器模式
7. Coding
7.1 静态代理
-
创建common的dao service层,见代码
- 订单实体类Order
public class Order { private String orderInfo ; private Integer userId; public String getOrderInfo() { return orderInfo; } public void setOrderInfo(String orderInfo) { this.orderInfo = orderInfo; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } @Override public String toString() { return "Order{" + "orderInfo='" + orderInfo + '\\'' + ", userId=" + userId + '}'; } }
- servie层接口及实现类
public interface IOrderService { int saveOrder(Order order); } public class IOrderServiceImpl implements IOrderService { private IOrderDao orderDao; @Override public int saveOrder(Order order) { orderDao = new IOrderDaoImpl(); System.out.println("Service层调用Dao层添加Order"); return orderDao.insert(order); } }
- dao层接口及实现类
public interface IOrderDao { int insert(Order order); } public class IOrderDaoImpl implements IOrderDao{ @Override public int insert(Order order) { System.out.println("Dao层添加订单成功!"); return 1; } }
-
创建代理类
public class OrderServiceStaticProxy {
private IOrderService orderService;
public void saveOrder(Order order) {
beforeProxy();
// 分库
orderService = new IOrderServiceImpl();
Integer userId = order.getUserId();
int dbNum = userId % 2;
System.out.println("静态代理分配到【db" + dbNum + "】处理数据");
// 设置分配的数据库
DataSourceContentHolder.setDBType("db" + dbNum);
afterProxy();
orderService.saveOrder(order);
}
public void beforeProxy() {
System.out.println("前置代理类增强方法");
}
public void afterProxy() {
System.out.println("后置代理类增强方法");
}
}
- 模拟Spring分库
public class DataSourceContentHolder {
private static final ThreadLocal<String> CONTENT_HOLDER = new ThreadLocal<>();
public static void setDBType(String dbType) {
CONTENT_HOLDER.set(dbType);
}
public static String getDBType() {
return CONTENT_HOLDER.get();
}
public static void remove() {
CONTENT_HOLDER.remove();
}
}
public class DynamicDaraSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContentHolder.getDBType();
}
}
- Test测试
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(1);
OrderServiceStaticProxy staticProxy = new OrderServiceStaticProxy();
staticProxy.saveOrder(order);
}
}
控制台输出:
- UML类图
现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
上面介绍的是静态代理的内容,为什么叫做静态呢?因为它的类型是事先预定好的。
代理的目的:增强/扩展目标方法
7.2 动态代理
-
public class OrderServiceDynamicProxy implements InvocationHandler { private Object target; public OrderServiceDynamicProxy(Object obj) { this.target = obj; } /** 生成代理对象 */ public Object getTarget() { Class<?> clz = target.getClass(); return Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object arg = args[0]; beforeProxy(arg); // 增强目标方法 Object object = method.invoke(target,arg); afterProxy(); return object; } public void beforeProxy(Object obj) { System.out.println("动态代理before"); int userId = 0; if (obj instanceof Order) { Order order = (Order) obj; userId = order.getUserId(); } int dbNum = userId % 2; System.out.println("动态代理分配到【db" + dbNum + "】处理数据"); // 设置分配的数据库 DataSourceContentHolder.setDBType("db" + dbNum); } public void afterProxy(){ System.out.println("动态代理after"); } }
-
测试方法
public class TestDynamicProxy {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
IOrderService dynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new IOrderServiceImpl()).getTarget();
dynamicProxy.saveOrder(order);
}
}
- 请注意
// JDK中的代理只能对接口代理 否则会报错
IOrderServiceImpl dynamicProxy = (IOrderServiceImpl) new OrderServiceDynamicProxy(new IOrderServiceImpl()).getTarget();
有兴趣的可以手动debug一下这个代码~
7.3 Cglib代理
- 创建Cglib代理类
public class CglibProxy implements MethodInterceptor {
public Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
beforeProxy(o);
Object invoke = methodProxy.invokeSuper(o, objects);
afterProxy();
return invoke;
}
public void beforeProxy(Object obj) {
System.out.println("Cglib动态代理before");
int userId = 0;
if (obj instanceof Order) {
Order order = (Order) obj;
userId = order.getUserId();
}
int dbNum = userId % 2;
System.out.println("动态代理分配到【db" + dbNum + "】处理数据");
// 设置分配的数据库
DataSourceContentHolder.setDBType("db" + dbNum);
}
public void afterProxy(){
System.out.println("动态代理after");
}
}
- 测试类
public class TestDynamicProxy {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
CglibProxy cglibProxy = new CglibProxy();
IOrderServiceImpl service = (IOrderServiceImpl) cglibProxy.getProxy(IOrderServiceImpl.class);
service.saveOrder(order);
}
}
- 输出
8.源码
Mybatis中的应用
-
MapperProxyFactory
-
代理模式
- 同时用到了享元模式(cachedMapperMethod(method))
以上是关于设计模式-代理模式的主要内容,如果未能解决你的问题,请参考以下文章