本文介绍: JDK动态代理只能代理接口实现类,原因是JDK动态代理是基于接口实现的,代理对象类型由接口列表决定。如果你想代理一个类而不是一个接口,你需要使用其他的代理技术比如CGLIB动态代理。CGLIB 动态代理。

代理模式

代理模式(Proxy Pattern)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象,这样做的好处是:可以目标对象实现的基础上,增强额外功能操作,即扩展目标对象的功能

分类/JavaEE/代理1.png  0 → 100644

代理模式分为两大类:静态代理和动态代理。其中动态代理又分为JDK代理和CGLIB代理。

1. 静态代理

1.1实现方式

代理类与委托实现同一接口。在代理类中需要编码接口。

1.2 优点

实现简单,容易理解

1.3 缺点

代理类需要编码接口,在实际应用可能会导致重复编码浪费存储空间并且效率较低。

1.4 实现代码
package com.wnhz.smart.order.proxy.sta;

/**
 * @author Hao
 * @date 2023-11-28 20:10
 */
public class StaticProxyDemo {
    public static void main(String[] args) {
        // 被代理对象
        RealObject realObject = new RealObject();
        // 创建代理对象
        StaticProxy proxy = new StaticProxy(realObject);
        // 实现静态代理,调用代理对象的方法
        proxy.doSomething();
    }
}

interface MyInterface {
    void doSomething();
}

class RealObject implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("RealObject doSomething");
    }
}

class StaticProxy implements MyInterface {
    private RealObject realObject;

    public StaticProxy(RealObject realObject) {
        this.realObject = realObject;
    }

    @Override
    public void doSomething() {
        System.out.println("Before method invocation");
        realObject.doSomething();
        System.out.println("After method invocation");

    }
}

2. JDK动态代理

2.1实现方式

代理类与委托类实现同一接口。代理类要实现 InvocationHandler 接口并重写 invoke 方法invoke 方法可以委托方法进行增强处理

2.2 优点

需要编码接口,代码复用率高。

2.3 缺点

只能够代理实现了接口的委托类。

2.4 特点

底层使用反射机制进行方法的调用

2.5 实现代码

在下面的代码中,RealObject实现了MyInterface接口,它是我们要代理的实际对象。DynamicProxy类实现了InvocationHandler接口,并在invoke()方法中添加额外逻辑用于在代理对象方法调用前后执行

main()方法中,我们使用Proxy.newProxyInstance()方法创建代理对象。我们指定了MyInterface接口作为代理对象类型,并将DynamicProxy对象作为代理对象的InvocationHandler。

最后,我们调用代理对象的doSomething()方法,并观察控制台输出结果

需要注意的是,代理对象的方法调用都会被转发到DynamicProxy类的invoke()方法中进行处理,因此在这个示例中,实际的RealObject对象的doSomething()方法的执行是在invoke()方法中通过反射进行的。

package com.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Hao
 * @date 2023-11-28 19:34
 */
public class JDKProxyDemo {
    public static void main(String[] args) {
        RealObject real = new RealObject();
        InvocationHandler handler = new DynamicProxy(real);
        // 创建代理对象
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                MyInterface.class.getClassLoader(),
                new Class<?>[]{MyInterface.class},
                handler);
        // 调用代理对象的方法
        proxy.doSomething();
    }
}

interface MyInterface {
    void doSomething();
}

class RealObject implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("RealObject doSomething");
    }
}

class DynamicProxy implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("Before method invocation");
        Object result = method.invoke(target, args);
        System.out.println("After method invocation");
        return result;
    }
}

结果:

Before method invocation
RealObject doSomething
After method invocation

2.6 总结

JDK动态代理只能代理接口实现类,原因是JDK动态代理是基于接口实现的,代理对象的类型由接口列表决定。如果你想代理一个类而不是一个接口,你需要使用其他的代理技术比如CGLIB动态代理。

CGLIB 动态代理

3.1实现方式

代理类将委托类作为自己父类并为其中的非 final 委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过 super 调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor 接口的对象,若存在则将调用 intercept 方法对委托方法进行代理。

3.2 优点

可以运行时对类或者是接口进行增强操作,且委托类无需实现接口。

3.3 缺点

不能对 final 类以及 final 方法进行代理。

3.4 特点

底层将方法全部存入一个数组中,通过数组索引直接进行方法调用。

3.5 代码实现

在下面的示例中,我们使用CGLIB的Enhancer类和MethodInterceptor接口来创建代理对象。RealObject类不再需要实现接口,而是直接作为代理对象的类型。在CGLIBProxy类中,我们实现了MethodInterceptor接口,并在intercept()方法中添加额外逻辑

main()方法中,我们使用Enhancer.create()方法创建代理对象。我们指定了RealObject类作为代理对象类型,并将CGLIBProxy对象作为代理对象的MethodInterceptor。最后,我们调用代理对象的doSomething()方法,并观察控制台输出的结果。

需要注意的是,CGLIB代理使用字节技术生成代理对象,因此它的效率比JDK动态代理要高,但是它也需要额外的库依赖

package com.proxy.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 Hao
 * @date 2023-11-28 19:58
 */
public class CGLIBProxyDemo {
    public static void main(String[] args) {
        RealObject real = new RealObject();
        MethodInterceptor handler = new CGLIBProxy(real);
        // 创建代理对象
        RealObject proxy = (RealObject) Enhancer.create(
                RealObject.class,
                handler);
        // 调用代理对象的方法
        proxy.doSomething();
    }
}

class RealObject {
    public void doSomething() {
        System.out.println("RealObject doSomething");
    }
}

class CGLIBProxy implements MethodInterceptor {
    private Object target;

    public CGLIBProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method invocation");
        Object result = proxy.invoke(target, args);
        System.out.println("After method invocation");
        return result;
    }
}

结果:

Before method invocation
RealObject doSomething
After method invocation

两者之间优缺点

JDK动态代理的优点:
JDK动态代理的缺点:
  • JDK动态代理只能代理实现了接口的类,无法代理没有实现接口的类。

  • JDK动态代理在生成代理对象时,需要使用反射机制,因此它的效率相对较低。

CGLIB代理的优点:
CGLIB代理的缺点:

综上所述,JDK动态代理适用于代理接口实现类的场景,而CGLIB代理适用于代理没有实现接口的类的场景。如果你需要代理接口实现类,而且不想引入额外的依赖,那么JDK动态代理是一个不错的选择;如果你需要代理没有实现接口的类,那么CGLIB代理可能更适合你的需求

原文地址:https://blog.csdn.net/treadsangerbraes/article/details/134676004

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_32012.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注