设为首页 加入收藏

TOP

JdkProxy的进阶知识(一)
2023-07-25 21:32:20 】 浏览:19
Tags:JdkProxy

如果想增强一个方法的功能,无非就是直接在方法体内直接修改。但这也无非给一些有代码洁癖人士一丝丝不悦!于是乎我们即不想在原来的代码里修改,又不想把原有的代码重新写一次,那么前辈们就发明了代理.
注意:本文以 JdkProxy 为基础展开所有描述!

参与对象

那么一个代理过程参与的对象有以下几项:

  • 目标接口
  • 目标类(Target)
  • 代理基类(Proxy)
  • 生成的代理类
  • 调用处理程序(InvocationHandler)
目标接口。

至于为什么要用接口,这是JdkProxy的理论知识。文章结束后你也会明白!

public interface Fight {

    /**
     * 射击
     */
    void shot();

    /**
     * 炸弹
     */
    void bomb();
}
目标类

就是需要被代理的类!

public class BeautifulCountryTarget implements Fight {


    private static final Logger LOGGER = LoggerFactory.getLogger(BeautifulCountryTarget.class);


    /**
     * 射击
     */
    @Override
    public void shot() {
        
        LOGGER.debug("M4 shot ---> big goose!");
        
    }

    /**
     * 炸弹
     */
    @Override
    public void bomb() {
        
        LOGGER.debug("HIMARS fire ---> big goose!");
    }
}
调试和输出结果
public class JdkProxy {
    
    
    private static final Logger LOGGER = LoggerFactory.getLogger(JdkProxy.class);


    /**
     * 通过 Proxy.create 生成的对象是代理对象,基于 接口的代理对象,那么有以下几点是需要注意
     *  
     * 1:生成的 代理对象 是实现了 目标接口
     * 2:生成的 代理对象 与 代理目标 是兄弟关系 (都实现了同一个目标接口)
     * 
     */
    public static void main(String[] args) throws InterruptedException {
        
        // jdkProxy
        jdkProxyTest();
        
    }
    
    
    public static void jdkProxyTest() throws InterruptedException {
        //类加载器,负责把生成的class($Proxy???)文件加载到JVM
        ClassLoader loader = JdkProxy.class.getClassLoader();

        //需要代理的目标(对象)
        BeautifulCountryTarget target = new BeautifulCountryTarget();

        //增强目标方法的处理程序
        InvocationHandler handler = (proxy, method, args) -> {

            LOGGER.debug("大哥你在旁边看着喝Coffee!,武器开给,我来打!");

            //方法调用,(目标对象,参数)
            return method.invoke(target, args);

        };


        //创建代理人
        Fight w_k_l_Fight = (Fight)Proxy.newProxyInstance(
                loader,
                new Class[]{Fight.class},
                handler
        );
        
        //打印下类路径,方便使用 arthas 进行反张译
        LOGGER.debug("proxy<w_k_l_Fight> class {}", w_k_l_Fight.getClass());
    
        //代理人调用方法
        w_k_l_Fight.shot();
        w_k_l_Fight.bomb();
        
    }

}

打印出

19:22:41.839 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- proxy<w_k_l_Fight> class class jdk.proxy1.$Proxy0
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- M4 shot ---> big goose!
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- HIMARS fire ---> big goose!

可以看出代理生效了,-_-!

那么通过 Proxy.create函数生成的是一字节码文件(至于怎么生成,太高端没去研究),它被 loader 加载到JVM,通过 debug只看了类名$Proxy0

模拟手写代理类

既然是系统自己生成的,那么我们自己可以自己写一个,不用系统生成的~。由理论知识可以写出以下 代理类

/**
 * 模拟 通过 Proxy.create 出来的 $Proxy?? 类,
 * 
 */
public class SimulateProxy extends Proxy implements Fight {
    
    
    protected SimulateProxy(InvocationHandler h) {
        super(h);
    }
    
    
    /**
     * 射击
     */
    @Override
    public void shot() {
        try {
            // 代理的方法
            Method pMethod = Fight.class.getMethod("shot");

            //调用增强处理器
            super.h.invoke(this, pMethod, null);   
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * 炸弹
     */
    @Override
    public void bomb() {
        try {
            // 代理的方法
            Method pMethod = Fight.class.getMethod("bomb");

            //调用增强处理器
            super.h.invoke(this, pMethod, null);   
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
调试输出
public class JdkProxy {
    
    
    private static final Logger LOGGER = LoggerFactory.getLogger(JdkProxy.class);


    /**
     * 通过 Proxy.create 生成的对象是代理对象,基于 接口的代理对象,那么有以下几点是需要注意
     *  
     * 1:生成的 代理对象
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java中ThreadLocal的用法和原理 下一篇Quartz 简单使用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目