Java核心技术06 | 动态代理

本文介绍了Java中的反射机制,特别是动态代理的概念。动态代理允许在运行时生成代理对象,常用于AOP、RPC等场景。文章详细讲解了JDK动态代理和cglib动态代理的实现原理,并探讨了反射在调整成员访问限制、O/R Mapping框架等方面的应用。

典型定义

  • 反射机制是Java语言提供的一种基础功能,赋予程序在运行时自省(introspect)的能力。通过反射我们可以直接操作类或对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。
  • 动态代理是一种方便运行时动态构造代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装RPC调用、面向切面的编程(AOP)。
  • 实现动态代理的方式很多,比如JDK自身提供的动态代理,主要利用到了反射机制,更高性能的字节码操作机制,类似ASM,cglib等。

分类

  •  静态代理:事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都要对应一个代理类,非常不灵活。
  •  动态代理:运行时自动生成代理对象。缺点是生成代理代理对象和调用代理方法都要额外花费时间。
  1. JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。新版本也开始结合ASM机制。
  2. cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。
  • Java 发射机制的常见应用:动态代理(AOP、RPC)、提供第三方开发者扩展能力(Servlet容器,JDBC连接)、第三方组件创建对象(DI)

反射机制及其演进

反射的功能:①在运行时能判断任意一个对象所属的类。②在运行时能构造任意一个类的对象。③在运行时判断任意一个类所具有的成员变量和方法。④在运行时调用任意一个对象的方法。

反射提供的AccessibleObject.setAccessible(boolean flag),它的子类大都重写了这个方法,这里所谓的accessible可以理解为修饰成员的public、protected、private,这意味着我们可以在运行时修改成员访问限制

setAccessible的应用场景非常普遍,遍布我们的日常开发、测试、依赖注入等各种框架中。比如在O/R Mapping框架中,我们为一个Java实体对象,运行时自动生成setter、getter的逻辑,这是加载或者持久化数据非常必要的,框架通常可以利用反射做这个事情,而不需要开发者手动写类似的重复代码。

另一个典型场景就是绕过API访问控制,我们日常开发时可能被迫要调用内部API去做些事情,比如,自定义的高性能NIO框架需要显式地释放DirectBuffer,使用反射绕开限制是一种常见的办法。

动态代理

它是一个代理机制,通过代理可以让调用者与实现者之间解耦。

(动态)代理模式主要涉及三个要素:①抽象类接口②被代理类(具体实现抽象接口的类)③动态代理类:实际调用被代理类的方法和属性的类

public class MyDynamicProxy {
    public static  void main (String[] args) {
        HelloImpl hello = new HelloImpl();
        MyInvocationHandler handler = new MyInvocationHandler(hello);
        // 构造代码实例
        Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
        // 调用代理方法
        proxyHello.sayHello();
    }
}
interface Hello {
    void sayHello();
}
class HelloImpl implements  Hello {
    @Override
    public void sayHello() {
        System.out.println("Hello World");
    }
}
 class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("Invoking sayHello");
        Object result = method.invoke(target, args);
        return result;
    }
}

常可采用的JDK提供的动态代理接口InvocationHandler来实现动态代理类。其中invoke方法是该接口定义必须实现的,它完成对真实方法的调用。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值