If there are dynamic proxies, there must be static proxies. Static proxies refer to static proxies in design mode
Function: Same as static proxy, but dynamic proxy solves the problem of one static proxy, only one type of target object
The following roles are involved in JDK dynamic proxies:
- Interface of the target class
- The target class target
- Handle template handlers
- Dynamic proxy classes that are generated in memory
- java.lang.reflect.Proxy
Let’s cut the crap and start with the code
The instance
The interface of the target class
To have JDK dynamic proxies, your classes must implement interfaces
/** * public interface UserService {Boolean login(String userName, String password); }Copy the code
The target class
Note that methods to be proxied must be implemented from the interface
/** * UserServiceImpl is the target class, Public class UserServiceImpl implements UserService {@override public Boolean. */ UserServiceImpl implements UserService login(String userName, String password) { System.out.println("Check account");
return false; }}Copy the code
Handle template classes
This is an implementation class for InvocationHandler
Here, we define a template that prints logs before and after the target method.
LogHandler’s target Object can be of any type, not just UserService. This way LogHandler can output logs before and after any method of any type, so it is called a processing template
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * This is a custom processing template that will be printed before and after the target methodlog*/ private UserService implements InvocationHandler {private UserService implements InvocationHandler; private Object target; Public LogHandler(Object target) {this.target = target; } /** * defines an output before and after the target method is executedlog@override Public Object Invoke (Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target, args); after();return result;
}
private void before() {
System.out.println("Log output before calling target method");
}
private void after() {
System.out.println("Log output after calling target method"); }}Copy the code
There is a question here, who calls the invoke() method and what are the three arguments in the method (although I have already written that down)?
The test class
The three classes above make up the smallest unit of JDK dynamic proxies. Next, write test classes that use JDK dynamic proxies
import java.lang.reflect.Proxy; Public static void main(String[] args) {// Create a target object UserService userServiceImpl = new userServiceImpl (); LogHandler userServiceLogHandler = new LogHandler(userServiceImpl); /** * proxy. newProxyInstance dynamically generates a Proxy Class based on the Class loader of the target object, the Class of the interface, and the processing template of the target object. It implements the login method of the UserService interface */ UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userServiceImpl.getClass().getClassLoader(), new Class[]{UserService.class}, userServiceLogHandler); userServiceProxy.login("wqlm"."123");
System.out.println("\n The name of the proxy class is + userServiceProxy.getClass().getName());
}
Copy the code
The output
/ Library/Java/jdk1.8.0 _201 / Contents/Home/bin/Java... Output before calling the target methodlogOutput after the verification account calls the target methodlogThe proxy class is named com.sun.proxy.$Proxy0
Process finished with exit code 0
Copy the code
java.lang.reflect.Proxy
This class is used in test methods to generate proxy objects!
This is the most important class in the JDK dynamic proxy, and we can generate a proxy class with the newProxyInstance method
public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentExceptionCopy the code
As above, newProxyInstance takes three parameters
- ClassLoader, the ClassLoader for target class
- Class
[], the Class of the target Class Interface - InvocationHandler, which handles the template class Handler
The process for generating a proxy class is as follows
- The proxy.newProxyinstance method, passed to it with the Class
[] interfaces, InvocationHandler h generates the bytecode of the proxy class - The Proxy loads the bytecode of the generated Proxy class using arguments passed to it (ClassLoader)
- Returns the object of the loaded proxy class
Dynamically generated proxy classes
Since the proxy classes are dynamically generated at run time, there are no.java files, and there are no.class files. $Proxy0; com.sun. Proxy.$Proxy0; com.sun
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class<? >[]{userServiceProxy.getClass()}); String pathDir ="/Users/wqlm/Desktop";
String path = "/$Proxy0.class";
File f = new File(pathDir);
path = f.getAbsolutePath() + path;
f = new File(path);
if (f.exists()) {
f.delete();
}
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
Copy the code
Get the bytecode stream and, after decompilation, get the approximate.java file. The following is the processed. Java file for the proxy class
import com.example.demo.service.UserService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; /** * The Proxy class inherits the Proxy and implements the target interface UserService */ public Final class$Proxy0 extends Proxy implements UserService {
private static Method m3;
static {
try {
m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("login",
new Class[]{Class.forName("java.lang.String"), Class.forName("java.lang.String")}); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); }} // When initialized, the processing template is passed to the parent class public$Proxy0(InvocationHandler var1) { super(var1); } /** * This is the proxy method, as you can see, it is the same as the invoke method that calls the parent's processing template, and then calls itself, */ public final Boolean login(String var1, String var2) {try {return((Boolean) super.h.invoke(this, m3, new Object[]{var1, var2})).booleanValue(); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); }}}Copy the code
- The dynamic Proxy class implements the interface of the target class and implements the method in the interface by invoking the invoke () method of the parent class — Proxy H
- NewProxyInstance (ClassLoader loader, Class
[] interfaces, InvocationHandler h) was introduced into the third parameter of InvocationHandler object - The target object is invoked by reflection in InvocationHandler.invoke ()
Remember the question left in the handling template section — “Who calls invoke() and what are the three arguments in the method?” Now we know that it is the proxy class that calls Invoke () and passes three arguments: itself (the proxy object itself), the target method, and the argument list
conclusion
JDK dynamic proxy
Features: Instead of explicitly implementing the same interface as the target class, this implementation is deferred to the JVM when the program is called.
- That is, create dynamic proxy classes and instances as they are used
- Static proxies specify the same interface as the target when the proxy class is implemented
Advantages: A single proxy class can proxy multiple target classes, avoiding duplicate and redundant code
disadvantages
- Compared with static proxy, the efficiency is low. Static proxies call methods of the target object directly, while dynamic proxies require classes and objects to call methods of the target object indirectly through Java reflection
- Application scenarios are limited. Each Proxy class inherits java.lang.Reflect. Proxy, and Java supports only single inheritance, so you cannot create a Proxy class for a class, but only for an interface. That is, dynamic proxies can only proxy classes that implement the interface.
Application scenarios
- A large number of objects need to be propped up. If the number of proxies is small, you are advised to use static proxies
- When programming for facets
Differences from static proxies
Design patterns | When the proxy class is created | The principle of | The efficiency of | Number of target classes that can be proxied |
---|---|---|---|---|
A dynamic proxy | Dynamically created at runtime | reflection | low | Can proxy multiple target classes |
Static agent | Before running, show created | / | high | Only one target class can be proxy |