Java动态代理相关简述
一、概念:
Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(如Spring AOP、cglib等
)。
代理模式:
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。(个人理解就是对调用目标的一种封装
)
静态代理
由程序员创建或者由第三方工具生成,再进行编译;在程序运行之前,代理类的.class文件已经存在了。
(静态代理类通常只代理一个类,静态代理事先知道要代理的是什么。
)
动态代理:
在程序运行时,通过反射机制动态生成。动态代理类通常代理接口下的所有类。( 动态代理事先不知道要代理的是什么,只有在运行的时候才能确定。
) 动态代理的调用处理程序必须事先InvocationHandler接口,及使用Proxy类中的newProxyInstance方法动态的创建代理类。JDK动态代理只能代理接口,要代理类需要使用第三方的CLIGB等类库。
二、JDK动态代理
上面的 JDK Proxy 例子,非常简单地实现了动态代理的构建和代理操作。
首先,实现对应的 InvocationHandler;
然后,以接口 Hello 为纽带,为被调用目标构建代理对象;
进而应用程序就可以使用代理对象间接运行调用目标的逻辑。
代理为应用插入额外逻辑(System.out.println("invoke:")
)提供了便利的入口。
从 API 设计和实现的角度,这种实现仍然有局限性,因为它是以接口为中心的,相当于添加了一种对于被调用者没有太大意义的限制。我们实例化的是 Proxy
对象,而不是真正的被调用类型,这在实践中还是可能带来各种不便和能力退化。
如果被调用者没有实现接口,而我们还是希望利用动态代理机制,那么可以考虑其他方式(如cglib
)。
三、cglib动态代理
cglib
动态代理采取的是创建目标类的子类的方式,因为是子类化,我们可以达到近似使用被调用者本身的效果,克服了接口的依赖。
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/** * @author wangcw * @create 2020-01-19 17:05 * @description:Cglib动态代理 **/
public class DynamicProxyDemo {
public static void main(String[] args) {
HelloCglib helloCglib = new HelloCglib();
Hello helloProxy = (Hello) helloCglib.getInstance(new Hello());
helloProxy.sayHello();
}
/* 目标类 */
static class Hello {
public void sayHello() {
System.out.println("hello world");
}
}
static class HelloCglib implements MethodInterceptor {
private Object target;
public Object getInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
//设置父类为目标类
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("扩展逻辑 1 - before invoke:");//扩展逻辑
methodProxy.invokeSuper(o, objects);
System.out.println("扩展逻辑 2 - after invoke!");//扩展逻辑
return null;
}
}
}
四、优势比较和应用
JDK Proxy 的优势:
1、最小化依赖关系,减少依赖意味着简化开发和维护,JDK 本身的支持,可能比 cglib 更加可靠;
2、平滑进行 JDK 版本升级,而字节码类库通常需要进行更新以保证在新版 Java 上能够使用;
3、代码实现简单;
4、新版本JDK也使用ASM提高性能。
基于类似 cglib 框架的优势:
1、有的时候调用目标可能不便实现额外接口,从某种角度看,限定调用者实现接口是有些侵入性的实践,类似 cglib 动态代理就没有这种限制;
2、只操作我们关心的类,而不必为其他相关类增加工作量;
3、基于ASM字节码,高性能;
4、通过生成业务类的子类作为代理类。
动态代理应用非常广泛,虽然最初多是因为 RPC 等使用进入我们视线,但是动态代理的使用场景远远不仅如此,它完美符合 Spring AOP 等切面编程。简单来说它可以看作是对 OOP 的一个补充,因为 OOP 对于跨越不同对象或类的分散、纠缠逻辑表现力不够,比如在不同模块的特定阶段做一些事情,类似日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等,你可以参考下面这张图。
还没有评论,来说两句吧...