Basics: It requires object-oriented design ideas, polymorphic ideas, and reflection ideas;
The emergence of Java dynamic proxy mechanism allows Java developers to dynamically obtain proxy classes without having to manually write proxy classes. The proxy class is responsible for dispatching all method calls to the delegate object to reflect execution. During the dispatch execution process, developers can also adjust the delegate object and its functions as needed. This is a very flexible and flexible proxy framework. By reading this article, readers will have a deeper understanding of Java dynamic proxy mechanism. This article first analyzes the code based on the operating mechanism and characteristics of Java dynamic proxy and deduces the internal implementation of dynamic generation classes.
Basic concepts and classification of agent model
Proxy mode: Provides a proxy for other objects to control access to this object. The proxy object acts as an intermediary, and can remove services or add additional services, or quote others: "The proxy class is responsible for pre-processing messages for the delegate class, filtering messages and forwarding messages, and performing subsequent processing after the message is executed by the delegate class."
Application scenarios of agent mode in development
Remote proxy: Provides LAN representative objects for objects of different geographic regions.
Virtual agent: delay objects that consume a lot of resources as needed and create them when they are really needed. For example, the text is displayed first and then the picture is displayed on the web page.
Protection Agent: Controls access rights of different users. For example: Only after the customer registration is successful can add, delete, modify and check operations be performed.
Smart reference agent: Provides additional services to the target agent.
How to implement the proxy mode
Which one is better to implement dynamic proxy using inheritance and aggregation!
public interface Moveable {public void move();}public class Car implements Moveable{@Override public void move() {try {Thread.sleep(new Random().nextint(1000));System.out.println("...driving...");}catch(InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}}}public class Car2 extends Car{@Override public void move() {//Separate the code, increase the business logic long startTime=System.currentTimeMillis();System.out.println("The car starts to drive...");super.move();long endTime=System.currentTimeMillis();System.out.println("The car ends to drive...Time: "+(endTime-startTime)+"ms");}}Inheritance method to implement proxy
Moveablecar2=newCar2();
car2.move();
Aggregation method implements proxy
Carcar=newCar();
Moveablem=newCar3(car);
m.move();
Summarize
The inheritance method is not flexible enough. When the functions are superimposed, you can only expand the proxy class bloatedly;
Using aggregation, agents can be passed on to each other, and a proxy can be flexibly combined;
public class CarLogProxy extends Car{@Override public void move() {//Separate the code and increase the business logic long startTime=System.currentTimeMillis();System.out.println("Login start...");super.move();long endTime=System.currentTimeMillis();System.out.println("Login end...");}}public class CarTimeProxy implements Moveable {public CarTimeProxy(Car car) {super();this.car=car;}private Carcar;@Override public void move() {//Separate the code and add business logic long startTime=System.currentTimeMillis();System.out.println("The car starts to drive...");car.move();long endTime=System.currentTimeMillis();System.out.println("The car ends to drive... Time: "+(endTime-startTime)+"ms");}}@Test: Car car =new Car();CarTimeProxy ctp=new CarTimeProxy(car);CarLogProxy clp=new CarLogProxy(ctp);clp.move();//You can also pass proxy instances to each other through interfaces CarLogProxy clp1=new CarLogProxy(car);CarTimeProxy ctp1=new CarTimeProxy(clp1);ctp1.move();JDK dynamic proxy and CGlib dynamic proxy
JDK dynamic proxy
Agent implementation
What should be done if different objects want to implement the proxy class with the same function?
At this time, you can try to integrate it in the same proxy class-------Dynamic proxy: implementing proxy for different classes/different methods;
The general process is as follows:
The Java dynamic proxy class is located under the java.lang.reflect package, which generally mainly involves the following two classes:
(1)InterfaceInvocationHandler: Only one method is defined in this interface Publicobjectinvoke(Objectobj,Methodmethod,Object[]args)
obj: Generally refers to the proxy class
method: is the proxy method
args is an array of parameters for this method.
This abstract method is implemented dynamically in the proxy class.
(2)Proxy: This class is a dynamic proxy class
statixObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)
Returns an instance of the glycoside class, and the returned proxy class can be used as the proxy class (you can use the method declared in the interface by the proxy class);
Implementation example:
@ TimeHandler public class TimeHandler implements InvocationHandler {public TimeHandler(Object target) {super();this.target = target;}private Objecttarget;/* * Parameters: * proxy proxy object* method method of proxy object* args parameter* * Return value: * Object method return value*/@Override public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {long startTime=System.currentTimeMillis();System.out.println("The car starts to drive...");method.invoke(target);long endTime=System.currentTimeMillis();System.out.println("The car ends to drive...Time: "+(endTime-startTime)+"ms");return null;}} @The interface of the proxy class public interface Moveable { public void move();}@The proxy class public class Car implements Moveable{@Override public void move() {try {Thread.sleep(new Random().nextint(1000));System.out.println("...driving...");}catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}}}@test
public class Test { /** * JDk dynamic proxy test class*/ public static void main(String[] args) { Car car=new Car(); InvocationHandler h=new TimeHandler(car); Class<?>cls=car.getClass(); /* * loader class loader* interfaces Implementing interface* h InvocationHandler */ Moveable m=(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h); m.move(); } }&&Test results
Summary
The DynamicProxy is such a class:
It is a class generated at runtime. This class needs to implement a set of interfaces. When using dynamic proxy classes, the InvocationHandler interface must be implemented.
General steps for JDK dynamic proxy
1. Create a class that implements the interface InvocationHandler, which must implement invoke()
2. Create the proxy class and interface
3. Call Proxy's static method to create a proxy class
newProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)
4. Call methods through proxy
Implementation of CGlib Dynamic Proxy
Agent implementation
@Introducing cglib-node-2.2.jar package
@CglibProxy intercept class implements interface MethodIntercept: Rewrite intercept method
public class CglibProxy implements MethodInterceptor {private Enhancerenhancer=new Enhancer();public Object getProxy(Class cl) {//Set the class that creates subclass enhancer.setSuperclass(cl);enhancer.setCallback(this);return enhancer.create();}/* * Intercept all target class methods* object Instance of target class* m Reflection object of target method* args method* proxy instance of proxy class* */@Override public Object intercept(Object obj, Method m,Object[] args, MethodProxy proxy)throws Throwable {System.out.println("Login start...");//The proxy class calls the parent class's method proxy.invokeSuper(obj, args);System.out.println("Login end...");return null;}}@Proxy class Train
public class Train { public void move() { System.out.println("The train is driving..."); } }@Test class
public class Test { /** * cglibProxy dynamic proxy test class*/ public static void main(String[] args) { CglibProxy proxy=new CglibProxy(); Train t=(Train)proxy.getProxy(Train.class); t.move(); } }##Test results:
Summary
General steps to implement dynamic proxy using CglibProxy
1. Create a class to implement the interface MethodInterceptor and override the intercept method
2. Create a proxy class
3. Call the proxy class custom method to get a proxy instance
4. Call the method that needs to be executed by the proxy instance
Comparative summary
JDK dynamic proxy
1. Only proxy classes that implement interfaces
2. Classes without an interface cannot implement dynamic proxy for JDK
CGlib Dynamic Proxy
1. Implementing proxy for classes
2. Generate a subclass to the execution target class, and use method intercepting technology to intercept all parent class methods calls.
Simulate agent generation steps
Ideas:
Implementation function: Return the proxy object through Proxy's newProxyInstance
1. Declare a piece of source code (dynamic generation agent)
2. Compile the source code (JDKCompilerAPI) to generate new classes (proxy classes)
3. Load this class into memory and generate a new object (proxy object)
4. Return the proxy object
Improve dynamic proxy implementation
First, we get the system compiler, get the file manager through the compiler, and then get the file. The compiler then performs the compilation task. After completing the compilation, we load the class file into the class loader, obtain the instance through the constructor method, and then call newInstance() to receive an instance of an object.
(1) Get the compiler JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();
(2) File manager StandardJavaFileManagerfileMgr=Compiler.getStandardFileManager(null,null,null);
(3) Get the file Iterableunits=fileMgr.getJavaFileObjects(filename);
(4) Compilation task CompilationTaskt=compiler.getTask(null,fileMgr,null,null,null,null,units);
(5) Load to memory
ClassLoadercl=ClassLoader.getSystemClassLoader();
Classc=cl.loadClass("com.imooc.proxy.$Proxy0");
(6) Construct an instance through the constructor of the proxy object
Constructorctr=c.getConstructor(infce);
ctr.newInstance(newCar());
--------
As mentioned above, the internal business logic is hard-coded. How to implement the real dynamic proxy and dynamically designated business logic?
1. You need to create a transaction processor. First, you create an interface, that is, InvocationHandler. In order to simulate JDK, the name of the interface is the same as the name of the JDK transaction processor. You also write a method called invoke(), which is used to represent a certain method of an object for business processing. Therefore, you need to pass a certain object and the method of the object as parameters of the invoke() method. Invoke(Objectobj, Methodmethod), the method used as a parameter to java reflection, and this package needs to be introduced. In this way, the InvocationHandler interface is completed.
2. Create transaction processing implementation classes, such as TimerProxy, to implement the InvocationHandler interface, so the structure becomes
――――――TimerProxyimplementsInvocationHandler{ ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――�You need to pass the target object in. If you don’t have parameters, you can not write parameters. Create a proxy object construction method and initialize the target object.
3. In the newProxyInstance() method of the Proxy class, in addition to using the target Class interface as a parameter, you also need to pass the transaction processor InvocationHandler, and then change the hard-coded part of the created instance object and use the transaction processor method to replace it. The difficulty lies in the splicing of strings.
Summarize
In our project, the agent pattern has its own practical significance. For example, if we want to call a class under a certain jar package, we can add some special business logic before calling this class. This method is also called AOP-oriented programming. (Add additional functions without changing the original functions.)
The above is all the detailed explanation of Java dynamic proxy (design pattern) code in this article, I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!