• 周六. 10 月 5th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

Java static proxy and dynamic proxy

King Wang

1 月 3, 2022

List of articles

        • Static proxy
        • A dynamic proxy
          • JDK A dynamic proxy
          • CGLIB A dynamic proxy
        • summary
          • JDK Dynamic proxy sum CGLIB Dynamic proxy differences
          • Advantages and disadvantages of each

What is agency ? It is commonly understood that the agent is the middle layer or the middle object , With an agent, you don’t need a client class to interact with a delegate class directly . Then why do we need an agent , There are two main factors to consider :

  • Can hide the implementation of delegate class
  • Achieve a decoupling with the delegate class , Without modifying the delegate class , Realize the processing of some functions .

such as : We usually buy goods , Usually go to the supermarket , Instead of going to the factory where the goods are made . We don’t care how the goods are produced in the factory , It’s just about buying things . In this case , Supermarket is a kind of agent , As the middle tier to supply our goods . And factory is the kind of commission we talk about , We belong to the customer group .

alike , In programming languages , There are many scenarios where proxy classes are also required , Because the delegate class itself doesn’t want its client group to see its internal implementation , So the call is done through the proxy class . For example, remote RPC When the service is invoked , We do this through proxy classes , Instead of direct delegation class , There’s more Spring Medium AOP The aspect also generates a proxy class for the aspect and so on .

As agent class , Can be divided into : Static agents and dynamic agents , Dynamic agents have JDK Dynamic proxy sum CGLIB A dynamic proxy , Each agent has its own advantages and disadvantages , You can’t just compare good with bad , Just like programming languages , There is no absolute difference between good and bad , The right thing is the best .

Static proxy

First, define the interface and its implementation class , Then define the proxy object of the interface , And inject an instance of the interface into the proxy object , Then you can call the real implementation class through the proxy object . The relationship of static agents is established during compilation . In view of this treatment , So static proxies are only suitable for situations where there are few and certain classes of proxies . such as , Packaging of goods purchased , Decouple customer and delegation class .

  1. Defining interfaces

    public interface IService {
    
    /**
    * Defining methods in an interface
    * @param userName
    * @return
    */
    String sayHello(String userName);
    }
    
  2. Define interface implementation

    // Implementation of delegate class 
    public class IServiceImpl implements IService {
    
    @Override
    public String sayHello(String userName) {
    
    System.out.println("HelloService " + userName);
    return "HelloService " + userName;
    }
    }
    
  3. Define proxy class

    public class ProxyHello implements IService {
    
    /**
    * Injection interface instance
    */
    private IService iService = new IServiceImpl();
    /**
    * @param userName
    * @return
    */
    @Override
    public String sayHello(String userName) {
    
    // Proxy objects can be wrapped here 
    System.out.println(" Proxy objects are processed accordingly ");
    return iService.sayHello(userName);
    }
    }
    
  4. Agent class test

    public class TestProxy {
    
    public static void main(String[] args) {
    
    ProxyHello proxyHello=new ProxyHello();
    proxyHello.sayHello("FEEL");
    }
    }
    
  5. Running results

    Proxy objects are processed accordingly
    HelloService FEEL

A dynamic proxy

That is, the agent created by the program during running .

There are usually two approaches to dynamic agents :

  • Through the interface JDK A dynamic proxy
  • By inheriting the CGLIB A dynamic proxy
JDK A dynamic proxy

Java Dynamic agent mainly involves java.lang.reflect.Proxy and java.lang.reflect.InvocationHandler Two classes . And we just need one implementation InvocationHandler Intermediate class of interface . There is only one method in this interface invoke, as follows :

public interface InvocationHandler {

/**
* Call processing
* @param proxy Proxy class object
* @param method Methods of the concrete called proxy class
* @param args Parameters of proxy class methods
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

The call to all the methods in the processing class becomes to invoke Method call , So we can invoke Add unified processing logic to method ( It can also be based on method Parameter judgment method ). Intermediate class ( Realization InvocationHandler Class ) There is a delegate class object reference , stay invoke Method to invoke the corresponding method of delegate class object , Hold delegate class object references through this aggregation , External pairs invoke All of the calls to the delegate class object .

actually , Intermediate class and principal class constitute static agent relationship , In this relationship , Intermediate class is agent class , Delegate class is delegate class . Then the agent class and the intermediate class form a static agent relationship , In this relationship , Intermediate class is delegate class , A proxy class is a proxy class . in other words , Dynamic agent relationship consists of two groups of static agent relationships , That’s how dynamic agents work .

Let’s take a look at one JDK Examples of dynamic agents :

  1. Interface definition
public interface IService {

/**
* @param userName
* @return
*/
String sayHello(String userName);
/**
* @param userName
* @return
*/
String sayLing(String userName);
}
  1. Interface implementation
public class IServiceImpl implements IService {

@Override
public String sayHello(String userName) {

System.out.println("HelloService " + userName);
return "HelloService " + userName;
}
@Override
public String sayLing(String userName) {

System.out.println(userName+" Ling");
return userName+ " Ling";
}
}
  1. Agent execution class
public class JavaProxyInvocationHandler implements InvocationHandler {

/**
* Intermediate class holds delegate class object reference
*/
private Object object;
/**
* Incoming delegate class object
*
* @param o Delegate class object
*/
public JavaProxyInvocationHandler(Object o) {

this.object = o;
}
/**
* Dynamically generate proxy class objects ,Proxy.newProxyInstance
*
* @return Return proxy class instance
*/
public Object newProxyInstance() {

return Proxy.newProxyInstance(
// Specifies the classloader for the proxy object 
object.getClass().getClassLoader(),
// Interface to be implemented by proxy class object 
object.getClass().getInterfaces(),
// The actual handler of the method call , Method calls to proxy objects are forwarded here 
this);
}
/**
* @param proxy Proxy object
* @param method Proxy method
* @param args Method parameter
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("Invoke before");
Object result = method.invoke(object, args);
System.out.println("Invoke after");
return result;
}
}
  1. Test class
public class TestJavaProxy {

public static void main(String[] args) {

JavaProxyInvocationHandler proxyInvocationHandler
= new JavaProxyInvocationHandler(new IServiceImpl());
IService iService = (IService) proxyInvocationHandler.newProxyInstance();
iService.sayHello("Gutter");
iService.sayLing("Lin");
}
}
  1. Output results

Invoke before
HelloService Gutter
Invoke after
Invoke before
Lin Ling
Invoke after

Brief description :

call Proxy Class newProxyInstance Method to get an instance of a proxy class . The proxy class implements the specified interface and distributes the method calls to the specified call handler .

Then call the method of the proxy class through the instance of the proxy class , Method calls to proxy classes call intermediate classes ( Realized invocationHandler The class of the interface ) Of invoke Method , In this method, the corresponding method of calling the delegate class is invoked. .

The main characteristic of the dynamic agent is :

The dynamically generated proxy class and delegate class implement the same interface . Its interior is actually realized through reflection mechanism , I.e. a known object , Dynamically call its methods at run time , And add your own processing when calling .

Here is Proxy.newProxyInstance Source code

Proxy.newProxyInstance() Dynamic generation of proxy class objects through reflection mechanism , Create a proxy class for the interface , The proxy class implements the interface .

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {

// Check null pointer 
Objects.requireNonNull(h);
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Get all constructors
*/
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
return newProxyInstance(caller, cons, h);
}
private static Object newProxyInstance(Class<?> caller,
// null if no SecurityManager
Constructor<?> cons,
InvocationHandler h) {

/*
* Invoke its constructor with the designated invocation handler.
*/
try {

if (caller != null) {

checkNewProxyPermission(caller, cons.getDeclaringClass());
}
// Returns the created proxy class Class Instance object of 
return cons.newInstance(new Object[]{
h});
} catch (IllegalAccessException | InstantiationException e) {

throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {

Throwable t = e.getCause();
if (t instanceof RuntimeException) {

throw (RuntimeException) t;
} else {

throw new InternalError(t.g(), t);
}
}
}
CGLIB A dynamic proxy

JDK Dynamic agents need to rely on interface implementation , When there is no interface but a class , Another dynamic proxy technology is needed CGLIB A dynamic proxy . Because it is a third-party framework implementation , So in maven It needs to be introduced into the project pom file

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>

CGLIB Agent is to implement agent for class , The principle is to generate a subclass of the specified delegate class and rewrite its methods to implement the proxy . Proxy class objects are created by Enhancer Class to create . The pattern of creating a dynamic proxy class is as follows :

  1. Find all non objects of the target class final Of public Method of type
  2. Convert method definition to bytecode
  3. Convert bytecode to the corresponding proxy’s Class object , And get the instance object of the proxy class through reflection
  4. Realization MethodInterceptor Interface , Used to handle methods on proxy classes

summary

Static agents are easy to understand , The classes that need to be proxied and proxy classes implement from the same interface , Then the real implementation class is called in the proxy class. , And the relationship of static agents is determined during compilation . The dynamic agent relationship is determined during runtime . Simple implementation of static agent , It is suitable for the case where there are few and definite proxy classes , Dynamic agents provide more flexibility .

JDK The proxy class used by dynamic proxy is only used when the program calls the proxy class object JVM Actually creating ,JVM According to what was passed in Business implementation class object as well as Method name , Dynamically create a proxy class’s class File and executed by bytecode engine , Then make method calls through the proxy class object . What we have to do , You can specify the pre and post operations of the agent class .

Both static and dynamic agents are based on interfaces , And for those who do not provide an interface but only an implementation class , You can only choose CGLIB Dynamic agent

JDK Dynamic proxy sum CGLIB Dynamic proxy differences
  • JDK Dynamic agent based on Java Reflection mechanism implementation , You have to implement the business class of the interface to generate the proxy object in this way .
  • CGLIB Dynamic agent based on ASM The framework is implemented by generating subclasses of business classes .
  • JDK The advantage of dynamic agent is to minimize dependency , This means simplified development and maintenance . And can follow JDK Version update , Simple code implementation . be based on CGLIB The advantage of the framework is that it does not need to implement interfaces , Achieve proxy class non-invasive , We just need to manipulate the classes of our relationship , No need to increase workload for other related classes , High performance .
Advantages and disadvantages of each
  • JDK Dynamic agent solves the problem of redundant agent implementation class in static agent , But it must be implemented based on the interface , If there is no interface , An exception will be thrown .
  • CGLIB Dynamic agents do not need interfaces , It adopts byte code enhancement technology , Good performance , But it’s relatively difficult to understand .

发表回复