Welcome to follow the official wechat account: FSA Full stack action 👋

I. Introduction to the agent mode

Proxy Pattern is a structural Pattern that provides a Proxy for other objects to control access to the object. The client does not directly call the actual object, but indirectly calls the actual object by invoking the Proxy.

Core function: Protect target object, enhance target object (similar to decorator mode)

  • The core of

    • Subject: Abstract interface, an abstract interface that both the target object class and the proxy class implement
    • Proxy: A Proxy class that contains a reference to the target object class and allows arbitrary manipulation of the target object’s methods
    • RealSubject: Target object class, also called delegate class, or proxied class
  • Application scenarios

    • Each big data franchise, agent manufacturers to sell the corresponding products, agents hold the real authorized agent
    • The client does not want to directly access the real object, or has difficulty accessing the real object, and does indirect access through a proxy object
    • You want to do some control or enhance access to a class
  • classification

    • Static proxy: the source code for a proxy class is created by a programmer or generated by a tool, and the proxy class is recompiled, that is, the relationship between the proxy class and the delegate class exists before the program runs
    • Dynamic proxy: use the form of dynamic bytecode generation to dynamically create proxy classes during running. Common dynamic proxy tools include JDKProxy (based on reflection principle, low performance) and Cglib (based on ASM mechanism, generation of subclasses of the proxy class, high performance).
  • advantages

    • You can do some control or add functionality when accessing a class
    • Operation agent class does not need to modify the original source code, in line with the open and closed principle, the system has good flexibility and scalability
  • disadvantages

    • Increased system complexity and call links

Second, agent mode code implementation

The following uses simulated file uploading as an example to estimate upload time using static and dynamic proxies.

Create an abstract interface:

Note: This interface is required, both proxying and proxying classes need to be implemented

/** * Subject: abstract interface **@author GitLqr
 */
public interface IUploader {
	void upload(File file);
}
Copy the code

Create the target object class, that is, the proxied class:

/** * RealSubject: Target object class **@author GitLqr
 */
public class HttpUploader implements IUploader {
	@Override
	public void upload(File file) {
		try {
			Thread.sleep(500);
			System.out.println("Upload files using HTTP...");
		} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code

Static proxy

  • Static proxies identify proxied classes at code compile time
  • A static proxy class must implement the same interface as the proxied class
  • Static proxies can hide the implementation of proxied classes; Additional operations can be added without changing the proxy class

Create a static proxy class:

The static proxy class holds the proxy object reference, in the corresponding interface method, uses the proxy object to execute the method, and records the time stamp before and after the method execution, so as to calculate the method time.

/** * Proxy class: static proxy **@author GitLqr
 */
public class StaticProxy implements IUploader {

	IUploader uploader;

	public StaticProxy(IUploader uploader) {
		super(a);this.uploader = uploader;
	}

	@Override
	public void upload(File file) {
		long start = System.currentTimeMillis();
		uploader.upload(file);
		long end = System.currentTimeMillis();
		System.out.println("Time:" + (end - start) + "ms"); }}Copy the code

Use:

Note: The proxied object can be created directly in the proxy class, so as to achieve better concealability, at the same time the extensibility will be reduced, depending on the actual needs

public static void main(String[] args) {
    IUploader uploader = new HttpUploader();
    IUploader uploaderProxy = new StaticProxy(uploader);
    File file = new File("/");
    uploaderProxy.upload(file);
}
Copy the code

Dynamic proxy

  • Dynamic proxies create proxy classes dynamically only when the code is running
  • Dynamic proxy can avoid the redundancy caused by generating a large number of proxy classes compared to static proxy classes

Dynamic proxy can be implemented using JDkProxy or Cglib. The following uses JDkProxy (also known as JDK dynamic proxy) as an example

Jdkproxy is JDK’s own, based on interface design implementation, can only proxy some methods in the interface, and through reflection execution method, low performance; Cglib relies on third-party libraries, but is based on ASM and does not rely on interfaces, because it is the way ASM subclasses (inheritance) and has higher performance

Jdkproxy involves two important classes or interfaces:

  • java.lang.reflect.ProxyClass for dynamically created proxy objects, which provide a number of methods, most commonly usedProxy#newProxyInstance()To get a dynamic proxy object
  • java.lang.reflect.InvocationHandler: is the interface that dynamic proxy classes implement. When we call a method through a proxy object, the method is forwarded toInvocationHandlerinvoke()Method to call

Create dynamic proxy objects:

public static void main(String[] args) {
    // Proxy object
    IUploader uploader = newHttpUploader(); ClassLoader classLoader = uploader.getClass().getClassLoader(); Class<? >[] interfaces = uploader.getClass().getInterfaces();// Dynamic proxy
    IUploader uploaderProxy = (IUploader) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long start = System.currentTimeMillis();
            Object result = method.invoke(uploader, args); // Note: the executor of the method is the proxied object!!
            long end = System.currentTimeMillis();
            System.out.println("Time:" + (end - start) + "ms");
            returnresult; }});/ / use
    File file = new File("/");
    uploaderProxy.upload(file);
}
Copy the code

If this article is helpful to you, please click on my wechat official number: FSA Full Stack Action, which will be the biggest incentive for me. The public account not only has Android technology, but also iOS, Python and other articles, which may have some skills you want to know about oh ~