写点什么

Java 代理模式

用户头像
gin
关注
发布于: 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 技术对字节码注入,实现原有的方法进行增强

优点:可以代理普通的类,不需要实现特定的接口

用户头像

gin

关注

还未添加个人签名 2020.01.17 加入

真正的大师永远怀着一颗学徒的心

评论

发布
暂无评论
Java 中的代理