Static proxy, the proxy class and the proxied class implement the same interface, and the proxy class also holds a reference to the proxied class. In this way, when we need to call the method of the proxy class, we can do it by calling the method of the proxy class.
Example: Suppose the leader’s job is to hold meetings and evaluate employees.
First define an interface:
package com.sharpcj; public interface IWork { void meeting(); int evaluate(String name); }
Then define the leadership class:
package com.sharpcj; import java.util.Random; public class Leader implements IWork { @Override public void meeting() { System.out.println("领导早上要组织会议"); } @Override public int evaluate(String name) { int score = new Random(System.currentTimeMillis()).nextInt(20) + 80; System.out.println(String.format("领导给%s的考评为%s分", name, score)); return score; } }
Secretary class:
package com.sharpcj; public class Secretary implements IWork { private Leader mLeader; public Secretary(Leader mLeader) { this.mLeader = mLeader; } @Override public void meeting() { System.out.println("秘书先给老板准备材料"); mLeader.metting(); } @Override public int evaluate(String name) { return mLeader.evaluate(name); } }
Test class:
package com.sharpcj; public class TestApp { public static void main(String[] args) { Leader leader = new Leader(); Secretary secretary = new Secretary(leader); secretary.meeting(); secretary.evaluate("Joy"); } }
Execution result:
This code It's very simple. Note that when calling the meeting method of the Secretary
class, we called the meeting method of the Leader
class. Before that, we also expanded this method. At this point, some people may be confused. This seems to be a bit of a decorator pattern. What's the matter?
In fact, there are still many differences between the decorator pattern and the proxy pattern. The Decorator pattern focuses on dynamically adding methods on an object, whereas the Proxy pattern focuses on controlling access to the object. In other words, using the proxy pattern, a proxy class can hide the specific information of an object from its clients. Therefore, when using the proxy pattern, we often create an instance of an object in a proxy class. And, when we use the decorator pattern, our usual approach is to pass the original object as a parameter to the decorator's constructor.
We can summarize these differences in another sentence: using the proxy pattern, the relationship between the proxy and the real object is usually determined at compile time, while the decorator can be recursive at runtime. Ground cover structure.
Let’s first look at the difference between the UML class diagrams of the two:
Agent mode:
Decorator mode:
Both pseudocode:
Agent mode:
Interface Subject { void doAction() } public class RealSubject implements Subject{ @Override public void doAction() {}; } public class Proxy implements Subject{ private RealSubject realSubject; public Proxy(RealSubject realSubject) { //关系在编译时确定 this.realSubject = realSubject; } @Override public void doAction() { …. realSubject.doAction(); …. } }
Decorator pattern;
Interface Component { void doAction() } public class ConcreteComponent implement Component { @Override public void doAction() {}; } public class Decorator implements Component { private Component component; public Decorator(Component component) { //关系在编译时确定 this.component = new component; } public void doAction() { …. component.doAction(); …. } }
In fact, the focus of proxy mode and decorator mode are different. The focus of proxy mode is to clarify the class being proxied. As in the above example, the secretary clearly wants to act for the leader. The decorator pattern focuses on methods of extending classes. The objects of classes that implement the Component interface held by the decorated class are not fixed. That is to say, the decorated class can decorate any object that implements the Component interface based on the parameters passed in during the call. the type.
Dynamic proxy can be divided into JDK dynamic proxy and CGlib dynamic proxy based on different implementation methods.
JDK dynamic proxy: Use the reflection mechanism to generate a class that implements the proxy interface, and call InvokeHandler to process it before calling the specific method.
CGlib dynamic proxy: Use ASM (open source Java bytecode editing library, operating bytecode) open source package to load the class file of the proxy object class and generate it by modifying its bytecode subclass to handle.
Difference: JDK agent can only generate agents for classes that implement interfaces; CGlib implements agents for classes, generates a subclass for the specified class, and overrides the methods in it. This is done by inheriting the class The implementation method cannot proxy the final modified class.
Let’s take the above example as an example:
First, define a class to implement the InvocationHandler
interface and implement invoke Method:
package com.sharpcj; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class WorkInvocationHandler implements InvocationHandler { private Object object; public WorkInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("object: " + object.getClass().getSimpleName()); System.out.println("proxy: " + proxy.getClass().getSimpleName()); if ("meeting".equals(method.getName())) { System.out.println("代理先准备会议材料..."); return method.invoke(object, args); } else if ("evaluate".equals(method.getName())) { if(args[0] instanceof String) { if ("James".equals(args[0])) { System.out.println("James 犯过错误,所以考评分数较低..."); return 70; } } return method.invoke(object, args); } return null; } }
Then create a proxy object through the Proxy.newProxyInstance()
method:
package com.sharpcj; import java.lang.reflect.Proxy; public class TestApp { public static void main(String[] args) { /*Leader leader = new Leader(); Secretary secretary = new Secretary(leader); secretary.meeting(); secretary.evaluate("Joy");*/ Leader leader = new Leader(); IWork proxy = (IWork) Proxy.newProxyInstance(Leader.class.getClassLoader(), new Class[]{IWork.class}, new WorkInvocationHandler(leader)); proxy.meeting(); proxy.evaluate("Joy"); proxy.evaluate("James"); } }
Output result:
We see that through the WorkInvocationHandler class, we can also proxy the implementation of the methods of the Leader class. In fact, what we implement is the implementation of any method, but we just pass it in when we create the proxy object. It is the Iwork interface and Leader class object.
What needs to be noted here is: The first parameter proxy in the invoke method of the InvocationHandler interface is not the object of our calling method. So what is this parameter? In the code, I specially added corresponding printing to print out the class name of proxy. In fact, proxy is the proxy object itself. Its meaning is that we can return the proxy object in the invoke method and then make continuous calls.
Look at the following example:
package com.sharpcj.proxytest; public interface IWork { IWork work(String subject); }
package com.sharpcj.proxytest; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class WorkInvocationHandler implements InvocationHandler { private Object object; public WorkInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("work".equals(method.getName())){ System.out.println("--- work: " + args[0]); return proxy; } return null; } }
package com.sharpcj.proxytest; import java.lang.reflect.Proxy; public class TestApp { public static void main(String[] args) { IWork worker = (IWork) Proxy.newProxyInstance(IWork.class.getClassLoader(), new Class[]{IWork.class}, new WorkInvocationHandler(new IWork() { @Override public IWork work(String subject) { return null; } })); worker.work("AAA").work("BBB").work("CCC"); } }
The result is as follows:
首先添加 cglib 依赖
build.gradle 文件:
... dependencies { // 引入 cglib 库 compile 'cglib:cglib:3.1' testCompile group: 'junit', name: 'junit', version: '4.12' } ...
前面说了,cglib 针对类进行代理,我们以上面的 Leader 类为例,先创建一个类实现 MethodInterceptor
接口:
package com.sharpcj; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class LeaderMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if ("meeting".equals(method.getName())) { System.out.println("代理先准备会议材料..."); return methodProxy.invokeSuper(o, objects); } else if ("evaluate".equals(method.getName())) { if(objects[0] instanceof String) { if ("James".equals(objects[0])) { System.out.println("James 犯过错误,所以考评分数较低..."); return 70; } } return methodProxy.invokeSuper(o, objects); } return null; } }
测试代码:
package com.sharpcj; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; import java.lang.reflect.Proxy; public class TestApp { public static void main(String[] args) { // System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\temp\code"); //保存生成的 class 文件 Enhancer enhancer = new Enhancer(); // 通过CGLIB动态代理获取代理对象的过程 enhancer.setSuperclass(Leader.class); // 设置enhancer对象的父类 enhancer.setCallback(new LeaderMethodInterceptor()); // 设置enhancer的回调对象 Leader proxy= (Leader)enhancer.create(); // 创建代理对象 // 通过代理对象调用目标方法 proxy.meeting(); proxy.evaluate("Joy"); proxy.evaluate("James"); } }
结果如下:
MethodInterceptor
接口只有一个 intercept
方法,这个方法有4个参数:
1)obj表示增强的对象,即实现这个接口类的一个对象;
2)method表示要被拦截的方法;
3)args表示要被拦截方法的参数;
4)proxy表示要触发父类的方法对象;
需要注意的是:实际调用是 methodProxy.invokeSuper()
, 如果使用 invoke()
方法,则需要传入被代理的类对象,否则出现死循环,造成 stackOverflow 。
The above is the detailed content of Example analysis of Java dynamic proxy and static proxy. For more information, please follow other related articles on the PHP Chinese website!