proxy pattern
1. Definition and type
- Provides a proxy for other objects to control access to such objects
- Proxy objects mediate between client and target objects
- Type: enhanced
2. Applicable scenarios
- Protect target object
- Enhance target object
3. Advantages
- Proxy mode can separate the proxy object from the target object to which the real object is called
- It reduces the coupling degree of the code to a certain extent and has good scalability
- Protect target object
- Enhance target object
4. Disadvantages
- The agent pattern will increase the number of classes in the system design
- Adding a proxy object to the client and target objects will slow down the request processing
- Increase the complexity of the system
5. Expansion
- Static proxy
- Dynamic proxy (only class proxy that implements interface in Jdk)
- CGlib proxy
6. Relevant design modes
- Agent mode and decorator mode
- Agent mode and adapter mode
7. Coding
7.1 static agent
-
Create the dao service layer of common. See the code
- Order entity class 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 layer interface and implementation class
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 Layer call Dao Layer addition Order"); return orderDao.insert(order); } }
- dao layer interface and implementation class
public interface IOrderDao { int insert(Order order); } public class IOrderDaoImpl implements IOrderDao{ @Override public int insert(Order order) { System.out.println("Dao Order added successfully!"); return 1; } }
-
Create proxy class
public class OrderServiceStaticProxy { private IOrderService orderService; public void saveOrder(Order order) { beforeProxy(); // sub-treasury orderService = new IOrderServiceImpl(); Integer userId = order.getUserId(); int dbNum = userId % 2; System.out.println("Static agent assigned to[ db" + dbNum + "]Processing data"); // Set the assigned database DataSourceContentHolder.setDBType("db" + dbNum); afterProxy(); orderService.saveOrder(order); } public void beforeProxy() { System.out.println("Pre proxy class enhancement method"); } public void afterProxy() { System.out.println("Post proxy class enhancement method"); } }
- Simulated Spring sub Library
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 test
public class Test { public static void main(String[] args) { Order order = new Order(); order.setUserId(1); OrderServiceStaticProxy staticProxy = new OrderServiceStaticProxy(); staticProxy.saveOrder(order); } }
Console output:
- UML class diagram
Now we can see that the proxy mode can add and enhance some functions by extending the proxy class without modifying the proxy object.
The above describes the content of static proxy. Why is it called static? Because its type is predetermined in advance.
Purpose of the agent: to enhance / extend the target method
7.2 dynamic agent
-
public class OrderServiceDynamicProxy implements InvocationHandler { private Object target; public OrderServiceDynamicProxy(Object obj) { this.target = obj; } /** Generate proxy object */ 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); // Enhanced target method Object object = method.invoke(target,arg); afterProxy(); return object; } public void beforeProxy(Object obj) { System.out.println("Dynamic agent before"); int userId = 0; if (obj instanceof Order) { Order order = (Order) obj; userId = order.getUserId(); } int dbNum = userId % 2; System.out.println("Dynamic agent assignment to[ db" + dbNum + "]Processing data"); // Set the assigned database DataSourceContentHolder.setDBType("db" + dbNum); } public void afterProxy(){ System.out.println("Dynamic agent after"); } }
-
test method
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); } }
- Please note that
//Agents in JDK can only be used for interface agents, otherwise an error will be reported
IOrderServiceImpl dynamicProxy = (IOrderServiceImpl) new OrderServiceDynamicProxy(new IOrderServiceImpl()).getTarget();
If you are interested, you can manually debug this code~
7.3 Cglib agent
- Create Cglib proxy class
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 Dynamic agent before"); int userId = 0; if (obj instanceof Order) { Order order = (Order) obj; userId = order.getUserId(); } int dbNum = userId % 2; System.out.println("Dynamic agent assignment to[ db" + dbNum + "]Processing data"); // Set the assigned database DataSourceContentHolder.setDBType("db" + dbNum); } public void afterProxy(){ System.out.println("Dynamic agent after"); } }
- Test class
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); } }
- output
8. Source code
Application in Mybatis
-
MapperProxyFactory [external link image transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-psrcgskn-1634196334408) (/ users / root1 / library / Application Support / typera user images / image-20211012203359641. PNG)]
-
proxy pattern
- The cached mapper method (method) is also used
- The cached mapper method (method) is also used