preface
Hello, everyone, see this title you should think of is the intermediary, the intermediary can help us rent a house to buy a house to go through the formalities and so on, let us in the whole process of renting a house to buy a lot of ease. In life, there are ticketing scalpers, matchmaking, brokers, express delivery, transaction agents, non-intrusive log monitoring, etc., are the actual embodiment of the agent mode.
Proxy Pattern is a structural Pattern that provides a Proxy for other objects to control access to this object. In cases where one object is unsuitable or cannot refer directly to another object, a proxy object can mediate between the client and the target object.
Generic UML class diagram:
The proxy pattern has two main purposes: one is to protect the target object, and the other is to enhance the target object. Proxy patterns are divided into static proxy and dynamic proxy. Let’s take a look at each.
Static agent
Take the mediation as an example and create the top-level interface IPerson.
public interface IPerson {
void findHouse(a);
}
Copy the code
Implement the IPerson interface and create a ZhangSan class.
public class ZhangSan implements IPerson {
@Override
public void findHouse(a) {
System.out.println("Zhang SAN requirements: close to the subway station, large area"); }}Copy the code
However, Zhang SAN is new here and is not familiar with the local area, so he needs the intermediary to help him find it. Create a mediation class HouseProxy, which also implements the IPerson interface. This needs to send in the three objects, and then the intermediary to help him find a room.
public class HouseProxy implements IPerson {
private ZhangSan zhangsan;
public HouseProxy(ZhangSan zhangsan) {
this.zhangsan = zhangsan;
}
@Override
public void findHouse(a) {
System.out.println("The agent starts looking for you.");
zhangsan.findHouse();
System.out.println("We made it."); }}Copy the code
Write a test class and test it
public static void main(String[] args) {
HouseProxy proxy = new HouseProxy(new ZhangSan());
proxy.findHouse();
}
Copy the code
The running results are as follows:Static proxy applications are used every day. When you write a service layer, you inject the DAO layer into it, like this.
public class Service{
@Autowired
private OrderDAO dao;
public void insertOrder(a) {
// Process the business logic. dao.insertOrder();// Process the business logic. }}Copy the code
Static proxies have disadvantages:
(1) An interface of a proxy object can only serve one type of object. If there are many methods to proxy, it is necessary to proxy for each method. Static proxy is not suitable for larger program size.
(2) If an interface adds a method, all proxy classes need to implement this method in addition to all implementation classes, which violates the open closed principle.
A dynamic proxy
Based on the above problem, dynamic proxy appears. The underlying implementation of dynamic proxy generally does not need to be implemented by ourselves. There are many ready-made apis. In the Java ecosystem, by far the most common use is the JDK’s own proxy and the class libraries provided by Cglib. So let’s show you how to write it.
JDK Dynamic proxy
Create a mediation class JDKIntermediary:
public class JDKIntermediary implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target) {
this.target = target; Class<? > clazz = target.getClass();return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target, args);
after();
return result;
}
private void before(a) {
System.out.println("I'm the agent. I'm gonna start looking for you.");
}
private void after(a) {
System.out.println("There you go..."); }}Copy the code
Create another li 4 class:
public class LiSi implements IPerson {
@Override
public void findHouse(a) {
System.out.println("Li Si request: cheap"); }}Copy the code
Test code is as follows:
public static void main(String[] args) {
JDKIntermediary intermediary = new JDKIntermediary();
IPerson zhangsan = intermediary.getInstance(new ZhangSan());
zhangsan.findHouse();
IPerson lisi = intermediary.getInstance(new LiSi());
lisi.findHouse();
}
Copy the code
The running results are as follows:
CGLib
Create the CGlibIntermediary class:
public class CGlibIntermediary implements MethodInterceptor {
public Object getInstance(Class
clazz) {
// The utility class is equivalent to Proxy
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o, objects);
after();
return obj;
}
private void before(a) {
System.out.println("I'm the agent. I'm gonna start looking for you.");
}
private void after(a) {
System.out.println("There you go..."); }}Copy the code
Create a Customer class Customer:
public class Customer {
public void zufang(a) {
System.out.println("Find a house with a budget of 2,000."); }}Copy the code
One small detail is that the target object of the CGLib proxy does not need to implement any interface; it implements dynamic proxy by dynamically inheriting the target object. Look at the test code:
public static void main(String[] args) {
Customer obj = (Customer) new CGlibIntermediary().getInstance(Customer.class);
obj.zufang();
}
Copy the code
Execution result:
Application of dynamic proxy in Spring
We know that the underlying class of Spring transactions is AOP, and the underlying class of AOP is dynamic proxy. There are two important classes: JdkDynamicAopProxy and CglibAopProxy.
The principles for using proxies in Spring are:
- Spring uses the JDK dynamic proxy when the Bean has an implementation interface
- Spring selects the CGLib proxy when the Bean does not implement an interface
- Spring can be configured to force the use of CGLib agents by adding the following code to Spring’s configuration file:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Copy the code
Comparison between JDK and CGLib dynamic proxies
(1) The JDK dynamic proxy implements the interface of the proxied object, and the CGLib proxy inherits the proxied object.
(2) Both the JDK dynamic proxy and the CGLib proxy generate bytecode files at runtime. The JDK dynamic proxy directly writes Class bytecode, while the CGLib proxy uses the ASM framework to write Class bytecode. The implementation of the CGLib proxy is more complex, and the generation of the proxy is less efficient than the JDK dynamic proxy.
(3) JDK dynamic proxy call proxy proxy method is called through the reflection mechanism, CGLib proxy is called directly through the FastClass mechanism, CGLib proxy execution efficiency is higher.
Advantages and disadvantages of the proxy model
Finally, the pros and cons of the code pattern:
- The proxy pattern separates the proxy object from the real object being invoked.
- To a certain extent, the coupling of the system is reduced, and the scalability is good.
- Protects the target object.
- You can enhance the functionality of the target object.
Disadvantages:
- The proxy pattern increases the number of classes in the system design.
- Adding a proxy object to both the client and target objects can slow down requests.
- Added system complexity.
The source code for this article and other design patterns can be found here at github.com/xuhaoj/patt… , thank you for watching, if you feel good, please click a like!