zoukankan      html  css  js  c++  java
  • Java 动态代理实现

    JDK 动态代理

    代理模式是常用的 JAVA 设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 JDK 动态代理是 java.lang.reflect.* 包提供的方式,但是必须借助一个或多个接口才能产生代理对象。

    • 主要实现包含
    说明
    java.lang.reflect.Proxy 用来获取动态代理对象
    java.lang.reflect.InvocationHandler 用来约束调用者实现

    定义接口 IHelloWorld

    public interface IHelloWorld {
        public void sayHelloWorld();
    }

    定义实现类 HelloWorldImpl

    public class HelloWorldlmpl implements IHelloWorld {
        @Override
        public void sayHelloWorld() {
            System.out.println("Hello World !");
        }
    }

    定义代理类 JdkProxy

    public class JdkProxy implements InvocationHandler {
    
        public Object target = null;
    
        public Object build(Object target) {
            this.target = target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("先处理~!!");
            Object obj = method.invoke(target, args);
            System.out.println("后处理~!!");
            return obj;
        }
    1. 第一步,建立代理对象和真实对象的关系。
    Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
     
    参数说明
    target.getClass().getClassLoader() 类加载器
    target.getClass().getInterfaces() 动态代理的下挂接口,即 IHelloWorld
    this 实现方法逻辑的动态代理类,即 JdkProxy 本身
    1. 第二步,实现代理的逻辑方法。
    invoke(Object proxy, Method method, Object[] args) 
     
    参数说明
    proxy 代理对象,build 方法生成的对象
    method 当前正在调度的方法
    args 调度方法的参数
    • 实际调用了真实对象的方法
    Object obj = method.invoke(target, args);

    实现和输出结果

    JdkProxy example = new JdkProxy();
    IHelloWorld helloWorld = (IHelloWorld) example.build(new HelloWorldImpl());
    helloWorld.sayHelloWorld();

    结果:

    先处理~!!
    Hello World !!
    后处理~!!

    上面简述了JDK动态代理,关于更多细节参考:https://www.cnblogs.com/youngao/p/12612963.html

    CGLIB 动态代理

    CGLIB 是一个强大的,高性能,高质量的 Code 生成类库。它可以在运行期扩展 Java 类与实现 Java 接口。其底层是通过小而快的字节码处理框架 ASM(http://forge.ow2.org/projects/asm,使用 BSD License)来转换字节码并生成新的类。大部分功能实际上是 asm 所提供的,CGLIB 只是封装了 asm,简化了 asm 的操作,实现了在运行期动态生成新的 class。

    • 主要实现包含
    说明
    net.sf.cglib.core 底层字节码处理类,他们大部分与 ASM 有关系
    net.sf.cglib.transform 编译期或运行期类和类文件的转换
    net.sf.cglib.proxy 实现创建代理和方法拦截器的类
    net.sf.cglib.reflect 实现快速反射和C#风格代理的类
    net.sf.cglib.util 集合排序工具类
    net.sf.cglib.beans JavaBean 相关的工具类

    直接定义类 HelloWorldImpl

    public class HelloWorldlmpl {
    
        public void sayHelloWorld() {
            System.out.println("Hello World !");
        }
    }

    定义代理类 CglibProxy

    public class CglibProxy implements MethodInterceptor {
    
        public Object getProxy(Class cls) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(cls);
            enhancer.setCallback(this);
            enhancer.setClassLoader(cls.getClassLoader());  
            return enhancer.create();
        }
    
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("先处理~!!");
            Object obj = methodProxy.invokeSuper(proxy, args);
            System.out.println("后处理~!!");
            return obj;
        }
    }
    1. 第一步,建立代理对象和真实对象的关系。
    enhancer.setSuperclass(cls);
    enhancer.setCallback(this);
    enhancer.setClassLoader(cls.getClassLoader());
    return enhancer.create();
     
    参数说明
    enhancer.setSuperclass(cls) 设置要代理的目标类,以扩展它的功能
    enhancer.setCallback(this) 设置单一回调对象,在回调中拦截对目标方法的调用
    enhancer.setClassLoader(cls.getClassLoader()) 设置类装载器
    enhancer.create() 创建代理对象
    • CGLIB 包提供了一些专门的回调(callback)类型
    类型说明
    net.sf.cglib.proxy.FixedValue 为提高性能,FixedValue 回调对强制某一特别方法返回固定值是有用的。
    net.sf.cglib.proxy.NoOp 把对方法调用直接委派到这个方法在父类中的实现。
    net.sf.cglib.proxy.LazyLoader 当实际的对象需要延迟装载时,可以使用 LazyLoader 回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用。
    net.sf.cglib.proxy.Dispatcher Dispathcer 回调和 LazyLoader 回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用。
    net.sf.cglib.proxy.ProxyRefDispatcher ProxyRefDispatcher 回调和 Dispatcher 一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递。
    1. 第二步,实现代理的逻辑方法。
    intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
     
    参数说明
    proxy 代理对象
    method 被代理的方法
    args 该方法的参数数组
    methodProxy 不是原始的 method,以提高性能

    实现和输出结果

    CglibProxy cglibProxy = new CglibProxy();  
    HelloWorldImpl hw = (HelloWorldImpl) cglibProxy.getProxy(HelloWorldImpl.class);
    hw.sayHelloWorld();

    运行结果:

    先处理~!!
    Hello World !!
    后处理~!!

    参考资料

    http://blog.csdn.net/zhoudaxia/article/details/30591941

  • 相关阅读:
    C# 获取类似java gettime() 的时间格式
    LUbuntu电脑棒安装指南
    Visual Studio Gallery
    SQL SERVER 分页存储过程
    asp.mvc获取checkbox、radio、select的值
    C#面向对象的一些笔记
    Javascript预解析、作用域、作用域链
    解决ajax请求cors跨域问题
    Asp.Net操作WebServices
    2019年科技趋势前10位
  • 原文地址:https://www.cnblogs.com/youngao/p/12574445.html
Copyright © 2011-2022 走看看