There is a certain correlation between reflection and dynamic proxy, but simply saying that dynamic proxy is realized by reflection mechanism is not comprehensive and inaccurate. Dynamic proxy is a functional behavior, and there are many ways to achieve it. To understand the above sentence, see below.
A, reflection
Reflection is a basic feature provided by the Java language that gives programs the ability to introspect (the official term) at runtime. Reflection allows us to manipulate classes or objects directly, such as getting the class definition of an object, getting the properties and methods declared by the class, calling methods or constructing objects, and even modifying the class definition at run time.
1. Get the Class object
There are three ways to get class objects:
- With forName() -> example: class.forname (“PeopleImpl”)
- GetClass () -> Example: new PeopleImpl().getClass()
- Class -> Example: PeopleImp.class
2, class common methods
- GetName () : Get the full method of the class;
- GetSuperclass () : Gets the parent class of the class;
- NewInstance () : Creates instance objects;
- GetFields () : Gets all attributes of the public modifier of the current class and its parent;
- GetDeclaredFields () : Gets all declared properties of the current class (excluding the parent class);
- GetMethod () : Gets all methods of the public modifier of the current class and its parent class;
- GetDeclaredMethods () : get the current class (does not contain the superclass) statement of all the methods;
More ways: icdn.apigo.cn/blog/class-…
Class method calls
Reflection calls methods in a class using the key “invoke()” method, which can be divided into three types:
- Static method calls
- Normal method call
- Private method call
The implementation code of each call and the common code part of each call are shown as follows:
// This code is public code
interface People {
int parentAge = 18;
public void sayHi(String name);
}
class PeopleImpl implements People {
private String privSex = "Male";
public String race = "Han";
@Override
public void sayHi(String name) {
System.out.println("hello," + name);
}
private void prvSayHi(a) {
System.out.println("prvSayHi~");
}
public static void getSex(a) {
System.out.println("18"); }}Copy the code
3.1 Static method Calls
// Core code (omits the exception declaration)
public static void main(String[] args) {
Class myClass = Class.forName("example.PeopleImpl");
// Call the static method
Method getSex = myClass.getMethod("getSex");
getSex.invoke(myClass);
}
Copy the code
Static method invocation is relatively simple, use getMethod(xx) to get the corresponding method, and use invoke(xx) directly.
3.2 Ordinary method calls
For ordinary non-static method invocation, you need to obtain a class example through “newInstance()”. The core code is as follows:
Class myClass = Class.forName("example.PeopleImpl");
Object object = myClass.newInstance();
Method method = myClass.getMethod("sayHi",String.class);
method.invoke(object,"Wang");
Copy the code
GetMethod gets a method that can declare the type of argument to be passed.
3.3 Calling private Methods
To call a private method, you must use getDeclaredMethod(xx) to get all the methods of the class.
Class myClass = Class.forName("example.PeopleImpl");
Object object = myClass.newInstance();
Method privSayHi = myClass.getDeclaredMethod("privSayHi");
privSayHi.setAccessible(true); // Modify access restrictions
privSayHi.invoke(object);
Copy the code
With the exception of getDeclaredMethod(xx), the key to calling a private method is to set the setAccessible(True) property and change the access limit so that the call can be made.
4, summarize
1. The core methods in reflection are newInstance() to obtain class instances and getMethod(..). Get method, use invoke(..) Make a method call, using setAccessible to modify the access limits of private variables/methods.
2. The difference between “Declared” and “Declared” when obtaining attributes/methods is that methods or attributes with Declared modifiers can obtain all methods or attributes of the class (private to public) but cannot obtain any information of the parent class. Methods or properties that are not modifiable can only get methods or properties that are modifiable by public and can get parent classes such as getMethod(..). And getDeclaredMethod (..) .
Dynamic proxy
Dynamic proxy is a convenient mechanism for dynamically building proxies and handling proxy method calls at run time, and many scenarios are done using similar mechanisms, such as AOP for wrapping RPC calls.
Dynamic proxies can be implemented in many ways, such as the JDK’s own dynamic proxies, which make use of the reflection mechanism mentioned above. There are other ways to do this, such as using the rumored higher performance bytecode manipulation mechanisms such as ASM, Cglib (based on ASM), etc.
Problem solved by dynamic proxy?
First, it is a proxy mechanism. If we are familiar with the proxy pattern in design patterns, we know that the proxy can be thought of as a wrapper around the calling target, so that our calls to the object code do not happen directly, but through the proxy. A proxy allows decoupling between the caller and the implementer. For example, RPC calls, via proxies, can provide a more user-friendly interface. You can also do a global interceptor by proxy.
JDK Proxy Dynamic Proxy
JDK Proxy is implemented by implementing the InvocationHandler interface, the code is as follows:
interface Animal {
void eat(a);
}
class Dog implements Animal {
@Override
public void eat(a) {
System.out.println("The dog is eating"); }}class Cat implements Animal {
@Override
public void eat(a) {
System.out.println("The cat is eating"); }}// JDK proxy class
class AnimalProxy implements InvocationHandler {
private Object target; // Proxy object
public Object getInstance(Object target) {
this.target = target;
// Get the proxy object
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before call");
Object result = method.invoke(target, args); // method call
System.out.println("After call");
returnresult; }}public static void main(String[] args) {
// JDK dynamic proxy calls
AnimalProxy proxy = new AnimalProxy();
Animal dogProxy = (Animal) proxy.getInstance(new Dog());
dogProxy.eat();
}
Copy the code
In the code above, we have implemented a dynamic proxy that prints a simple message before and after all requests.
Note: JDK Proxies can only Proxy classes that implement interfaces (even extends inherited classes can’t).
Why can JDK Proxies only Proxy classes that implement interfaces?
This problem from the implementation of dynamic proxy method newProxyInstance source:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h)
throws IllegalArgumentException
{
// omit other code
Copy the code
Look at the first two source parameters:
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class to implement
Copy the code
- Target.getclass ().getClassLoader()
- Interfaces: List of interface implementations of the interface proxy class
So the source of this problem lies in the source code design of the JDK Proxy. If you want to insist on dynamic proxy, the non-interface implementation class will report an error:
Exception in thread “main” java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to xxx
2. Cglib dynamic proxy
The JDK dynamic proxy mechanism can only be used to proxy classes that implement the interface. Cglib implements the proxy for classes. Its principle is to generate a subclass of the specified target class and override the method implementation enhancement.
Additional can directly by Maven version reference, Maven version address: mvnrepository.com/artifact/cg…
This article uses the latest version of Cglib, 3.2.9, and adds the following reference to pom.xml:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId>Copy the code
Cglib code implementation, as follows:
class Panda {
public void eat(a) {
System.out.println("The panda is eating"); }}class CglibProxy implements MethodInterceptor {
private Object target; // Proxy object
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
// Set the parent class to the instance class
enhancer.setSuperclass(this.target.getClass());
// Callback method
enhancer.setCallback(this);
// Create a proxy object
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before call");
Object result = methodProxy.invokeSuper(o, objects); // Perform the method call
System.out.println("After call");
returnresult; }}public static void main(String[] args) {
// CGLIB dynamic proxy invocation
CglibProxy proxy = new CglibProxy();
Panda panda = (Panda)proxy.getInstance(new Panda());
panda.eat();
}
Copy the code
Cglib calls through implementing the Intercept method of the MethodInterceptor interface, invokeSuper is called for dynamic proxy, you can directly perform dynamic proxy for ordinary classes.
JDK Proxy VS Cglib
Advantages of JDK Proxy:
- Minimizing dependencies, reducing dependencies means simplified development and maintenance, JDK support itself, and more reliability;
- Smooth JDK version upgrades, which bytecode libraries often need to be updated to ensure they are usable on new versions;
Advantages of Cglib framework:
- Ordinary classes can be called without implementing an interface;
- High performance;
Conclusion: it is important to note that we are in the selection, performance is not the only consideration, reliability, maintainability, and programming work tend to be more important consideration, after all the standard class library and the threshold of the reflective programming are much lower, also more manageable amount of code, if we compare the different open source project on dynamic proxy development investment, also can see that.
All sample code for this article: github.com/vipstone/ja…
Iv. Reference documents
Java Core Technology Lecture 36: t.cn/EwUJvWA
Java reflection and dynamic proxy: www.cnblogs.com/hanganglin/…
Follow the author’s official account:
If you find this article helpful, buy me a cup of coffee.