有趣的jdk动态代理

前言

  • 代理:顾名思义,一个对象无法完成的事情交给代理对象来做。或者反过来,一般事情交给代理对象完成,代理对象完不成的事情交给雇佣来干。代理是需要花费资源的。动态代理:动态指运行时,代理对象才会出场。
  • 注意:使用固定的代理(静态代理)和根据实际业务选择合适的代理对象(动态代理),开销也是不一样的。动态代理用到了反射。
  • 反射是什么?按照正常的逻辑,.java文件编译成.class文件,二进制字节流类加载变成类文件,接着链接,初始化,变成可执行文件,也就是正常运行的程序。但是在运行的时候突然决定某一段程序不合适,需要修改,那么java提供的修改的方法就是反射。动态代理就是想要修改正在运行的可执行文件。
  • 叛逆的总是有意思的。那么动态代理也是很有意思的功能,会给程序带来很多变化,前提是你要会使用。

代理HashMap

public class DynamicProxyTest {
    private static Logger logger = LoggerFactory.getLogger(DynamicProxyTest.class);

    public static void main(String[] args) {
        Map proxyInstance = (Map) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
                new Class[] {Map.class},
                new DynamicInvocation(new HashMap<>()));

        proxyInstance.put("userName", "John");

        Object userName = proxyInstance.get("userName");
        logger.info("userName:{}", userName);

    }
}

class DynamicInvocation implements InvocationHandler {
    private static Logger logger = LoggerFactory.getLogger(DynamicInvocation.class);

    private Map<String, String> target;

    public DynamicInvocation(Map<String, String> target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        logger.info("执行方法:{}, 方法参数:{}", method, args);

        return method.invoke(target, args);
    }
}
  • 下面是输出


    11232151-45317077db2d51dd.png
    image.png
  • 分析一下jdk动态代理的流程:
    1.动态代理的类继承InvocationHandler,重写invoke方法,invoke就是对代理类的方法处理,上面的处理是每次HashMap调用之前都会打印出方法名和方法参数;
    2.可以看到DynamicInvocation对象有个target字段,是Map类型。对,它就是需要代理的对象,通过构造函数传入,看起来和decorate方法很像。但是动态代理的核心是反射。
    3.创建一个代理实例,使用Proxy.newProxyInstance()方法,有三个参数:类加载器,接口类文件,动态代理对象。说下接口类文件:java中类加载器加载的二进制字节流有两种:类和接口。二进制字节流被类加载器加载之后就是Class<>文件。jdk动态代理要求被代理类必须要有接口,所以没有接口的类都不能使用jdk动态代理,但是可以使用cglib动态代理。
    4.jdk动态代理的是对象,接口中定义的所有方法都会在invoke方法中路过。invoke的地位参考高速收费口,不管多少车,都要从我这走,不同的是invoke吃拿卡要。
    1. proxyInstance,代理对象新鲜出炉,代码运行期间生成的。

为什么使用动态代理?

  • 程序员的能力体现在什么地方?我认为是掌控。掌控代码的生成,编译,加载,执行。代码大部分的生命周期都在执行上面,那么对代码执行的控制就很重要了。
  • 方法什么时候执行的?方法执行之前能不能加点东西,我能不能在方法执行之前改变它的参数?我能不能记录每次方法执行参数,它的返回值?Map每次put的执行时间等。动态代理给我们提供了一种在方法执行的时候修改操控代码的方式。
  • java对象有自己的垃圾回收功能,但是理解一个Class文件中不同对象在内存中的存储区域,生命周期,特性也是很重要的。一个方法是dubbo接口,http接口还是和数据存储相关的dao层代码,特性是不同的,围绕这这些东西我们的代码也可以衍生出更多的变化,而不是永远的单纯的crud。

猜你喜欢

转载自blog.csdn.net/weixin_33860528/article/details/86962912