代理模式之静态代理、动态代理和CGLIB代理 小记

        代理是一种设计模式,它可以允许我们在不修改原始对象的情况下,通过引入一个代理对象来控制对原始对象的访问。简单来说就是:我们使用 代理对象 来代替对 真实对象 的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

        举例来说:当员工C想要找老板A时,要经过秘书B来传话,员工C将请求给秘书B,秘书B去询问老板A获得回答后在反馈给员工C,在其中秘书B就实现了代理的功能,是老板A的代理对象。

        代理模式有静态代理和动态代理两种实现方式,Java提供了两种动态代理机制:JDK动态代理和CGLIB动态代理。

静态代理

        静态代理在编译时就已经确定了要代理的类和方法,其需要定义一个代理类,该代理类实现了与目标对象相同的接口,并拥有目标对象的引用。通过在代理类的方法中调用目标对象的对应方法,可以在方法调用前后添加额外的逻辑。

// 定义接口
interface Subject {
    void doSomething();
}
// 实现原始对象
class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}
// 实现代理对象
class ProxySubject implements Subject {
    private RealSubject realSubject;
    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }
    @Override
    public void doSomething() {
        // 在调用目标方法之前添加额外的操作
        System.out.println("ProxySubject is doing something before RealSubject.");
        // 调用目标对象的方法
        realSubject.doSomething();
        // 在调用目标方法之后添加额外的操作
        System.out.println("ProxySubject is doing something after RealSubject.");
    }
}
// 使用静态代理
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.doSomething();
    }
}

在上述代码中,RealSubject是实际的业务逻辑类,ProxySubject是代理类。ProxySubject实现了Subject接口,并持有RealSubject对象的引用。在ProxySubjectdoSomething方法中,我们可以进行一些额外的操作,然后再调用RealSubjectdoSomething方法。

        通过静态代理,我们可以在不修改原始对象的情况下,对其进行控制、扩展或增强功能。但是缺点是每个需要代理的类都需要编写一个代理类,如果代理类较多,就会导致代码冗余和维护成本增加。 

动态代理

        动态代理,即JDK动态代理,是一种在运行时创建代理类的机制,它允许在不提前知道代理类的具体类型的情况下,动态地创建一个代理对象来代替原始类。相比于静态代理,动态代理更加灵活,可以代理任意的接口类型,不需要为每个被代理的类编写专门的代理类,而是通过Java的反射机制在运行时动态生成代理类。

        JDK动态代理通过使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Subject {
    void doSomething();
}
class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}
class LoggingHandler implements InvocationHandler {
    private Object target;
    public LoggingHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method call");
        Object result = method.invoke(target, args);
        System.out.println("After method call");
        return result;
    }
}
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler handler = new LoggingHandler(realSubject);
        Subject subject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);
        subject.doSomething();
    }
}

        在上述代码中,RealSubject是实际的业务逻辑类,LoggingHandler是实现了InvocationHandler接口的代理处理器。在invoke()方法中,我们可以在调用目标方法之前或之后添加额外的操作。通过Proxy.newProxyInstance()方法创建代理对象,该方法接收目标对象的类加载器、目标对象的实现接口以及代理处理器作为参数。最后,我们可以调用代理对象的方法,实际上会调用invoke()方法,从而触发额外的操作。

 CGLIB动态代理

        CGLIB:Code Generation Library。

        CGLIB代理是一种通过使用CGLIB库来动态生成代理类的代理方式。与JDK动态代理不同,CGLIB代理可以代理普通的类,而不仅限于接口。这使得CGLIB可以代理那些没有实现任何接口的类。

在使用CGLIB代理时,需要添加相关依赖

 <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class RealSubject {
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}
class LoggingInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method call");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method call");
        return result;
    }
}
public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new LoggingInterceptor());
        RealSubject realSubject = (RealSubject) enhancer.create();
        realSubject.doSomething();
    }
}

在上述代码中,我们定义了一个RealSubject类作为目标对象,它没有实现任何接口。

然后,我们创建了一个LoggingInterceptor拦截器实例,它实现了MethodInterceptor接口(方法拦截器)。在intercept()方法中,我们可以在调用目标方法之前或之后添加额外的操作。

通过Enhancer类创建代理对象,我们首先设置要代理的目标对象的类为代理类的父类,然后设置拦截器为LoggingInterceptor

最后,我们使用enhancer.create()方法来创建代理对象,并将其转型为目标对象的类型。此时,我们可以调用代理对象的方法,实际上会调用拦截器的intercept()方法来触发额外的操作。

        CGLIB代理在某些场景下比JDK动态代理更加强大和灵活,但由于它是通过生成子类来实现代理,所以对于final类和private方法等情况可能会出现限制。同时,由于CGLIB需要动态生成字节码,所以相对于JDK动态代理来说,启动和加载速度较慢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值