java代理模式

发布时间:2023年12月21日

代理模式有两种

静态代理:需要为每个目标类写个代理类,代理类中需要引用目标类来编码实线

动态代理:jdk api和cglib两种

jdk动态代理

jdk api就是写一个代理类,这个代理类,使用jdk提供的java.lang.reflect Proxy和java.lang.reflect InvocationHandler来获取代理以及传入被代理的方法,这样就是不用直接引用被代理对象,可以在使用处以参数的方式传入被代理对象的方法和参数。

动态代理的实现方式

JDK的动态代理是通过Proxy类和InvocationHandler接口来实现的。InvocationHandler接口中定义了一个invoke方法,用于处理代理方法的调用。当目标对象实现了接口时,可以通过Proxy类的newProxyInstance方法动态生成代理类,并将InvocationHandler对象传入,从而实现对目标对象方法的动态代理。

为什么jdk动态代理只能代理实现接口的类,不能代理普通类

动态代理实际上是程序在运行中

  • 根据被代理的接口来动态生成代理类的 class 文件,
  • 并加载 class 文件运行的过程,
  • 通过反编译被生成的?$Proxy0.class?文件发现
    public final class $Proxy0 extends Proxy implements Interface {
     
        public $Proxy0(InvocationHandler paramInvocationHandler) {
            super(paramInvocationHandler);
        }
     
        // 该方法为被代理接口的业务方法,代理类都会自动生成相应的方法,里面去执行invocationHandler 的invoke方法。
        public final void sayHello(String paramString) {
            try {
                this.h.invoke(this, m3, new Object[] { paramString });
                return;
            }
            catch (Error|RuntimeException localError) {
                throw localError;
            }
            catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    }

    java 是单继承
    动态生成的代理类已经继承了 Proxy 类的,就不能再继承其他的类,
    所以只能靠实现被代理类的接口的形式,故 JDK 的动态代理必须有接口。
    为何调用代理类的方法就会自动进入 InvocationHandler 的 invoke()方法呢?

    因为 invoke 方法中利用 jdk 反射的方式去调用真正的被代理类的业务方法,
    而且还可以在方法的前后去加一些我们自定义的逻辑

JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口(就是一个类它要先定义一个接口再定义一个接口实现才能使用动态代理,没有定义接口的类用不了jdk动态代理)。 如果想代理没有实现接口的类,就可以使用CGLIB实现。

CGLIB动态代理

2)CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。 它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。 CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。’

CGLib 动态代理可以代理普通的类。CGLib 动态代理采用继承方式来实现代理,在运行时动态生成一个被代理类的子类,被代理类的方法作为子类的方法被调用,通过这种方式来实现对被代理对象的代理。被代理的类不能是final类。

  1. 静态代理在编译时产生class字节码文件,可以直接使用,效率高。

  2. 动态代理必须实现InvocationHandler接口,通过反射代理方法,比较消耗系统性能,但可以减少代理类的数量,使用更灵活。

  3. cglib代理无需被代理类实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。

文章来源:https://blog.csdn.net/snow_7/article/details/135132718
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。