Reflection and dynamic proxy
The proxy pattern
Proxy schema definition:
The proxy pattern provides a proxy or placeholder for another object to control access to that object.
Why proxy mode is used:
The proxy pattern is used to create representative objects that control access to real objects, which can be remote objects, expensive objects to create, or objects that require security control.
In simple terms, we use proxy objects instead of real objects to provide additional functionality and extend the functionality of the target object without modifying the real object.
Take real life as an example: when a defendant is interviewed by a judge, he commissions a lawyer to take his place. The representative object here is the lawyer, the real object is the defendant. The lawyer asked the defendant privately after further explaining the judge’s question in accordance with his professional knowledge. After the suspect talks privately to his lawyer, the lawyer relies on his answering skills to explain to the judge.
The proxy mode has two implementation modes: static proxy and dynamic proxy.
Static agent
Static proxies prepare interfaces, delegate classes, and proxy classes before the program runsThe bytecode
File).
To print “Hello, world!” For example, the static proxy implementation steps are as follows:
- Define an interface
interface HelloWordService {
void printHelloWorld(a);
}
Copy the code
- The delegate class implements this interface
class HelloWorldServiceImpl implements HelloWordService {
@Override
public void printHelloWorld(a) {
System.out.println("Hello, world!"); }}Copy the code
- Proxy classes also implement this interface
class HelloWorldProxy implements HelloWordService {
private final HelloWordService helloWorldService;
public HelloWorldProxy(HelloWordService helloWorldService) {
this.helloWorldService = helloWorldService;
}
@Override
public void printHelloWorld(a) {
System.out.println("I'm here to do something as an agent.");
helloWorldService.printHelloWorld();
System.out.println("One last act as agent."); }}Copy the code
- The delegate object is injected into the proxy object and the corresponding method of the delegate object is called in the corresponding method of the proxy object
public class Main {
public static void main(String[] args) {
HelloWordService helloWordService = new HelloWorldServiceImpl();
HelloWordService helloWordProxy = newHelloWorldProxy(helloWordService); helloWordProxy.printHelloWorld(); }}Copy the code
After running, the console prints output
As your agent, I’ll do something first. To do one last thing as an agent
In static proxies, a separate proxy class is written for each delegate class, and enhancements to each method of the delegate object are done manually. Once new methods are added to the interface, both the delegate and proxy classes are modified. So we need more flexible dynamic proxies.
JDK dynamic proxy
Dynamic proxies dynamically generate proxy class bytecodes while the program is running and load them into the JVM.
Dynamic proxies are more flexible than static proxies. We only need to define interfaces and implementation classes; we don’t need to write proxy classes.
The JDK provides the InvocationHandler interface Proxy class to implement dynamic proxies.
The Proxy class
The most common methods in the Proxy class are:
public static Object newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h)
Copy the code
The static method takes the following parameters:
- Loader: class loader used to load proxy objects
- Interfaces: Interfaces implemented by a delegate class and passed in at least one interface
- H: Implements an instance of the InvocationHandler interface for logical processing
InvocationHandler interface
From the third argument, we must implement the InvocationHandler interface. When we invoke a method on a dynamic proxy object, the JVM invokes the Invoke method of the implementation class to handle the corresponding logic.
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
Copy the code
The parameters of this method are:
- Proxy: dynamically generated proxy class instance by the JVM
- Method: The method class instance that corresponds to the method calling the proxy class instance
- Args: arguments to invoke the proxy class instance method
Use of JDK dynamic proxies
Continue to print “Hello, world!” For example, the implementation steps of dynamic proxy are as follows:
- Defines the interface
interface HelloWordService {
void printHelloWorld(a);
}
Copy the code
- The delegate class implements this interface
class HelloWorldServiceImpl implements HelloWordService {
@Override
public void printHelloWorld(a) {
System.out.println("Hello, world!"); }}Copy the code
- Define a JDK dynamic proxy class that calls native methods in the Invoke method and customizes the logic handling
class SimpleInvocationHandler implements InvocationHandler {
private final Object target;
public SimpleInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("I'm here to do something as an agent.");
Object result = method.invoke(target, args);
System.out.println("One last act as agent.");
returnresult; }}Copy the code
- Create a Proxy object using the proxy. newProxyInstance method
// Define a static factory class that produces proxy objects
class ProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T getProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
newSimpleInvocationHandler(target) ); }}public class Main {
public static void main(String[] args) {
// Through the proxy factory, produce the proxy class instance
HelloWordService serviceProxy =
ProxyFactory.getProxy(newHelloWorldServiceImpl()); serviceProxy.printHelloWorld(); }}Copy the code
After running, the console prints output
As your agent, I’ll do something first. To do one last thing as an agent
conclusion
- The proxy mode allows you to extend the functionality of the target object by providing additional functionality without modifying the real object
- Static proxies prepare interfaces, delegate classes, and proxy classes before the program runs
The bytecode
File) - Dynamic proxies dynamically generate proxy class bytecodes while the program is running and load them into the JVM