“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”
preface
Proxy mode is a kind of structural design mode, which provides another way to access the target object. That is, the target object is accessed through the proxy object.
The advantage of doing this is that you can enhance additional functional operations on the basis of the target object implementation, that is, extend the functionality of the target object.
Here’s an idea in programming: don’t modify code or methods that someone else has written. If you need to modify, you can extend the method by proxy.
There are roughly three roles in the proxy model:
Real Subject
: Real class, that is, the proxy class, delegate class. Used to actually fulfill business service functions;Proxy
: proxy class, which implements its own request using the corresponding function of the Real Subject. Proxy class object does not really implement its business function;Subject
: Defines the interface that both the RealSubject and Proxy roles should implement.
There are three types of proxy patterns: static proxy, dynamic proxy (JDK proxy, interface proxy), and Cglib proxy (dynamically subclass the target object in memory).
The body of the
Static agent
A static proxy needs to define the interface, the proxied object implements the same interface with the proxied object, and then invoke the methods of the target object by calling the same methods.
As you can see, the proxy class does nothing more than add operations before and after calling the delegate class method. Different delegate classes lead to different proxy classes.
A company manufactures television sets and needs an agent to sell them locally. So when customers need to buy a TV set, they can buy it directly through an agent.
Example code:
TV:
public class TV {
private String name;/ / name
private String address;/ / producer
public TV(String name, String address) {
this.name = name;
this.address = address;
}
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress(a) {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString(a) {
return "TV{" +
"name='" + name + '\' ' +
", address='" + address + '\' ' +
'} '; }}Copy the code
Create company interface:
public interface TVCompany {
/** * produces TV sets *@returnThe TV * /
public TV produceTV(a);
}
Copy the code
The company’s factories make television sets:
public class TVFactory implements TVCompany {
@Override
public TV produceTV(a) {
System.out.println("TV factory produce TV...");
return new TV("Xiaomi TV".Hefei ""); }}Copy the code
Agents to order goods (static agent) :
public class TVProxy implements TVCompany{
private TVCompany tvCompany;
public TVProxy(a){}@Override
public TV produceTV(a) {
System.out.println("TV proxy get order .... ");
System.out.println("TV proxy start produce .... ");
if(Objects.isNull(tvCompany)){
System.out.println("machine proxy find factory .... ");
tvCompany = new TVFactory();
}
returntvCompany.produceTV(); }}Copy the code
Consumers pick up goods through agents (use of agents) :
public class TVConsumer {
public static void main(String[] args) {
TVProxy tvProxy = newTVProxy(); TV tv = tvProxy.produceTV(); System.out.println(tv); }}Copy the code
Output results:
TV proxy get order .... TV proxy start produce .... machine proxy find factory .... TV factory produce TV... TV{name=' mi TV ', address=' hehei '} Process finished with exit code 0Copy the code
Summary:
-
Advantages: The static proxy mode extends the functions of the target object without changing the target object.
-
Disadvantages: Static proxy implements all the methods of the target object. Once a method is added to the target interface, both the proxy object and the target object have to be modified accordingly, increasing maintenance costs.
How do you address the shortcomings in static proxies? The answer is to use dynamic proxies
A dynamic proxy
Dynamic proxy has the following characteristics:
-
JDK dynamic proxy objects do not need to implement interfaces, only target objects need to implement interfaces.
-
Implementing dynamic interface-based proxies requires the use of apis in the JDK to dynamically build Proxy objects in JVM memory.
-
You need to use java.lang.reflect.Proxy, and its newProxyInstance method, but this method takes three arguments.
Note that this method is static in the Proxy class and takes the following three arguments:
ClassLoader loader
: specifies that the current target object uses a class loader. The method of obtaining the loader is fixed.Class<? >[] interfaces
: Specifies the type of the interface implemented by the target object.InvocationHandler h
: event handling. When executing the method of the target object, the method of the event handler will be triggered, passing in the currently executing method of the target object as an argument.
One day the company increased its business and sold more and more goods, and the after-sales service also needed to be better. However, the company found that the original agent needed retraining to complete all the business, so it found another dynamic agent B. Agent B promises to seamlessly connect all the business of the company. No matter what new business is added, it can be completed without additional training.
Example code:
The company added maintenance business:
public interface TVCompany {
/** * produces TV sets *@returnThe TV * /
public TV produceTV(a);
/** * Repair TV *@paramTV *@returnThe TV * /
public TV repair(TV tv);
}
Copy the code
Factories need to get into the maintenance business:
public class TVFactory implements TVCompany {
@Override
public TV produceTV(a) {
System.out.println("TV factory produce TV...");
return new TV("Xiaomi TV".Hefei "");
}
@Override
public TV repair(TV tv) {
System.out.println("tv is repair finished...");
return new TV("Xiaomi TV".Hefei ""); }}Copy the code
B Agents are responsible for all the business of the company. Use the proxy. newProxyInstance method to generate the Proxy object, implement the Invoke method in the InvocationHandler, invoke the method of the Proxy class through reflection, and provide enhancement methods.
public class TVProxyFactory {
private Object target;
public TVProxyFactory(Object o){
this.target = o;
}
public Object getProxy(a){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("TV proxy find factory for tv.... ");
Object invoke = method.invoke(target, args);
returninvoke; }}); }}Copy the code
The purchase and maintenance of these two businesses can be handled directly by AGENT B. After the company to increase business, B agent can also be done.
public class TVConsumer {
public static void main(String[] args) {
TVCompany target = new TVFactory();
TVCompany tvCompany = (TVCompany) newTVProxyFactory(target).getProxy(); TV tv = tvCompany.produceTV(); tvCompany.repair(tv); }}Copy the code
Output results:
TV proxy find factory for tv....
TV factory produce TV...
TV proxy find factory for tv....
tv is repair finished...
Process finished with exit code 0
Copy the code
Summary:
-
The proxy object does not need to implement the interface, but the target object must implement the interface, otherwise dynamic proxy cannot be used.
-
With dynamic proxy, all function calls will eventually be forwarded by the Invoke function, so we can do whatever we want here, such as logging, transactions, interceptors, permission control, etc.
One of the most fatal problems with dynamic proxy in the JDK is that it can only proxy implementation classes that implement an interface, and the proxy classes can only proxy methods implemented in the interface. If the implementation class has its own private method that the interface does not have, the method cannot be called by the proxy.
How to solve this problem? We can use CGLIB dynamic proxy mechanisms.
Additional agent
Both static proxies and JDK proxies require an object to implement an interface, and sometimes the proxy object is just a single object, in which case the Cglib proxy can be used.
A Cglib agent, known as a subclass agent, builds a subclass object in memory to extend the functionality of the target object.
Agent C not only wants to represent the company, but also the products of multiple factories.
Cglib generates a proxy class using Enhancer, implements the Intercept Method in the MethodInterceptor interface, and adds enhancement methods to this Method, and calls to the Method using the reflection Method or inheriting the Method proxy class.
Seeing that agent B has taken on a variety of business of the company (interface), agent C has found new business opportunities. B can only represent the products of a certain company, while I not only want to represent the products of the company, but also connect with different factories to get goods through a wider range of channels and make money more easily. And that’s where Cglib comes in.
Example code:
public class TVProxyCglib implements MethodInterceptor {
// Create a proxy object for the target object
public Object getProxyInstance(Class c){
/ / 1. Utility class
Enhancer enhancer = new Enhancer();
//2. Set the parent class
enhancer.setSuperclass(c);
//3. Set callback function
enhancer.setCallback(this);
//4. Create subclasses (proxy objects)
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("TVProxyFactory enhancement.....");
Object object = methodProxy.invokeSuper(o, objects);
returnobject; }}Copy the code
New agent B factory
public class TVFactoryB {
public TV produceTVB(a) {
System.out.println("tv factory B producing tv.... ");
return new TV("Huawei TV"."Nanjing");
}
public TV repairB(TV tv) {
System.out.println("tv B is repair finished.... ");
returntv; }}Copy the code
Agent C can cooperate directly with the company or with the factory. And can be the agent of any factory products.
public class TVConsumer {
public static void main(String[] args) {
TVCompany tvCompany = (TVCompany) new TVProxyCglib().getProxyInstance(TVFactory.class);
TV tv = tvCompany.produceTV();
tvCompany.repair(tv);
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
TVFactoryB tvFactoryB = (TVFactoryB) newTVProxyCglib().getProxyInstance(TVFactoryB.class); TV tv = tvFactoryB.produceTVB(); tvFactoryB.repairB(tv); }}Copy the code
Output results:
TVProxyFactory enhancement.....
TV factory produce TV...
TVProxyFactory enhancement.....
tv is repair finished...
==============================
TVProxyFactory enhancement.....
tv factory B producing tv....
TVProxyFactory enhancement.....
tv B is repair finished....
Process finished with exit code 0
Copy the code
AOP in Spring uses proxies
There are two implementations of AOP in Spring, JDK and Cglib, as shown in the figure below:
If the target object needs to implement the interface, use the JDK proxy.
If the target object does not need to implement the interface, the Cglib proxy is used.
conclusion
-
Static proxy: Requires that both the proxy class and the target class implement the methods of the interface so that the proxy can enhance its functionality.
-
We need a Proxy class to implement an interface. We need to generate a Proxy class using the proxy. newProxyInstance method, and implement the Invoke method in the InvocationHandler to achieve enhanced functionality.
-
Cglib dynamic proxy: You do not need a proxy class to implement the interface. You use Enhancer in Cblib to subclass the proxy object and implement the Intercept method in MethodInterceptor, which implements enhancements.
The last
I am a code is being hit is still trying to advance. If the article is helpful to you, remember to like, follow yo, thank you!