Java 代理模式
发布于: 3 小时前
代理模式主要是在不改变原有方法的前提对方法进行增强!
静态代理
ISubject.java
public interface ISubject { void sayHello();}复制代码
SubjectImpl.java
public class SubjectImpl implements ISubject { @Override public void sayHello() { System.out.println("HELLO WORLD"); }}
复制代码
Proxy.java
public class Proxy implements ISubject { private ISubject target;
public Proxy(ISubject target) { this.target = target; }
@Override public void sayHello() { System.out.println("调用方法前"); target.sayHello(); System.out.println("调用方法后"); }}
复制代码
TestStaticProxy.java
public class TestStaticProxy { public static void main(String[] args) { ISubject target = new SubjectImpl(); ISubject proxy = new Proxy(target); proxy.sayHello(); }}复制代码
结果
调用方法前HELLO WORLD调用方法后复制代码
静态代理,本质上是利用了 Java 中的多态,代理对象通过持有被代理对象的
缺点:扩展性差
JDK 动态代理
定义对被代理的类增强的处理类(即,被代理的类的方法都需要经过该类处理)
JdkProxy.java
public class JdkProxy implements InvocationHandler {
private ISubject target;
public JdkProxy(ISubject target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("jdk proxy 调用方法前"); target.sayHello(); System.out.println("jdk proxy 调用方法后"); return null; }}复制代码
TestJdkProxy
public class TestJdkProxy { public static void main(String[] args) { ISubject target = new SubjectImpl();
ISubject jdkProxy = (ISubject) Proxy.newProxyInstance( ISubject.class.getClassLoader(), new Class<?>[]{ISubject.class}, new JdkProxy(target) ); jdkProxy.sayHello(); }}复制代码
输出
jdk proxy 调用方法前HELLO WORLDjdk proxy 调用方法后复制代码
可以在 com.sun.proxy 的路径中看到一个 $Proxy0.class
package com.sun.proxy;
import com.gingo.training.camp.week05.work.aop.statico.proxy.ISubject;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;
// 动态代理类 实现了 ISubjectpublic final class $Proxy0 extends Proxy implements ISubject { private static Method m1; private static Method m3; private static Method m2; private static Method m0; // var1 就是 new JdkProxy(target) public $Proxy0(InvocationHandler var1) throws { super(var1); }
// super.h 就是 var1 public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } // 将 参数交给 InvocationHandler 的 invoke 方法, // 又因为 InvocationHandler 持有 原有方法的引用可以基于增强 public final void sayHello() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.gingo.training.camp.week05.work.aop.statico.proxy.ISubject").getMethod("sayHello"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}复制代码
本质上还是利用了 Java 接口的多态,但是这里有一个有趣的地方,就是 Java 可以在运行期生成类,并通过我们指定的类加载器加载。即多态 + 运行期生成类并加载
优点:扩性比静态代理前
缺点:只能代理接口
CGLIB
引入 cglib 依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version></dependency>复制代码
定义一个普通的类
Subject.java
public class Subject { public void sayHello() { System.out.println("HELLO WORLD"); }}复制代码
TestCglibProxy.java
public class TestCglibProxy { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Subject.class); enhancer.setCallback( (MethodInterceptor) (obj, method, argss, proxy) -> { System.out.println("jdk proxy 调用方法前"); Object result = proxy.invokeSuper(obj, argss); System.out.println("jdk proxy 调用方法后"); return result; } ); Subject cglibProxy = (Subject) enhancer.create(); cglibProxy.sayHello(); }}复制代码
输出
cglib proxy 调用方法前HELLO WORLDcglib proxy 调用方法后复制代码
本质通过 ASM 技术对字节码注入,实现原有的方法进行增强
优点:可以代理普通的类,不需要实现特定的接口
划线
评论
复制
发布于: 3 小时前阅读数: 7
gin
关注
还未添加个人签名 2020.01.17 加入
真正的大师永远怀着一颗学徒的心











评论