Learning is not so utilitarian, two brothers with you from a higher dimension of easy to read source ~
With the in-depth reading of Nacos source code, I feel more and more interesting, and a large number of design patterns and basic knowledge points are used in it. Whether or not you read the source code, it’s worth taking a look at the Nacos application case.
Today’s article introduces the use of the agent pattern in Nacos Client. Reading this article, you can not understand the Nacos source code, but can learn the use of the agent mode; If you are ready to read the source code of Nacos, you can not only learn the case of the agent pattern, but also have a deeper perception of the design ideas in Nacos.
Introduction to the Proxy Pattern
Generally speaking, the agency mode is to let others (agents) to help you do things you do not care about, the role of the intermediary in daily life.
For example, in daily life, if you want to buy a car, you can go directly to the selection, quality inspection, etc., but this process will consume a lot of time and energy. Then, you can find an agent to help with the selection, quality inspection things.
For software design, the proxy pattern is defined as: the proxy pattern provides an object with a proxy object, and the proxy object controls the reference to the original object. Generally speaking, the agent mode is the common intermediary in our life.
The structure of the proxy pattern
When not using the proxy pattern, we use an interface like this:
When the client uses the CarService interface, it needs to create an instance of the CarServiceImpl class and then process the business logic.
However, in some scenarios where a client class does not want or cannot refer directly to a delegate object (CarServiceImpl), the proxy class object can mediate between the client class and the delegate object and provide the same functionality.
If the same functionality is provided, then the proxy class and the delegate class need to implement the same interface. At this point, the figure above evolves into an agency model:
In the proxy pattern diagram, a proxy class is added compared to the normal direct use, and the proxy class holds a reference to the delegate class (real object). The proxy class itself does not actually implement the service, but rather provides a specific service by calling the relevant methods of the delegate class, so it holds a reference to the real class.
The proxy class can add some common services before and after the execution of the business function, such as being responsible for pre-processing, filtering, forwarding messages to the delegate class, and later processing the returned results.
Roles in proxy mode:
- Abstract Subject class: Declares the common interface between the target object and the proxy object. The proxy object can be used anywhere the target object can be used.
- RealSubject classes: also known as delegated or brokered roles. Defines the target object represented by the proxy object.
- Proxy class: also called Proxy class or Proxy class. The proxy object contains a reference to the target object so that it can be manipulated at any time. The proxy object provides the same interface as the target object so that it can be replaced at any time. A proxy object typically performs an operation before or after a client call is passed to the target object, rather than simply passing the call to the target object.
Proxy pattern implementation
Take a look at the code implementation of the proxy pattern as shown in the above structure diagram.
Define abstract topic class (CarService), concrete topic class (CarServiceImpl), and proxy class (CarServiceProxy) :
Public interface CarService {// select Car chooseCar(); Boolean qualityCheck(); } public class CarServiceImpl implements CarService {@override public Car chooseCar() { System.out.println(" Real operation: select car "); return new Car(); } @override public Boolean qualityCheck() {system.out.println (" real operation: qualityCheck "); return true; }} public class CarServiceProxy implements CarService {private CarServiceImpl real; public CarServiceProxy() { real = new CarServiceImpl(); } @override public Car chooseCar() {system.out.println (" CarServiceProxy: add some logs "); return real.chooseCar(); } @override public Boolean qualityCheck() {system.out.println (" CarServiceProxy qualityCheck: add some logs "); return real.qualityCheck(); }}Copy the code
Corresponding client test class:
public class Client { public static void main(String[] args) { CarService carService = new CarServiceProxy(); carService.chooseCar(); carService.qualityCheck(); }}Copy the code
Using the proxy class directly, you can do the expected job.
Execute the program and print the following log:
Agent CarServiceProxy Car selection: Add some logs first True operation: CarServiceProxy Quality check: Add some logs first True operation: Quality checkCopy the code
As you can see, you can add some additional operations through the proxy class before the actual operations.
Nacos’s agent pattern practices
With the basic knowledge and examples of the broker pattern shown above, let’s take a look at how the broker pattern is implemented in Nacos.
The Nacos Client uses two protocols to communicate with the registry: HTTP and gRPC. These two protocols implement the common abstract topic class NamingClientProxy, the specific topic class NamingHttpClientProxy and NamingGrpcClientProxy, corresponding to the Http protocol and gRPC protocol implementation respectively.
At this point, the Nacos considering to support through flexible configuration to choose specific communication protocol, and this function has no way to the theme of the two concrete classes, thus creates a proxy class NamingClientProxyDelegate to complete some processing and judgment in advance.
The usage class diagram of the entire proxy pattern is as follows:
As you can see from the figure above, there are some differences between Nacos’s proxy pattern usage and the standard proxy pattern.
First, NamingClientProxyDelegate agent the specific theme class at the same time, it may consider is convenient communication protocol configuration of the switch. At the same time, some additional functions such as event listening are handled in the proxy class.
Secondly, the naming of Nacos is not friendly. For example, the abstract theme is directly suffixes with Proxy, which makes people confused. This causes a conflict with the proxy class name in the proxy pattern, so replace the suffix of the proxy class with Delegate.
The customer class in the figure above is NacosNamingService, in which the agent class initialization operation is implemented. The specific code implementation is as follows:
public class NacosNamingService implements NamingService {
// ...
private NamingClientProxy clientProxy;
private void init(Properties properties) throws NacosException {
// ...
this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, properties, changeNotifier);
}
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
clientProxy.registerService(serviceName, groupName, instance);
}
// ...
}
Copy the code
Abstract Topic class NamingClientProxy is the interface, part of the code is as follows:
public interface NamingClientProxy extends Closeable {
void registerService(String serviceName, String groupName, Instance instance) throws NacosException;
void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException;
// ...
}
Copy the code
The proxy class NamingClientProxyDelegate partial implementation is as follows:
public class NamingClientProxyDelegate implements NamingClientProxy {
// ...
private final NamingHttpClientProxy httpClientProxy;
private final NamingGrpcClientProxy grpcClientProxy;
public NamingClientProxyDelegate(String namespace, ServiceInfoHolder serviceInfoHolder, Properties properties,
InstancesChangeNotifier changeNotifier) throws NacosException {
// ...
this.httpClientProxy = new NamingHttpClientProxy(namespace, securityProxy, serverListManager, properties,
serviceInfoHolder);
this.grpcClientProxy = new NamingGrpcClientProxy(namespace, securityProxy, serverListManager, properties,
serviceInfoHolder);
}
// ...
}
Copy the code
As you can see, the proxy class implements the NamingClientProxy interface, holds object references to both NamingHttpClientProxy and NamingGrpcClientProxy, and initializes them.
About NamingHttpClientProxy and NamingGrpcClientProxy code we will no longer show, they first inherited AbstractNamingClientProxy abstract class, the abstract class implements NamingClientProxy interface.
On the whole, the application of the agent pattern in Nacos is quite clever. Combined with the scene, one agent class represents two concrete implementation classes, but at the same time, the problem of naming remains to be discussed.
The difference between the proxy and decorator patterns
When learning to use the proxy pattern, it is often confused with the friend and decorator pattern. Here’s a quick look at the immediate differences.
In the decorator pattern, the decorator and the decoratee both implement the same interface. In the proxy pattern, proxy classes and real classes all implement the same interface. And both extend the methods of the class, which does seem to blur the boundaries.
But there are some differences:
- The decorator pattern emphasizes enhancements, such as providing more properties and methods; Proxy mode emphasizes having someone else do the tasks for you (logging, caching) that don’t have much to do with your business. The proxy pattern is for object control because the object being represented is often difficult to obtain directly or does not want to be exposed internally.
- Decoration pattern is an alternative to inheritance scheme, which extends the function of objects in a transparent way to the client. In proxy mode, an object is provided with a proxy object, and the proxy object controls the reference to the original object.
- The decorative mode is to enhance the function of the decorative object; The proxy mode controls the proxy object, but does not enhance the function of the object itself.
summary
The proxy mode is relatively rare in everyday business code. This article focuses on the static proxy mode and its application in Nacos. You can see many examples of dynamic proxies in the Spring framework, and we’ll cover them when we have a chance. Nacos’s use of the proxy model is flexible, but not perfect. This may also provide another perspective on how we perceive the agency pattern.
If you have any questions or want to discuss the content of the article, please contact me (wechat: Zhuan2quan, remarks Nacos), if you think the writing is good, worth learning together, then pay attention to it.
Nacos series of articles
-
01 “Learn Nacos with two brothers” the first Nacos client service registration source code analysis”
-
Ext-01 “Learn Nacos with two brothers” Ext-01 article to see how Nacos is live to learn to use the simple factory mode!
-
Ext-02 “Learn Nacos from two senior brothers” Ext-02 interviewers asked about the factory model, did you understand it correctly?
-
Ext-03 “Learn Nacos from two senior brothers” Ext-03 Article Nacos here why use reflection mechanism?
-
Ext-04 “learn Nacos from two brothers” Ext-04 article Nacos unexpectedly use proxy mode like this?
Author of SpringBoot Tech Insider, loves to delve into technology and write about it.
Official account: “Program New Horizon”, the official account of the blogger, welcome to follow ~
Technical exchange: please contact the blogger wechat id: Zhuan2quan