A brief introduction to agent mode

1. What is the proxy mode

Proxy Pattern, also called delegation Pattern, belongs to structural design Pattern and is defined as follows in the Book Zen of Design Pattern: Provide a surrogate or placeholder for another object to control access to it. In short, our purpose is to provide a proxy object for a business class to complete the business logic, if you still have questions, please continue to read.

2. Simple examples

I wonder if my friends in front of the screen will play games to eliminate the boring time. Many of the blogger’s colleagues are addicted to a mobile game called King of Glory. These mMORPGs have a ladder mechanism called ranking, where you play to increase or decrease your ranks. Since it is a game, there must be a win and a lose, and the blogger’s vegetable chicken falls into the category of both vegetable and fun:Over the course of the day, the blogger’s position is getting lower and lower, which is definitely not good, but witty as the blogger came up with a very simple solution: find a substitute. Here is a simple explanation of what is to find a boost: a boost is to give your game account to a higher level of game players to operate to bring profit. At this time we are not difficult to find, although the game is still my account, but the operation of the game has been replaced by my agent, so that we can achieve the purpose of the specified segment. So with continuous efforts, I finally reached my desired position before the end of the season.

So what we need to do now is to analyze the business scenario of the enabler:Before I hired a facilitator to help me play the game, my game flow was as follows:

Code implementation of business scenarios without enablement:

  1. Create a game business interface
public interface Player {

	void login(String username, String password);

	void play(a);

	void result(a);
}

Copy the code
  1. Creating a Gamer
public class GamePlayer implements Player {

	private String username;
	private String password;

	@Override
	public void login(String username, String password) {
		this.username = username;
		this.password = password;
		System.out.println("Users." + username + "Online");
	}

	@Override
	public void play(a) {
		System.out.println("Users." + username + "Game on.");

	}

	@Override
	public void result(a) {
		System.out.println("Users." + username + "Game over, win."); }}Copy the code
  1. Creating a Client
public class Client {

	public static void main(String[] args) {
		GamePlayer gamePlayer = new GamePlayer();
		gamePlayer.login("Zhang"."123456"); gamePlayer.play(); gamePlayer.result(); }}Copy the code

Test results:

After I get a facilitator to help me play the game, the flow becomes: Code implementation:

  1. The game business interface and user class code remain unchanged
  2. Create a generation object
public class ProxyGamePlayer implements Player {

	private GamePlayer gamePlayer;

	@Override
	public void login(String username, String password) {
		// TODO Auto-generated method stub
		gamePlayer.login(username, password);

	}

	@Override
	public void play(a) {
		// TODO Auto-generated method stub
		gamePlayer.play();
		System.out.println("The agent has begun to work.");
	}

	@Override
	public void result(a) {
		gamePlayer.result();
		System.out.println("Training is over.");
	}

	public ProxyGamePlayer(GamePlayer gamePlayer) {
		super(a);this.gamePlayer = gamePlayer; }}Copy the code
  1. The test code
public class Client {

	public static void main(String[] args) {
		ProxyGamePlayer proxyGamePlayer = new ProxyGamePlayer(new GamePlayer());
		proxyGamePlayer.login("Zhang"."123456"); proxyGamePlayer.play(); proxyGamePlayer.result(); }}Copy the code

Test results:

In fact, a simple agent mode has been completed. It is not difficult to find that the overall business process of the game has not changed in this code, but the player of the game has become my facilitator, and I do not need to care about the whole game process. This is the most typical application of the agent mode: Through a proxy object to complete the business logic of the proxy object to achieve the enhancement and monitoring of the entire business process. There are similar scenes in which we look for an intermediary when renting a house and a lawyer when filing a lawsuit. All of these scenes have one thing in common: we fail to give the agent what we should have done by ourselves. Through the agent to complete the original need for us to do things, and we as the principal do not need to care about how to achieve the business process, then we will talk about the agent model and its implementation principle in detail.

Second, the design idea of agent mode

1. Composition of the proxy mode

The agency mode is mainly composed of three elements:

  1. Common behavior (often used as interfaces or abstract classes)
  2. Delegate objects (real objects that provide delegates to proxy objects)
  3. Proxy object (proxy object, the delegate responsible for implementing the real object)

According to the three elements, we can draw a general class diagram:

The implementation of the proxy pattern follows two principles:

  1. The delegate class and the proxy class behave in common or similar ways
  2. The proxy class is responsible for enhancing and managing the delegate class

However, there are two forms of proxy mode implementation:

  1. Static agent
  2. A dynamic proxy

So what are static proxies and what are dynamic proxies? What’s the difference between the two?

1. Static proxy

Static proxy means that the designer of the program has already created the proxy object for the delegate object before the program runs. In other words, the.class file of the proxy object is already generated before the service is started. The game generation example we just cited is the most typical static proxy form. Our generation object ProxyGamePlayer has written the proxy strategy in the way of code before our program runs, and provides proxy service in the way of static after the program runs. In order to deepen our understanding of static agents, we will tell about the static agent model through an example of intermediary rental.

If you have the same experience as the blogger, the normal process of renting a house might be as follows:

Decides to look for housing rental demand – > – > meet the checking – > signing – > check in But by bloggers to work and study at ordinary times, energy is limited, may not be able to provide plenty of time to put into finding homes and landlord to see process, this time we may need an intermediary to help us finish what should we do. After the agency joined us, our rental process did not change too much, but the agency did these things on my behalf, and I only needed to settle the salary for the agency after the process.

Let’s use the form of static agent to do a simple implementation: 1. First define a behavior process of renting a house

public interface Renting {
	// Demand for housing
	public void demand(a);

	// Search for properties
	public void find(a);

	/ / the checking
	public void look(a);

	/ / contract
	public void sign(a);

}

Copy the code

2. Create a delegate object

public class Tenant implements Renting {

	@Override
	public void demand(a) {
		System.out.println("The need is for a three-bedroom near a subway station.");

	}

	@Override
	public void find(a) {
		System.out.println("Find through the rental APP");

	}

	@Override
	public void look(a) {
		System.out.println("House sitting");

	}

	@Override
	public void sign(a) {
		System.out.println("Sign with the landlord."); }}Copy the code

3. Create a proxy object

public class RentingProxy implements Renting {

	private Renting renting;

	// Inject the delegate object with a parameterized construct
	public RentingProxy(Renting renting) {
		super(a);this.renting = renting;
	}

	@Override
	public void demand(a) {
		renting.demand();
		System.out.println("The intermediary has received the customer's demand");

	}

	@Override
	public void find(a) {
		renting.find();
		System.out.println("The intermediary simultaneously leverages existing resources to match customer needs.");

	}

	@Override
	public void look(a) {
		renting.look();
		System.out.println("The intermediary provides door-to-door video recording service.");

	}

	@Override
	public void sign(a) {
		renting.sign();
		System.out.println("Collect commission from client after signing contract."); }}Copy the code

Creating a Client

public class Client {

	public static void main(String[] args) {
		RentingProxy rentingProxy = new RentingProxy(newTenant()); rentingProxy.demand(); rentingProxy.find(); rentingProxy.look(); rentingProxy.sign(); }}Copy the code

Test results: Here’s ourRentingProxyObject before we run the business side I have specified the proxy behavior and write the relevant code, because we pass in the delegate object when the client call, so if we have 100 delegate objects we need to create 100 proxy objects, this is static proxy. So what are the pros and cons of static proxies?Advantages:The proxy behavior of the proxy object is more pure. It does not need to care about some common attribute behavior of the proxy object. It only needs to concentrate on serving its own proxy object.Disadvantages:The proxy object must be created in advance. If the proxy object changes, the proxy object also needs to be changed accordingly, resulting in high maintenance costs.

Is there a way to optimize for the inflexibility of static proxies?

2. Dynamic proxy

Dynamic Proxy: Dynamic Proxy is a runtime loading Proxy technology provided by Java. Compared with static Proxy, Dynamic Proxy is more flexible in providing Proxy services for objects. Dynamic Proxy classes can be dynamically generated by Java through reflection when the program is running. In simple terms, dynamic proxies do not specify who to delegate to during the implementation phase, but specify the delegate object during the run phase. There are two common implementations of dynamic proxies: interface proxies and Cglib proxies.

(1) Interface proxy

The interface proxy mode is a dynamic proxy mode in JavaProxyClass static methodsnewProxyInstanceA proxy instance that returns an interface has achieved the goal of generating proxy classes for different delegate classes. NewProxyInstance = newProxyInstance; newProxyInstance = newProxyInstance;We can see that three elements are needed to use this method again:

  1. Delegate the object’s own classloader.
  2. Delegate the interface implemented by the object itself
  3. A proxy object that implements the invocationHandler interface

OK, we still use the case of intermediary renting to do a simple dynamic agent implementation. 1. Define a rental process interface

public interface Renting {
	// Demand for housing
	public void demand(a);
	// Search for properties
	public void find(a);
	/ / the checking
	public void look(a);
	/ / contract
	public void sign(a);
}
Copy the code

2. Create an implementation class for the interface

public class Tenant implements Renting {

	@Override
	public void demand(a) {
		System.out.println("The need is for a three-bedroom near a subway station.");
	}
	@Override
	public void find(a) {
		System.out.println("Find through the rental APP");
	}
	@Override
	public void look(a) {
		System.out.println("House sitting");
	}
	@Override
	public void sign(a) {
		System.out.println("Sign with the landlord."); }}Copy the code

3. Create a proxy class that implements invocationHandler

public class GamePlayerProxyHandler implements InvocationHandler {
	// Proxied instance
	private Object obj;
	public GamePlayerProxyHandler(Object obj) {
		super(a);this.obj = obj;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = method.invoke(obj, args);
		System.out.println("Resettlement Agency is at your service.");
		returnresult; }}Copy the code

4. Use the Proxy object to implement dynamic Proxy

public class Client {

	public static void main(String[] args) {
		Renting tenant = new Tenant();
		GamePlayerProxyHandler gamePlayerProxyHandler = new GamePlayerProxyHandler(tenant);
		// Get the loader for the delegate object
		ClassLoader classLoader = tenant.getClass().getClassLoader();
		Renting newProxyInstance = (Renting) Proxy.newProxyInstance(classLoader, newClass[] { Renting.class }, gamePlayerProxyHandler); newProxyInstance.demand(); }}Copy the code

Test results: If you’re confused, take a look at the simple structure of this code; Finally, what are the characteristics of dynamic proxy in interface form? Advantages:Compared with static proxy, dynamic proxy greatly reduces the workload of development, reduces the dependency of proxy class on business interface, and reduces the degree of coupling.Disadvantages:Unfortunately, dynamic proxy in Interface form is a bit flawed. Since the newProxyInstance method must pass in the Interface of a delegate object, it is decided that if we want to use dynamic proxy in Interface form, we must create an Interface for the delegate object and implement it. So what if we don’t want to create interfaces for delegate objects?

(2) Cglib agent

The Cglib proxy pattern uses very low-level bytecode technology to implement dynamic proxies. It does not require the delegate class to implement a certain interface, but creates a subclass for the delegate class through bytecode technology, and dynamically weaks the proxy logic into the method by intercepting the method call of the parent class. However, because of the form of creating the subclass integration, the parent class cannot be modified with final. It is important to note that Cglib is not a native Java API, so we need to import the dependent JAR packages before using it.

The git address of the Cglib project is github.com/cglib/cglib

Pom dependence of Cglib:

<dependency> <groupId>cglib</ artifactId> <version>3.1</version> </dependency>Copy the code

If you don’t already know how to use Maven, you can also download it from my web disk:

Link: pan.baidu.com/s/1Fs3ptOUT…

Extraction code: CK14

Then we will continue to explain the code implementation of Cglib through the case of intermediary rental: 1. Here we turn the rental process interface into an abstract class that illustrates the differences between the two dynamic agents

public abstract class Renting {
	// Demand for housing
	abstract void demand(a);

	// Search for properties
	abstract void find(a);

	/ / the checking
	abstract void look(a);

	/ / contract
	abstract void sign(a);
}

Copy the code

2. Create a delegate class

public class Tenant extends Renting {

	@Override
	public void demand(a) {
		System.out.println("The need is for a three-bedroom near a subway station.");

	}

	@Override
	public void find(a) {
		System.out.println("Find through the rental APP");

	}

	@Override
	public void look(a) {
		System.out.println("House sitting");

	}

	@Override
	public void sign(a) {
		System.out.println("Sign with the landlord."); }}Copy the code

3. Create a Cglib proxy object

public class CglibProxy implements MethodInterceptor {

	private Object target;

	public Object getProxyInstance(a) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(target.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}

	public CglibProxy(Object target) {
		super(a);this.target = target;
	}

	@Override
	public Object intercept(Object target, Method method, Object[] param, MethodProxy proxy) throws Throwable {
		System.out.println("Cglib proxy begins");
		Object result = proxy.invokeSuper(target, param);
		System.out.println("Cglib proxy terminated.");
		returnresult; }}Copy the code

4. Test the code (if you are not a Maven project, there will be an error, keep reading)

public class Main {

	public static void main(String[] args) {
		CglibProxy cglibProxy = new CglibProxy(newTenant()); Tenant proxyInstance = (Tenant) cglibProxy.getProxyInstance(); proxyInstance.demand(); }}Copy the code

Test results (non-Maven project): Cglib relies on a third-party oracle ASM package to implement cglib. If you are a Maven project, there will be no error if you have this dependency. If there is an error, you can import the dependency.Pom depends on:

<dependency> <groupId>org.ow2.asm</groupId> <artifactId> <version>5.0.4</version> </dependency>Copy the code

Jar package download address:

Link: pan.baidu.com/s/1qizkN8rf…

Extraction code: 2xeg

Test again after importing jar package: Now that the dynamic proxy can be implemented normally, let’s briefly summarize the cglib proxy form.

Advantages and disadvantages of Cglib: Advantages: Delegate objects do not need to implement interfaces and are more flexible than interface proxies. Disadvantages: Proxying classes cannot be final, and target methods cannot be private or static, limiting the scope of cglib.

Cglib differs from Java’s native interface proxy pattern:

  1. Java dynamic proxies can only be used to Proxy interfaces, not common classes (because the parent class of all generated Proxy classes is Proxy, Java class inheritance mechanism does not allow multiple inheritance). CGLIB can delegate common classes;
  2. Java dynamic proxy uses Java’s native reflection API to operate and is efficient in generating classes. CGLIB uses the ASM framework to operate directly on bytecode, which is efficient in class execution

Summary of agency model

1. Simple design class diagram for proxy pattern

The agency mode is mainly composed of three elements:

  1. Common behavior (often used as interfaces or abstract classes)
  2. Delegate objects (real objects that provide delegates to proxy objects)
  3. Proxy object (proxy object, the delegate responsible for implementing the real object)

2. Advantages and disadvantages of the proxy model

Advantages:

  1. It can realize the management and enhancement of the delegate class flexibly and reduce the coupling degree of the system to a certain extent.
  2. When delegating a proxy, you only need to extend the proxy object to comply with the open closed principle.

Disadvantages:

  1. The complexity of the system is increased to a certain extent
  2. Using the proxy mode may reduce the efficiency of some business scenarios

3. Application scenarios of the proxy mode

Cainiao tutorial mentioned that the agent mode can be divided according to the responsibilities of the use of the following scenarios: 1. Remote agent. 2. Virtual proxy. 3. Copy-on-write proxy. 4. Protect or Access agents. Cache proxy. 6. Firewall agent. 7. Synchronization agents. 8. Smart Reference agents

4. Application of proxy mode in Java

Java proxy mode is really everywhere, such as the Spring framework AOP technology (Aspect Oriented Programming, Aspect Programming) is the use of proxy mode implementation, its main application in the log, cache, transaction and other business module implementation. Using AOP can effectively reduce the coupling between business and business. The blog will be writing a series of hand-written posts on the Spring framework that will also focus on the use of the proxy pattern in AOP.

6. Expansion: Similarities and differences between agent mode and decorator mode

For those of you who are not familiar with decorator pattern, please learn the basics of decorator pattern: [Design Pattern] – Decorator pattern

First, let’s compare the class diagrams of the two modes:Decorator mode: Proxy mode:

The common feature of the two patterns is that they share the same interface. In order not to confuse you, let’s first declare that the decorative pattern is a special application of the proxy pattern. Since the decorator pattern is a proxy pattern, it is normal for it to have the characteristics of a proxy pattern. However, there is also a difference between the two. The proxy mode focuses on the control of the proxy process, while the decoration mode pays more attention to the enhancement and attenuation of the class function, which is more focused on the functional changes. If you don’t comment your code, you don’t have too many peers who care about whether you’re using decorations or proxies

Four, conclusion

Today’s proxy mode explanation is all over, the related code of the design mode has been included in Gitee, you can take it directly if you need it:

Gitee.com/xiaolong-ob…

If you have any questions, you are welcome to leave a message in the comment section or send a private message to the blogger, who will answer them for you in the first time. The code word is not easy, feel the harvest of friends remember to pay attention to the blogger, do not be white whoring monster oh ~ blogger here wish you can be promoted in the New Year, to the peak of life!