java中的代理

代理

什么是代理模式?

deepSeek 给我的答案,如下:

代理模式(Proxy Pattern)是一种设计模式,属于结构型模式。在代理模式中,一个类代表另一个类的功能,以便控制客户对原始对象的访问,或者为原始对象提供一个替代品。
在代理模式中,通常会涉及以下三个角色:
* 抽象主题(Subject):定义了RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
* 真实主题(RealSubject):定义了代理所表示的真实对象,代理角色通常要引用真实主题,以便在需要的时候将请求转发给它。
* 代理(Proxy):保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来代替实体。代理角色通常在将请求提交给真实主题之前或之后,执行某个操作,比如权限检查、缓存、记录日志等。

两种代理类型

特性/模式 静态代理 动态代理
定义 编译时确定代理类和原始类的关系,通常由程序员手动编写。 运行时动态创建代理类,不需要手动编写代理类。
实现方式 代理类和原始类实现相同的接口或继承自相同的父类,代理类中持有原始类的实例。 利用反射机制,如Java中的java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler
灵活性 代理类和原始类的关系固定,不够灵活。 可以在运行时动态创建,更加灵活。
维护成本 每个需要代理的类都需要一个代理类,可能导致类数量膨胀,增加维护成本。 不需要为每个类手动编写代理类,减少了代码量,降低了维护成本。
接口变更 接口增加方法时,代理类和原始类都需要修改。 接口变更不会影响代理类的创建,只需要修改InvocationHandler的实现。
使用场景 适用于代理类数量较少且稳定的场景。 适用于代理类数量较多或频繁变化的场景。

两种动态代理

特性/模式 JDK代理 CGLIB代理
实现方式 JDK代理利用反射机制,通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。 CGLIB代理通过底层的字节码技术,为目标类生成一个子类,并在子类中覆盖非final的方法,进而实现方法拦截和增强处理。
接口要求 目标类必须实现一个或多个接口,JDK代理基于这些接口创建代理实例。 目标类不需要实现接口,CGLIB代理通过继承目标类来创建代理实例。
性能 JDK代理的性能相对较低,因为它依赖于反射机制。 CGLIB代理的性能相对较高,因为它使用了底层的字节码技术。
final方法 JDK代理不能拦截final方法,因为final方法不能被覆盖。 CGLIB代理同样不能拦截final方法。
构造函数 JDK代理不会拦截构造函数。 CGLIB代理可以在子类中拦截构造函数。
使用场景 当目标类已经实现了某个接口,或者你希望代码更轻量级时,适合使用JDK代理。 当目标类没有实现任何接口,或者你希望在运行时生成代理类以进行方法增强时,适合使用CGLIB代理。
兼容性 JDK代理是Java语言的一部分,因此不需要额外的依赖。 CGLIB代理需要额外的库(如Apache Commons Collections)支持。

jdk 动态代理

示例:

package demo.base.proxy;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Demo1 {

    @Test
    public void test() {
        //真实角色
        Rent host = new Host();
        //动态生成对应的代理类!
        DynamicProxyHandler pih = new DynamicProxyHandler(host);
        Rent proxy = (Rent) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                host.getClass().getInterfaces(), pih);
        //执行方法
        proxy.rent();
    }

    public static class DynamicProxyHandler implements InvocationHandler {
        private final Object rent;

        public DynamicProxyHandler(Object rent) {
            this.rent = rent;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            seeHouse();
            Object result = method.invoke(rent, args);
            fare();
            return result;
        }

        //看房
        public void seeHouse() {
            System.out.println("带房客看房");
        }

        //收中介费
        public void fare() {
            System.out.println("收中介费");
        }
    }

    public interface Rent {
        public void rent();
    }

    public class Host implements Rent{
        @Override
        public void rent() {
            System.out.println("房屋出租");
        }

    }
}

cglib 动态代理

cglib 代理是通过继承实现,故注意继承需要考虑final问题,final类型不能有子类,所以CGLIB不能代理final类型。
若如下 SimpleService 使用final 修饰,会报错:

java.lang.IllegalArgumentException: Cannot subclass final class demo.base.proxy.CgLibDemo$SimpleService

同样的,final方法是不能重载的,所以也不能通过CGLIB代理,遇到这种情况不会抛异常,而是会跳过final方法只代理其他方法。
示例:

package demo.base.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * @author lijunjie134
 * @date 2025/2/19
 */
public class CgLibDemo {

    // 服务类
    static class  SimpleService {
        public void sayHello() {
            System.out.println("Hello, this is the original method.");
        }
    }

    // CGLIB代理的拦截器
    static class MyMethodInterceptor implements MethodInterceptor {
        private Object target;

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

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            // 在调用原始方法之前执行的操作
            System.out.println("Before method call.");

            // 调用原始方法
            Object result = method.invoke(target, args);

            // 在调用原始方法之后执行的操作
            System.out.println("After method call.");

            return result;
        }
    }

    @Test
    public void test() {
        // 创建一个Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置要代理的目标类
        enhancer.setSuperclass(CgLibDemo.SimpleService.class);
        // 设置回调方法(拦截器)
        enhancer.setCallback(new CgLibDemo.MyMethodInterceptor(new CgLibDemo.SimpleService()));

        // 创建代理对象
        CgLibDemo.SimpleService proxy = (CgLibDemo.SimpleService) enhancer.create();

        // 使用代理对象调用方法
        proxy.sayHello();
    }


}

posted @ 2025-02-19 16:01  执大象  阅读(36)  评论(0)    收藏  举报