疏窗

  • 首页
  • 生活
  • Java
  • Python
  • Golang
  • 其他
  • 归档

  • 搜索
leetcode jdk 生活 nas nosql 数据库 线程 爬虫 中间件

Java代理模式

发表于 2022-02-11 | 分类于 Java | 0 | 阅读次数 1644

一、静态代理

从jvm层面来说,静态代理在编译时就将接口、实现类、
代理类变成了一个个class文件

1.静态代理的优点:

1.可以使实现方的业务更加纯粹,不用关注额外的业务
2.代理角色实现额外的业务,完成对公共业务的补充
3.额外业务扩展时方便集中管理

2.静态代理的缺点:

1.每个实现方都需要单独写一个代理方
2.需求方发生变更时,代理方和实现方都需要修改代码,非常不方便

3.静态代理实现步骤:

1.定义一个接口及其实现类


/**
 * @description: 需求方接口类
 * @author: Jason
 * @create: 2021-11-19 10:45
 **/
public interface Demander {

    /**
     * 需求
     */
    void doDemand();

}
/**
 * @description: 需求方接口类实现类
 * @author: Jason
 * @create: 2021-11-19 10:47
 **/
public class Implementor implements Demander {
    @Override
    public void doDemand() {
        System.out.println("实现方实现需求!");
    }
}

2.创建一个代理类同样实现这个接口

/**
 * @description: 代理类
 * @author: Jason
 * @create: 2021-11-19 10:49
 **/
public class Proxy implements Demander {

    Implementor implementor;

    public Proxy(Implementor implementor) {
        this.implementor = implementor;
    }

    public Proxy(){

    }

    @Override
    public void doDemand() {
        beforeDemand();
        System.out.println("中介代理!");
        implementor.doDemand();
        afterDemand();
    }

    void beforeDemand(){
        System.out.println("中介代理之前的工作!");
    }

    void afterDemand(){
        System.out.println("中介代理之后的工作!");
    }
}

3.将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

/**
 * @description: 业务入口
 * @author: Jason
 * @create: 2021-11-19 10:53
 **/
public class StartAction {

    public static void main(String args[]){
        Implementor implementor = new Implementor();
        Proxy proxy = new Proxy(implementor);
        proxy.doDemand();
    }

}

二、动态代理

动态代理实质上是对静态代理的补充及优化
相比静态代理更加灵活,不需要我们必须实现接口类,
甚至可以直接代理实现类(CGLIB动态代理机制)

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

1.JDK 动态代理 (针对接口,基于反射)

/**
 * @description: 公共获取代理对象类
 * @author: Jason
 * @create: 2021-11-19 14:51
 **/
public class DemanderInvocationHandler implements InvocationHandler {

    private final Object target;

    public DemanderInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String className = target.getClass().getName();
        String methodName = method.getName();
        log(className,methodName);
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String className,String methodName){
        System.out.println("代理对象为"+className+",代理方法为:"+methodName);
    }

}
/**
 * @description: jdk动态代理对象工厂类
 * @author: Jason
 * @create: 2021-11-19 15:00
 **/
public class JdkProxyFactory {

    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), // 目标类的类加载器
                target.getClass().getInterfaces(),  // 代理需要实现的接口,可指定多个
                new DemanderInvocationHandler(target)   // 代理对象对应的自定义 InvocationHandler
        );
    }
}
/**
 * @description: 入口类
 * @author: Jason
 * @create: 2021-11-19 15:01
 **/
public class StartAction {

    public static void main(String[] args) {
        Demander demander = (Demander) JdkProxyFactory.getProxy(new Implementor());
        demander.doDemand();
    }

}

2.CGLIB 动态代理 (针对类,基于ASM)

/**
 * @description: cglib动态代理类
 * @author: Jason
 * @create: 2021-11-19 16:36
 **/
public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String methodName = method.getName();
        String className = o.getClass().getName();
        log(className,methodName);
        Object result = methodProxy.invokeSuper(o, objects);
        return result;
    }

    public void log(String className,String methodName){
        System.out.println("代理对象为"+className+",代理方法为:"+methodName);
    }
}
/**
 * @description: 入口
 * @author: Jason
 * @create: 2021-11-19 16:41
 **/
public class StartAction {

    public static void main(String[] args) {
        ImplementorNoSuperClass implementorNoSuperClass = new ImplementorNoSuperClass();
        CglibProxy cglibProxy = new CglibProxy();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(implementorNoSuperClass.getClass());
        enhancer.setCallback(cglibProxy);
        ImplementorNoSuperClass implementorNoSuperClassProxy = (ImplementorNoSuperClass) enhancer.create();
        implementorNoSuperClassProxy.doDemand();
    }
}

3.javassist 动态代理 (针对类,基于ASM)

/**
 * @description: javassist动态代理类
 * @author: Jason
 * @create: 2021-11-19 17:08
 **/
public class JavassistProxy {

    private String className;

    public JavassistProxy(String className) {
        this.className = className;
    }

    public JavassistProxy(){

    }

    public void updateDoDemand(String methodName) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        CtClass cc = classPool.get(className);
        CtMethod method = cc.getDeclaredMethod(methodName);
        log(method,methodName);
        Object proxyClass = cc.toClass().newInstance();
        Method execute = proxyClass.getClass().getMethod("doDemand");
        execute.invoke(proxyClass);
    }

    public void log(CtMethod method,String methodName) throws Exception {
        StringBuilder str = new StringBuilder();
        str.append("System.out.println(");
        str.append("\"代理对象为"+className+",代理方法为:"+methodName);
        str.append("\");");
        method.insertBefore(str.toString());
    }


}
/**
 * @description: 入口
 * @author: Jason
 * @create: 2021-11-19 17:15
 **/
public class StartAction {

    public static void main(String[] args) {
        JavassistProxy javassistProxy = new JavassistProxy("com.design.design_pattern.proxy.ImplementorNoSuperClass");
        try {
            javassistProxy.updateDoDemand("doDemand");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

总结

1.spring aop使用的是混合模式,代理对象实现了接口优先使用jdk动态代理,没实现接口则优先使用cglib动态代理

2.cglib动态代理和javasist动态代理都是基于ASM操作字节码实现,其中cglib动态代理是继承目标对象生成一个子类并覆盖方法实现,所以被代理的类不能被final修饰,而javasist动态代理则是直接修改字节码实现。

打赏作者
疯子虾夫 微信支付

微信支付

疯子虾夫 支付宝

支付宝

  • 本文作者: 疯子虾夫
  • 本文链接: https://hefengwei.com/archives/代理模式md
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
Mybatis plus lambdaQuery和lambdaUpdate用法
jdk9-17部分新特性使用
  • 文章目录
  • 站点概览
疯子虾夫

疯子虾夫

24 日志
5 分类
9 标签
RSS
Creative Commons
© 2025 疯子虾夫
由 Halo 强力驱动
|
主题 - NexT.Mist v5.1.4
赣ICP备2024026242号

粤公网安备 44010602005909号