java Interview Common Mode Questions Agent Mode

  • 2021-09-12 01:06:21
  • OfStack

Directory 1, Static Agent 2, Dynamic Agent Interview Question 1: What is the difference between JDK Dynamic Agent and CGLIB Dynamic Agent? Interview 2: Why can JDK dynamic proxies only generate proxies for classes that implement interfaces? Summarize This article summarizes the agent design pattern, which will be updated frequently ~ The most intuitive explanation of proxy pattern is that through proxy, it will be "enhanced" by proxy objects! (That is, extending the functionality of the proxy object) Proxy pattern is divided into static proxy and dynamic proxy: the proxy class of dynamic proxy is generated dynamically, and the proxy class of static proxy is the logic written in advance. There are two ways to implement dynamic proxies in Java: JDK Dynamic Proxy CGLIB Dynamic Proxy

1. Static proxy

Static agent role analysis:

Abstract roles: 1. Use interfaces or abstract classes to implement them. Real role: The role being represented. Proxy role: Proxy real role, proxy real role, 1 will do a number of subsidiary operations. Caller: Use the proxy role to do some operations.

We take tenants renting houses as an example, involving tenants, intermediaries and landlords. (The landlord is the agent object and the intermediary is the agent object)

Tenants rent houses in the east of the house through the intermediary, and the agent intermediary needs to find tenants to rent houses and obtain intermediary fees from them.

Code implementation:

Rent.java That is, abstract roles


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

Host.java That is, the real role


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

Proxy.java That is, the proxy role


// Agent role: Mediation 
public class Proxy implements Rent {
   private Host host;
   public Proxy() { }
   public Proxy(Host host) {
       this.host = host;
  }
   //  Rent a house 
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   //  House-viewing 
   public void seeHouse(){
       System.out.println(" Show the tenants the house ");
  }
   //  Collect agency fees 
   public void fare(){
       System.out.println(" Collect agency fees ");
  }
}

Client.java Caller, that is, customer


//  Customer class, 1 All customers will go to the agent! 
public class Client {
   public static void main(String[] args) {
       //  The landlord wants to rent a house 
       Host host = new Host();
       //  Intermediary helps landlord 
       Proxy proxy = new Proxy(host);
       //  You go to the agency! 
       proxy.rent();
  }
}

Disadvantages of static proxy:

You need to create proxy classes manually, and if there are more objects to proxy, there are more and more proxy classes.

In order to solve this problem, there is a dynamic agent!

2. Dynamic Agent

When it comes to dynamic agent, you will definitely ask two ways to implement dynamic agent during the interview:

Let's look at the public first UserService Interface, and UserServiceImpl Implementation class:


/**
 * @author csp
 * @date 2021-06-03
 */
public interface UserService {
    /**
     *  Login 
     */
    void login();
    /**
     *  Logout 
     */
    void logout();
}

/**
 * @author csp
 * @date 2021-06-03
 */
public class UserServiceImpl implements UserService{
    @Override
    public void login() {
        System.out.println(" User login ...");
    }
    @Override
    public void logout() {
        System.out.println(" User launch login ...");
    }
}
JDK Dynamic Proxy

The code is as follows:


/**
 * @author csp
 * @date 2021-06-03
 */
public class JDKProxyFactory implements InvocationHandler {
    //  Target object ( Proxy object )
    private Object target;
    public JDKProxyFactory(Object target) {
        super();
        this.target = target;
    }
    /**
     *  Create a proxy object 
     *
     * @return
     */
    public Object createProxy() {
        // 1. Get the class loader of the target object 
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 2. Obtain the implementation interface of the target object 
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // 3. No. 1 3 Parameters required 1 Implementation invocationHandler Interface object 
        Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
        return newProxyInstance;
    }
    /**
     *  A way to actually perform proxy enhancements 
     *
     * @param proxy   Proxy object .1 Do not use 
     * @param method  Methods that need enhancement 
     * @param args    Parameters in the method 
     * @return
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK  Dynamic proxy: login / Logic check before logout ......");
        Object invoke = method.invoke(target, args);
        System.out.println("JDK  Dynamic proxy: login / Log print after logout ......");
        return invoke;
    }
    public static void main(String[] args) {
        // 1. Create an object 
        UserServiceImpl userService = new UserServiceImpl();
        // 2. Create a proxy object 
        JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
        // 3. Invoke enhanced methods of proxy objects , Get the enhanced object 
        UserService userServiceProxy = (UserService) jdkProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("==================================");
        userServiceProxy.logout();
    }
}

The output is as follows:

JDK Dynamic Proxy: Logic Verification Before Login/Logout......
User Login...
JDK Dynamic Agent: Log printing after login/logout......
==================================
JDK Dynamic Proxy: Logic Verification Before Login/Logout......
User launch login...
JDK Dynamic Agent: Log printing after login/logout......

CGLIB Dynamic Agent

The code is as follows:


/**
 * @author csp
 * @date 2021-06-03
 */
public class CglibProxyFactory implements MethodInterceptor {
    //  Target object ( Proxy object )
    private Object target;
    //  Pass the target object using the constructor 
    public CglibProxyFactory(Object target) {
        super();
        this.target = target;
    }
    /**
     *  Create a proxy object 
     *
     * @return
     */
    public Object createProxy() {
        // 1. Create Enhancer
        Enhancer enhancer = new Enhancer();
        // 2. Object of the target object class
        enhancer.setSuperclass(target.getClass());
        // 3. Set callback action 
        enhancer.setCallback(this);
        return enhancer.create();
    }
    /**
     *  A way to actually perform proxy enhancements 
     * @param o  Proxy object 
     * @param method  Methods to Enhance 
     * @param objects  Parameters to enhance the method 
     * @param methodProxy  Proxy for the method to be enhanced 
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib  Dynamic proxy: login / Logic check before logout ......");
        Object invoke = method.invoke(target, objects);
        System.out.println("cglib  Dynamic proxy: login / Log print after logout ......");
        return invoke;
    }
    public static void main(String[] args) {
        // 1. Create an object 
        UserServiceImpl userService = new UserServiceImpl();
        // 2. Create a proxy object 
        CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
        // 3. Invoke enhanced methods of proxy objects , Get the enhanced object 
        UserService userServiceProxy = (UserService) cglibProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("==================================");
        userServiceProxy.logout();
    }
}

The test results are as follows:

cglib Dynamic Proxy: Logic Verification Before Login/Logout......
User Login...
cglib Dynamic Agent: Log printing after login/logout......
==================================
cglib Dynamic Proxy: Logic Verification Before Login/Logout......
User launch login...
cglib Dynamic Agent: Log printing after login/logout......

Question 1: What is the difference between JDK dynamic agent and CGLIB dynamic agent?

JDK dynamic proxy essentially implements the interface of the proxy object, while CGLib essentially inherits the proxy object and covers the methods in it.

② JDK dynamic proxy can only generate proxies for classes that implement interfaces, while CGLib does not have this restriction. However, because CGLib uses an inherited implementation, CGLib cannot set the final Class, private Methods and static Method for proxy.

③ JDK dynamic agent is built in JDK, and CGLib dynamic agent needs to be introduced into the third party jar Bag.

④ In calling proxy methods, JDK dynamic proxy is called through reflection mechanism, and CGLib is called directly through FastClass mechanism. (After reading an article, it is introduced that the simple understanding of FastClass is to use an index subscript as a reference, which can directly locate the method to be called and call it)

In terms of performance, before JDK1.7, CGLib was faster than JDK in execution efficiency due to the use of FastClass mechanism. However, with the continuous optimization of JDK dynamic proxy, JDK dynamic proxy has been obviously faster than CGLib since JDK 1.7.

Interview 2: Why can JDK dynamic proxies only generate proxies for classes that implement interfaces?

The fundamental reason is that the class generated by JDK dynamic proxy has inherited the Proxy class, so it is no longer possible to use inheritance to proxy the class.

Summarize


Related articles: