什么是代理模式
假如我喜欢上隔壁班的翠花, 但是我没胆量向她送花, 这时候我需要一个铁杆哥们帮我做这件事, 很明显这哥们是个代理, 是去执行任务的, 但是花实际上是我 "送" 的, 代理和我一样会送花这个动作, 直接上代码.
- public interface IProcess { void SendFlower();
- }
- public class Studnet1 implements IProcess {
- @Override
- public void SendFlower() {
- System.out.println("my name is Studnet1 , the flower is for you");
- }
- }
- public class ProxyStudent implements IProcess {
- private IProcess targetObj;
- public ProxyStudent(IProcess targetObj) {
- this.targetObj = targetObj;
- }
- @Override
- public void SendFlower() {
- System.out.println("check it before send");
- targetObj.SendFlower();
- System.out.println("check it after send");
- }
- }
- public class ProcessFactory {
- public static IProcess getProcess(){
- return new Studnet1();
- }
- }
- public class Main {
- public static void main(String[] args) {
- IProcess ProxyObj = ProcessFactory.getProcess();
- ProxyObj.SendFlower();
- }
- }
运行结果:
- check it before send
- my name is Studnet1 , the flower is for you
- check it after send
很开心, 终于把花送出去了, 可以见到调用代理者的 SendFlower 方法, 实际上是我的 SendFlower 方法, 打到我需要送花的目的, 同时这铁哥们人缘非常好, 其他的同学也需要他来帮忙 , Student2, Student3 , Student4 也需要这铁哥们,
并且他们的要求不只是送花, 还可能邀请看电影.... 等等, 那么 ProcessFatory 也要改写, 另外假如我不止想送花这个动作, 需要添加方法到接口上, 那么其他类相应的也要改动.
- public class ProcessFactory {
- public static IProcess getProcess(){
- return new Studnet1();
- }
- public static IHold getHold(){
- return new Studnet2();
- }
- public static IMovie getMovier(){
- return new Studnet3();
- }
- .....
- }
显然这样的每次一个新的一个需求都需要创建一个对象, 很不合理, 于是就出现了动态代理.
动态代理
先上代码, 新建一个类,
- public class StuInvocationHandler<T> implements InvocationHandler {
- T target;
- public StuInvocationHandler(T target) {
- this.target = target;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- System.out.println("this is a proxy method");
- System.out.println("check it before sending");
- Object result = method.invoke(target, args);
- System.out.println("check it after sending");
- return result;
- }
- }
调用, 输出结果:
- public class Main {
- public static void main(String[] args) {
- IProcess student1 = ProcessFactory.getProcess();
- InvocationHandler handler = new StuInvocationHandler<IProcess>(student1);
- IProcess ProxyStudent = (IProcess) Proxy.newProxyInstance(IProcess.class.getClassLoader(), new Class<?>[]{IProcess.class}, handler);
- ProxyStudent.SendFlower();
- }
- }
- this is a proxy method
- check it before sending
- my name is Studnet1 , the flower is for you
- check it after sending
我们似乎看不到了代理类, 实际上 StuInvocationHandler 就是我们的代理类, 这时无论代理谁都可以进行操作, 动态代理运用了 java 一个重要的特性 -"反射" . 我们需要知道两点:
代理类调用方法使用了反射
代理类继承了 Proxy , 实现了被代理的接口, 对应例子中的 IProcess , 由于 java 是单继承, 所以也就决定了 java 动态代理只能对接口进行代理.
在 main 方法中添加以下代码,
- byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", Studnet1.class.getInterfaces());
- String path = "E:StuProxy.class";
- try(FileOutputStream fos = new FileOutputStream(path)) {
- fos.write(classFile);
- fos.flush();
- System.out.println("代理类 class 文件写入成功");
- } catch (Exception e) {
- System.out.println("写文件错误");
- }
在 E 盘中就会有一个 StuProxy.class 文件, 这个就是代理类, 我们用反编译工具 java decompiler 查看源代码,
- import com.benjious.IProcess;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.lang.reflect.UndeclaredThrowableException;
- public final class $Proxy0
- extends Proxy
- implements IProcess
- {
- private static Method m1;
- private static Method m3;
- private static Method m2;
- private static Method m0;
- public $Proxy0(InvocationHandler paramInvocationHandler)
- throws
- {
- super(paramInvocationHandler);
- }
- public final boolean equals(Object paramObject)
- throws
- {
- try
- {
- return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final void SendFlower()
- throws
- {
- try
- {
- this.h.invoke(this, m3, null);
- return;
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final String toString()
- throws
- {
- try
- {
- return (String)this.h.invoke(this, m2, null);
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final int hashCode()
- throws
- {
- try
- {
- return ((Integer)this.h.invoke(this, m0, null)).intValue();
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- static
- {
- try
- {
- m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
- m3 = Class.forName("com.benjious.IProcess").getMethod("SendFlower", new Class[0]);
- m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
- m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
- return;
- }
- catch (NoSuchMethodException localNoSuchMethodException)
- {
- throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
- }
- catch (ClassNotFoundException localClassNotFoundException)
- {
- throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
- }
- }
- }
动态代理的弊端
java 动态代理只能对接口进行代理. 这个在源代码中也可以看到, CGLib 可以解决这个问题, cglib 是针对类来实现代理的, 他的原理是对指定的目标类生成一个子类, 并覆盖其中方法实现增强, 但因为采用的是继承, 所以不能对 final 修饰的类进行代理.
再回想一下, 调用 invoke 方法前后我们都是可以进行其他操作的, 实际上这就是 Spring 里的 AOP,Spring 的 AOP 实现其实也是用了 Proxy 和 InvocationHandler 这两个东西的.
参考文章:
- https://www.cnblogs.com/gonjan-blog/p/6685611.html
- http://www.importnew.com/22015.html
来源: http://www.bubuko.com/infodetail-2683007.html