There are feelings, there are dry goods, wechat search [three prince Ao bing] pay attention to the programmer who has a little bit of things.
This article has been included in GitHub github.com/JavaFamily, there are a line of large factory interview complete test sites, information and my series of articles.
Design Patterns have been shared with you many common patterns, interested partners can review, consolidate understanding.
This time, I’m going to share with you the agent model, one of the three main types of design patterns. The agent model is not often used in business scenarios, but interviewers often ask a question.
Can you tell me about the AOP proxy pattern in Spring? What is the difference between the JDK proxy mode and cglib proxy mode?
Clear and unclear students can continue to look down, there will be a harvest.
Without further ado, let’s begin a step by step analysis of the proxy pattern.
Definition and Purpose
First, there are several types of proxy patterns
- Remote proxy: Delegate work to a remote object (a different server, or a different process). It is commonly used in Web services. Also, our RPC calls can be understood as a kind of remote proxy.
- Protected proxy: this mode mainly performs security and permission checks. (Little contact)
- Caching proxy: This is well understood as a way to speed up calls with storage, such as the @cacheable method in Sping, which caches the results of a particular parameter and returns data directly from the cache the next time the method is called with the same parameter.
- Virtual proxy: This proxy is used to add functionality to a method, such as logging performance metrics or lazy initialization
The above are just the concepts we are looking at, but let’s take a look at the components of the proxy pattern.
- Subject (common interface) : The existing interface used by the client
- RealSubject (Real Object) : Class of real objects
- ProxySubject (proxy object) : Proxy class
As you can see from the figure, the whole interface is still very simple, just a real object and a proxy object.
Purpose: To provide a real proxy object for better control of the real object. This is from Beauty of Design Patterns.
Code example implementation
In order to facilitate understanding, or as an example, do not know whether everyone is reading junior high school or high school has experienced the process of the small strip, if now A classmate C have some words want to talk to classmates (such as playing games together A school) but because it’s class time, and cannot be said with A loud voice, between the classmate A and classmate C took A classmate B, So now student A can only find student B first and give it the note, and let him tell student C, but whether to play or not to play, that is still only A real student C can decide.
Therefore, the agent mode can be understood as student B is the agent of student C. Student A can only find student B when seeking student C. Student B can convey student C through student B and feedback the execution result of student C to student A at the same time.
Finished with the example or concrete look at the implementation of the code
public interface Subject {
// Common interface
void doSomething(a);
}
Copy the code
Define a common interface (what everyone should do: Play games together after school)
public class RealSubject implements Subject {
// Real objects
@Override
public void doSomething(a) {
System.out.println("Play video games after school."); }}Copy the code
Build a real object, student C in this example
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public ProxySubject(a) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
this.realSubject = (RealSubject) this.getClass().getClassLoader().loadClass("com.ao.bing.demo.proxyPattern.RealSubject").newInstance();
}
@Override
public void doSomething(a) {
realSubject.doSomething();
}
public static void main(String[] args) {
try {
// The first way
new ProxySubject().doSomething();
// Print the result: Go to play games after school
} catch (Exception e) {
// The proxy fails.
// The teacher caught him passing the note. Or classmate C is not on the seat and other abnormal circumstances
}
// The second way
new ProxySubject(new RealSubject()).doSomething();
// Print the result: Go to play games after school}}Copy the code
Construct the proxy object, namely student B, so it can be seen that student A has no real contact with student C. Through student B’s proxy for student C, we can know whether student C can play games with him after school
Inside the Main method, there are two ways to call real objects
The first is to load the real column object in the form of a classloader, so we don’t have to worry about when we need a real real column object
The second way is to pass the materialized object as a value. (Understood as decorator mode)
The difference here is that the proxy mode provides the exact same interface, while the decorator mode enhances the interface.
Static proxy, dynamic proxy and CGLIb proxy analysis
Static agent
The child implementation above is actually a static proxy, as you can see the overall simplicity. But its disadvantages are also obvious
Static proxies need to create a proxy class for each object, which increases maintenance costs and development costs. To solve this problem, dynamic proxies need to be created instead of creating a proxy class for each class that needs a proxy
A dynamic proxy
Dynamic proxies reasonably avoid the static approach of having to build proxy classes for the classes to be propped up in advance. Instead, it is created at run time through reflection.
You need to understand two things when writing dynamic proxies: Proxy can be understood as a scheduler, and InvocationHandler enhanced service interface can be understood as a Proxy. So I personally understand dynamic proxy as a kind of behavior monitoring.
Specific code to achieve an example: mantis cicada, by listening to the action of the cicada mantis. The multilevel proxy pattern will be discussed later.
public interface BaseService {
void mainService(a);
}
public class Cicada implements BaseService {
@Override
public void mainService(a) {
System.out.println("Main business, take the cicada for example, when the cicada makes a business call, mantis listens."); }}Copy the code
Create common interfaces as well as real object cicadas
public class PrayingMantis implements InvocationHandler {
private BaseService baseService;
// The first example is the style code
public PrayingMantis(BaseService baseService) {
this.baseService = baseService;
}
// Mantis's main business is listening to objects
@Override
public Object invoke(Object listener, Method method, Object[] args) throws Throwable {
method.invoke(baseService,args);
secondaryMain();
return null;
}
// Here we understand enhanced business, that is, we can implement InvocationHandler to add other business, such as logging, etc.
private void secondaryMain(a){
System.out.println("Mantis chasing cicadas - Secondary business."); }}Copy the code
Create a mantis class that listens for the action of the cicada class
public class BeanFactory {
public static BaseService newInstanc(Class classFile) {
// 1. Create cicada, real class object
BaseService trueCicada = new Cicada();
// 2. Create a proxy mantis
InvocationHandler prayingMantis = new PrayingMantis(trueCicada);
// 3. Request a proxy object from the Jvm.
Class classArray[] = {BaseService.class};
BaseService baseService = (BaseService) Proxy.newProxyInstance(classFile.getClassLoader(), classArray, prayingMantis);
return baseService;
}
/ / the Demo test
public static void main(String[] args) {
BaseService baseService = newInstanc(Cicada.class);
baseService.mainService();
// Test result: main business
// Mantis catchers - secondary business}}Copy the code
It can be seen from the results that when cicada main business is called, Mantis can listen to cicada’s business and process other business logic, which is why AOP in Spring can deal with log facets.
Nature of agency:
I think it’s actually a behavior of listening on a proxy object ($proxy InvocationHandler).
Composition of proxy mode:
- Interface: Declares behavior that needs to be listened on
- Proxy implementation class (InvocationHandler) : Secondary business, secondary business and primary business binding execution
- Proxy object (listener object)
Cglib dynamic proxy
Cglib dynamic proxies are similar to JDK dynamic proxies in that they implement the proxy interface.
The specific code is as follows:
public class PrayingMantis implements MethodInterceptor {
private Cicada cicada;// Proxy object
public Cicada getInstance(Cicada cicada) {
this.cicada = cicada;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.cicada.getClass());
enhancer.setCallback(this);
return (Cicada) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object object = methodProxy.invokeSuper(o, objects);
secondaryMain();
return object;
}
private void secondaryMain(a) {
System.out.println("Mantis chasing cicadas - Secondary business.");
}
public static void main(String[] args) {
PrayingMantis prayingMantis = new PrayingMantis();
Cicada instance = prayingMantis.getInstance(new Cicada());
instance.mainService();
// Result: primary business
// Mantis catchers - secondary business
}
Copy the code
Because cicadas are the same, I won’t post them here.
Careful students have noticed that Cglib does not need to be implemented through an interface; it is invoked by implementing subclasses.
The Enhancer object implements dynamic proxying by setting the proxy object as a subclass of the promenade class. Because it is inherited, the proxy class cannot be modified with final, otherwise an error will be reported.
Final classes: Classes cannot be inherited; internal methods and variables become final types
JDK and Cglib:
JDK dynamic proxies use reflection to generate an anonymous class that implements the proxy interface and calls InvokeHandler to handle it before invoking the specific method
The cglib dynamic proxy uses the ASM open source package to load the class file of the propped object class and subclass it by modifying its bytecode
ASM: A Java bytecode manipulation framework. It can be used to dynamically generate classes or enhance the functionality of existing classes. ASM can either generate binary class files directly or dynamically change the behavior of classes before they are loaded into the Java virtual machine. Java classes are stored in rigorously formatted.class files that have enough metadata to parse all the elements of the class: class names, methods, attributes, and Java bytecodes (instructions). After reading information from class files, ASM can change class behavior, analyze class information, and even generate new classes based on user requirements. — The above ASM explanation comes from Jane’s book
Multistage dynamic agent
After looking at the dynamic proxy above, I do not know if you have an idea to achieve a multi-level dynamic proxy.
Or to mantis cicada as an example, plus a yellow sparrow after the realization of multi-level dynamic proxy mode.
public class Cardinal implements InvocationHandler {
// Listen to proxy proxy objects
private Object proxyOne;
public Cardinal(Object proxyOne) {
this.proxyOne = proxyOne;
}
// Mantis's main business is listening to objects
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(proxyOne, args);
secondaryMain();
return null;
}
private void secondaryMain(a) {
System.out.println("Sparrow eats Mantis." - Secondary business.); }}Copy the code
Create a sparrow proxy object, which becomes a mantis as its real object, and when the mantis object is called, the sparrow is strong enough to make the corresponding business logic
public class BeanFactory {
public static BaseService newInstanc(Class classFile) {
// 1. Create cicada, real class object
BaseService trueCicada = new Cicada();
// 2. Create a proxy mantis
InvocationHandler prayingMantis = new PrayingMantis(trueCicada);
// 3. Requesting a proxy object from the Jvm is actually a solid object
Class classArray[] = {BaseService.class};
BaseService baseService = (BaseService) Proxy.newProxyInstance(classFile.getClassLoader(), classArray, prayingMantis);
// 4. Create the agent to implement the yellow sparrow secondary agent
InvocationHandler cardinal = new Cardinal(baseService);
BaseService secondBaseService = (BaseService) Proxy.newProxyInstance(classFile.getClassLoader(), classArray, cardinal);
// Add a layer of proxy on top of the finches.
// omit other more hierarchical proxy objects
return secondBaseService;
}
/ / the demo test
public static void main(String[] args) {
BaseService baseService = BeanFactory.newInstanc(Cicada.class);
baseService.mainService();
// Result: primary business
// Mantis catchers - secondary business
// Finches eat mantis - secondary business}}Copy the code
Based on this code, the multilevel proxy process is basically implemented. The mantis listens to the cicadas, and the finch listens to the mantis.
Similarly, if you want to achieve three-level proxy, four-level proxy is not difficult, in each layer of the top of the proxy object can be added.
The essence of dynamic proxy can be understood as decoupling the “secondary business” from the “primary business”, allowing developers to focus more on the primary business, improving development efficiency and maintenance costs.
conclusion
The proxy pattern is relatively rare in business code in my opinion, and dynamic proxies in particular are almost unheard of. But the proxy mode is also a mode we must understand, because learning a good proxy mode helps us to read some source code, check some deeper problems, or in the face of some business scenarios, can also have a great improvement, design mode itself is to solve the problem and create.
With an understanding of dynamic proxies, the implementation of AOP is now self-evident to us.
This is the end of the detailed design patterns, and I will give you a summary of some unusual design patterns.
I’m Aobing, the more you know, the more you don’t know, thank you for your talent: likes, favorites and comments, we’ll see you next time!
This article is constantly updated. You can search “Santaizi Aobing” on wechat and read it for the first time. Reply [Information] There are the interview materials and resume templates for first-line big factories prepared by me.