Notes on Java Design Patterns for Beginners--Dynamic Proxy of Proxy Pattern

 

What is a dynamic proxy?

The proxy object ( RealSubject ) can be changed dynamically at runtime, the interface that needs to be controlled ( Abstract Subject (Subject) ) can be changed at runtime, and the control method can also be changed dynamically, thus achieving a very flexible dynamic agency relationship.

 

Java provides an implementation method for dynamic proxy.

In Java's java.lang.reflect library, the following three classes are provided to implement dynamic proxies.

Proxy (class): This class represents proxy settings, usually type (http, socks) and socket address. Proxyis an immutable object.

InvocationHadler (interface): It can be called an invocation handler and is the interface implemented by the invocation handler of the proxy instance. Each agent instance has an associated call handler. When a method is called on a proxy instance, the method call is encoded and dispatched to the method of its invocation handler invoke.

Method (class): Provides information about an individual method on a class or interface (and how to access the method). The reflected methods may be class methods or instance methods (including abstract methods).

 

So, how to implement dynamic proxy? Mainly through the following four steps:

1) Define an abstract topic

2) Define a real topic

The first two are the same as static proxies. The key is how to implement this dynamic agent role ?

3) InvocationHadler (interface) needs to be implemented . The implementation class of this interface will complete the actual work of the dynamic proxy class.

     In the invoke method of this interface, Java's reflection mechanism will be used to dynamically call the real theme through Method (class) .

4) On the client (or the implementation class of InvocationHadler), calling the static method newProxyInstance of Proxy (class) will return a proxy object (this is the dynamic proxy class, which does not actually do actual work) .

 

Let’s understand the implementation mechanism of dynamic proxy through code. 

Also take the example of buying a car in the static proxy of the proxy (Proxy) mode - Notes on Java Design Patterns for Beginners .

In real life, when you buy a car from a seller ( Abstract Subject) , you usually do not buy a car directly from the manufacturer ( Real Subject) . You can buy a car from a 4S store ( Proxy role ) , where you can get more information. Many services.

 

The Java code is as follows:

Abstract subject: 

/**
 * 抽象主题(Subject)
 * 
 * 汽车的销售商
 *
 */
public interface CarSeller {
	
	/*
	 * 销售汽车
	 */
	public Object sellCars(int type);

}

 

Real Subject: 

/**
 * 真实主题(Real Subject)角色
 * 奥迪厂家
 *
 */
public class AudiCarFactory implements CarSeller {

	/*
	 * 实现了抽象主题(Subject)角色的方法
	 */
	public Object sellCars(int type) {
		System.out.println("奥迪工厂出售汽车。");
		if(type == 1){
			return "AudiA6";
		}else{
			return "AudiA8";
		}
	}
}

 

Invocation processor (implementation class of InvocationHadler): 

/*
 * 实际提供代理商服务的一个类
 * (很多地方把这个类称为代理类,个人觉得不准确。
 * 它是一个会完成动态代理类的实际工作的类。)
 */
public class CarProxyInvocationHandler implements InvocationHandler {
	
	Object carSeller = null;
	
	public CarProxyInvocationHandler(Object carSeller){
		this.carSeller = carSeller;
	}
	
	/*
	 * 代理角色提供服务的真正方法。
	 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
	 */
	public Object invoke(Object proxy, Method method, Object[] args){
		Object result = null;
		
		try {
			
			serveBeforeSell();
			result = method.invoke(carSeller,args);
			serveAfterSell();

		} catch (Exception e) {
			System.exit(1);
		}
		
//		System.out.println("result:" + result +";" + args[0]);
		
		return result;
	}
	
	protected void serveBeforeSell(){
		System.out.println("汽车代理商为客户提供了一些售前服务");
	}
	
	protected void serveAfterSell(){
		System.out.println("汽车代理商为客户提供了一些售后服务");
	}

}

  

Client: 

/**
 * 客户端调用
 */
public class Customer {

	public static void main(String[] args) {

//		创建真实主题对象
		CarSeller carSeller = new AudiCarFactory();

//		通过动态的方式,得到了真正的代理角色对象。
//		在运行时,真实主题对象,代理角色以及实际完成代理操作的类被关联起来了。
		CarSeller carProxy = (CarSeller) Proxy.newProxyInstance(carSeller.getClass()
				.getClassLoader(), carSeller.getClass().getInterfaces(),
				new CarProxyInvocationHandler(carSeller));
		
//		由代理商销售汽车
		Object car = carProxy.sellCars(2);
		System.out.println("顾客从代理商那里买了一辆" + car);
		
	}

}

 

operation result: 

汽车代理商为客户提供了一些售前服务
奥迪工厂出售汽车。
汽车代理商为客户提供了一些售后服务
顾客从代理商那里买了一辆AudiA8

 

 When I first see the implementation of Java dynamic proxy, there are several places that are always difficult to understand: 

1) What are the three parameters in the newProxyInstance method of the Proxy class used for.

The first parameter is the class loader used by the real theme object ----- to load the created dynamic proxy class;

The second parameter, all interfaces implemented by the real theme object ----- for the dynamic proxy class, all interfaces of the real theme will be implemented;

The third parameter, an instance of the invocation handler (the implementation class of InvocationHadler) - because the dynamic proxy class inherits the Proxy class, use its InvocationHadler implementation class to construct from the subclass (usually the dynamic proxy class) Function constructs a new Proxyinstance. (See the jdk help documentation)

 

In this way, the dynamic proxy class $Proxy0 we get is designated as the proxy of a real topic, and the proxy inherits Proxy (class) , also implements the abstract topic interface, and is bound to the InvocationHadler interface.

Since the dynamic proxy class $Proxy0 is created at runtime, we cannot directly see the code of this class. You can refer to the link below to learn more.

java dynamic proxy deep learning (Proxy, InvocationHandler), including $Proxy0 source code (transferred)

 

2) What are the three parameters in the invoke method of the InvocationHadler interface used for.

The first parameter is the dynamic proxy object $Proxy0, which is usually not used. However, because of this parameter, we can get access to the methods of this object.

The second parameter is the method defined by the proxy object ( real subject ).

The third parameter is the parameter of the method defined by the proxy object ( real subject )

The second and third parameters can use the reflection mechanism of the Method class to dynamically call the theme object. 

 

3) When calling the method of the dynamic proxy class, how do you call the invoke method of the InvocationHadler interface?

 According to the code of the dynamic proxy class $Proxy0 , we can see that the invoke method of InvocationHadler is called in the method of the abstract theme interface it implements. And use the this pointer of the dynamic proxy class $Proxy0 itself as the first parameter of the invoke method.

 

After understanding these three points, combined with the above code, you can understand the operating mechanism of dynamic proxy:

1) Create a real theme (AudiCarFactory) object, which inherits the abstract theme class (CarSeller);

2) Use the newProxyInstance method of the Proxy class to obtain a dynamic proxy class $Proxy0 and bind the CarProxyInvocationHandler instance;

3) The dynamic proxy class $Proxy0 inherits the Proxy class and implements all interfaces of the real subject object (in this case, only CarSeller);

4) In the method (sellCars) of the abstract theme (CarSeller) class implemented by the dynamic proxy class $Proxy0 , the invoke method of CarProxyInvocationHandler is called;

5) In the invoke method of CarProxyInvocationHandler, the sellCars method of the real theme (AudiCarFactory) is called , and additional operations are added before or after sellCars.

 

The timing diagram is given below, which should be clearer:



 

 

A dynamic proxy class is a class that can specify the interface it implements at runtime and when the class is created. Each instance of the proxy class has a corresponding InvocationHandler object.

 

To quote a netizen’s summary: 

The so-called dynamic proxy (Dynamic Proxy) is a class: it is a class generated at runtime. When generating it, you must provide a set of interfaces to it, and then the class advertises that it implements this interface. You can of course use an instance of this class as any one of this interface. Of course, this dynamic proxy (Dynamic Proxy) is actually a proxy (Proxy), and it will not do substantive work for you. When generating its instance, you must provide a handler, which takes over the actual work.

 

 

Guess you like

Origin blog.csdn.net/louis_lee7812/article/details/83803451