The proxy pattern

Learning from crazy God B station video

Why learn the proxy pattern, because the underlying mechanism of AOP is dynamic proxies!

The proxy mode is divided into static proxy and dynamic proxy. Dynamic proxies do not care who they are in the implementation phase, but specify which objects they are in the run phase. In contrast, the way to write your own proxy class is static proxy.

Static agent

So let’s write a static proxy first

Static agent

Static proxy role analysis

  • Abstract roles: Typically implemented using interfaces or abstract classes

  • Real role: The role being represented

  • Proxy role: Proxy for the real role; After a real role is represented, it usually does some ancillary operations.

  • Customer: Use the agent role to perform some operations.

Code implementation

Rent.java is an abstract role

// Abstract role: rent a house
public interface Rent {
   public void rent(a);
}
Copy the code

Host. Java is a real role

// Real character: landlord, landlord wants to rent the house
public class Host implements Rent{
   public void rent(a) {
       System.out.println("House for Rent"); }}Copy the code

Proxy. Java is the Proxy role

// Proxy role: intermediary
public class Proxy implements Rent {

   private Host host;
   public Proxy(a) {}public Proxy(Host host) {
       this.host = host;
  }

   / / rent
   public void rent(a){
       seeHouse();
       host.rent();
       fare();
  }
   / / the checking
   public void seeHouse(a){
       System.out.println("Show the tenant a house.");
  }
   // A broker fee is charged
   public void fare(a){
       System.out.println("Collect a broker's fee"); }}Copy the code

Client.java is a Client

// Client class, usually customers to find agent!
public class Client {
   public static void main(String[] args) {
       // The landlord wants to rent a house
       Host host = new Host();
       // The agent helps the landlord
       Proxy proxy = new Proxy(host);
       // You go to an agent!proxy.rent(); }}Copy the code

Analysis: in this process, you direct contact is intermediary, just as in real life, you can’t see the landlord, but you still rent to the landlord’s house through the agent, this is the so-called agency model, program is derived from life, so to learn programming, generally more abstract events in the way of looking at life.

Benefits of static proxies:

  • Can make our real role more pure. No longer pay attention to some public things.
  • The common business is completed by the agent. The division of business is realized.
  • Common services become more centralized and convenient when they are extended.

Disadvantages:

  • More classes, more proxy classes, the amount of work is larger. Development efficiency is reduced.

We want the benefits of static proxies without the disadvantages, so here we have dynamic proxies!

Static proxies understand again

1, create an abstract role, such as we usually do user business, abstract is to add, delete, change and check!

// Abstract roles: add, delete, change and check services
public interface UserService {
   void add(a);
   void delete(a);
   void update(a);
   void query(a);
}
Copy the code

2. We need a real object to do this

// The real object, the person who completed the add, delete, change and check operation
public class UserServiceImpl implements UserService {

   public void add(a) {
       System.out.println("Added a user.");
  }

   public void delete(a) {
       System.out.println("Deleted a user");
  }

   public void update(a) {
       System.out.println("Updated a user");
  }

   public void query(a) {
       System.out.println("Query a user"); }}Copy the code

Demand comes, now we need to add a log function, how to achieve!

  • Idea 1: Add code to the implementation class.
  • Idea 2: Using proxies is the best way to do this without changing the business.

4. Set up a proxy class to handle logging! The agent role

// Proxy role, in which to add logging implementation
public class UserServiceProxy implements UserService {
   private UserServiceImpl userService;

   public void setUserService(UserServiceImpl userService) {
       this.userService = userService;
  }

   public void add(a) {
       log("add");
       userService.add();
  }

   public void delete(a) {
       log("delete");
       userService.delete();
  }

   public void update(a) {
       log("update");
       userService.update();
  }

   public void query(a) {
       log("query");
       userService.query();
  }

   public void log(String msg){
       System.out.println("Executed."+msg+"Method"); }}Copy the code

5, Test access class:

public class Client {
   public static void main(String[] args) {
       // Real business
       UserServiceImpl userService = new UserServiceImpl();
       / / the proxy class
       UserServiceProxy proxy = new UserServiceProxy();
       // Use proxy classes to implement logging!proxy.setUserService(userService); proxy.add(); }}Copy the code

OK, now we should have no problem with the proxy model, the key point is that we need to understand the idea;

The core idea in AOP is that we have implemented enhancements to the original functionality without changing the original code

A dynamic proxy

JDK dynamic proxy

A dynamic proxy

  • The role of a dynamic proxy is the same as that of a static proxy.

  • The proxy class for dynamic proxy is dynamically generated. The proxy class for static proxy is written in advance

  • Dynamic proxy can be divided into two types: dynamic proxy based on interface and dynamic proxy based on class

    • Interface based dynamic proxy —-JDK dynamic proxy
    • Class – based dynamic proxy – Cglib
    • Javasist is now used to generate dynamic proxies.
package com.company;

public interface Rent {
    void rent(a);
}
Copy the code
package com.company;

public class Host implements Rent{
    @Override
    public void rent(a) {
        System.out.println("House for Rent"); }}Copy the code
package com.company;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Proxy2 implements InvocationHandler {
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // This can be enhanced
        seeHouse();
        // Core: Essence is realized by reflection!
        Object result = method.invoke(rent, args);
        fare();
        return result;
    }

    // Generate the proxy class, focusing on the second argument, to get the abstract role to proxy! It used to be one role, but now it can represent a class of roles
    public Object CreateProxyObj(a) {
        return Proxy.newProxyInstance(rent.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
    }

    / / the checking
    public void seeHouse(a) {
        System.out.println("Show the tenant a house.");
    }

    // A broker fee is charged
    public void fare(a) {
        System.out.println("Collect a broker's fee"); }}Copy the code
package com.company;

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy2 proxy2 = new Proxy2();
        proxy2.setRent(host);
        Rent rent = (Rent)proxy2.CreateProxyObj(); // Dynamically generate the corresponding proxy class!rent.rent(); }}Copy the code

Deepen the understanding

Let’s implement the proxy using the dynamic proxy we’ll write later UserService!

We could also write a generic dynamic proxy implementation class! Set all proxy objects to Object!

public class ProxyInvocationHandler implements InvocationHandler {
   private Object target;

   public void setTarget(Object target) {
       this.target = target;
  }

   // Generate the proxy class
   public Object getProxy(a){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),
               target.getClass().getInterfaces(),this);
  }

   // proxy: proxy class
   // method: the method object of the invocation handler of the proxy class.
   public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
       log(method.getName());
       Object result = method.invoke(target, args);
       return result;
  }

   public void log(String methodName){
       System.out.println("Executed."+methodName+"Method"); }}Copy the code

The test!

public class Test {
   public static void main(String[] args) {
       // Real objects
       UserServiceImpl userService = new UserServiceImpl();
       // The invocation handler for the proxy object
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setTarget(userService); // Set the object to be proxied
       UserService proxy = (UserService)pih.getProxy(); // Dynamically generate proxy classes!proxy.delete(); }}Copy the code

Test, add, delete, check, check the results!

CGLIB dynamic proxy

Let’s take a look at the code

package proxy;
 
import java.lang.reflect.Method;
 
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
public class CglibProxy implements MethodInterceptor
{
    Generates a proxy class based on a type. This method is not required to be in the MethodInterceptor
    public Object CreatProxyedObj(Class
        clazz)
    {
        Enhancer enhancer = new Enhancer();
        
        enhancer.setSuperclass(clazz);
        
        enhancer.setCallback(this);
        
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
    {
        // Here is the enhancement
        System.out.println("Money");
        
        returnarg3.invokeSuper(arg0, arg2); }}Copy the code

CreatProxyedObj requires only one type clazz to generate a proxy object, so it is a “proxy of class” and creates an object of a new type discovered by printing the type. Unlike JDK dynamic proxies, which require an object to implement an interface (the second of three arguments), Cglib does not require this.

Benefits of dynamic proxies

Static proxy has it, static proxy does not have, it also has!

  • Can make our real role more pure. No longer pay attention to some public things.
  • The common business is completed by the agent. The division of business is realized.
  • Common services become more centralized and convenient when they are extended.
  • A dynamic proxy, typically for a certain type of service
  • A dynamic proxy can proxy multiple classes, proxy is the interface!