Java中代理的实现方式

在这里插入图片描述

在Java中,有多种方式可以实现代理,包括:

  1. 静态代理:

    • 创建一个代理类,实现与目标类相同的接口或继承与目标类相同的父类。
    • 在代理类中持有一个目标类的引用。
    • 在代理类的方法中,调用目标类的对应方法,并在其前后执行额外的逻辑。
    • 使用代理对象来调用方法,实际上是通过代理类间接调用目标类的方法。
  2. JDK动态代理:

    • 定义一个接口,作为代理类和目标类的共同接口。
    • 创建一个实现InvocationHandler接口的代理类。
    • 通过Proxy.newProxyInstance()方法创建代理对象,传入目标类的类加载器、目标类实现的接口和代理类的实例。
    • 在代理类的invoke()方法中,可以在调用目标方法之前和之后执行额外的逻辑。
    • 使用代理对象来调用方法,实际上是通过代理类的invoke()方法间接调用目标类的方法。
  3. CGLIB动态代理:

    • 引入CGLIB库的依赖。
    • 创建一个实现MethodInterceptor接口的代理类。
    • 通过Enhancer类创建代理对象,设置目标类作为父类、代理类作为回调对象。
    • 在代理类的intercept()方法中,可以在调用目标方法之前和之后执行额外的逻辑。
    • 使用代理对象来调用方法,实际上是通过代理类的intercept()方法间接调用目标类的方法。

这些代理方式各有特点,可以根据具体需求选择适合的方式。静态代理相对简单,但需要为每个目标类编写一个代理类;JDK动态代理适用于基于接口的代理;CGLIB动态代理适用于没有实现接口的类的代理。

1. 静态代理

// 定义接口
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 StaticProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.doSomething();
    }
}

在上面的示例中,Subject是一个接口,RealSubject是目标类,实现了Subject接口。ProxySubject是代理类,也实现了Subject接口。在ProxySubject中,我们持有一个RealSubject的引用,并在调用doSomething()方法之前和之后执行额外的逻辑。

在StaticProxyExample中,我们创建了一个RealSubject对象和一个ProxySubject对象,并调用proxySubject.doSomething()方法。在执行过程中,ProxySubject会在调用RealSubject的doSomething()方法之前和之后输出额外的信息,从而实现对目标类的增强。

这就是一个简单的静态代理示例,通过代理类包装目标类,实现了对目标类的功能增强。

2. JDK动态代理

首先,定义一个接口和一个实现该接口的目标类:

// 定义接口
interface Subject {
    void doSomething();
}

// 实现接口的目标类
class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}

然后,创建一个实现InvocationHandler接口的代理类:

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

// 代理类
class ProxyHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Proxy is doing something before RealSubject.");
        Object result = method.invoke(target, args);
        System.out.println("Proxy is doing something after RealSubject.");
        return result;
    }
}

在代理类的invoke()方法中,我们可以在调用目标方法之前和之后执行额外的逻辑。
最后,创建代理对象并调用方法:

import java.lang.reflect.Proxy;

public class JDKDynamicProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxyHandler proxyHandler = new ProxyHandler(realSubject);

        // 创建代理对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                proxyHandler);

        // 调用代理对象的方法
        proxySubject.doSomething();
    }
}

在上面的示例中,我们创建了一个RealSubject对象和一个ProxyHandler对象。然后,使用Proxy.newProxyInstance()方法创建代理对象,传入目标类的类加载器、目标类实现的接口和代理类的实例。通过代理对象调用方法时,实际上是调用了代理类的invoke()方法,在其中执行了额外的逻辑,并最终调用目标对象的方法。

这就是一个简单的使用JDK动态代理的示例,通过代理类和InvocationHandler接口,我们可以在运行时动态地生成代理对象,并在调用目标方法之前和之后执行额外的逻辑。

3. CGLIB动态代理

首先,确保在项目中添加CGLIB库的依赖。

然后,定义一个目标类:

// 目标类
class RealSubject {
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}

接下来,创建一个实现MethodInterceptor接口的代理类:

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 代理类
class ProxyInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Proxy is doing something before RealSubject.");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("Proxy is doing something after RealSubject.");
        return result;
    }
}

在代理类的intercept()方法中,我们可以在调用目标方法之前和之后执行额外的逻辑。在CGLIB动态代理中,通过MethodProxy对象来调用目标方法。

最后,创建代理对象并调用方法:

import net.sf.cglib.proxy.Enhancer;

public class CGLIBDynamicProxyExample {
    public static void main(String[] args) {
        ProxyInterceptor proxyInterceptor = new ProxyInterceptor();

        // 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(proxyInterceptor);

        // 创建代理对象
        RealSubject proxySubject = (RealSubject) enhancer.create();

        // 调用代理对象的方法
        proxySubject.doSomething();
    }
}

在上面的示例中,我们创建了一个ProxyInterceptor对象,并使用Enhancer类来创建代理对象。通过setSuperclass()方法指定目标类,通过setCallback()方法指定代理类。最后,调用create()方法创建代理对象。

通过代理对象调用方法时,实际上是调用了代理类的intercept()方法,在其中执行了额外的逻辑,并最终调用目标对象的方法。

这就是一个简单的使用CGLIB动态代理的示例,通过代理类和MethodInterceptor接口,我们可以在运行时动态地生成代理对象,并在调用目标方法之前和之后执行额外的逻辑。

扩展

CGLIB在实现动态代理时使用了ASM库。ASM是一个Java字节码操作和分析框架,可以用于在运行时生成或修改字节码。CGLIB利用ASM库来生成代理类的字节码,以实现对目标类的动态代理。

在CGLIB中,Enhancer类使用了ASM库来生成代理类的字节码。ASM提供了一套API,可以直接操作字节码,包括创建类、添加字段、添加方法、修改方法等。CGLIB利用ASM的API来生成代理类的字节码,并将其加载到JVM中。

通过使用ASM库,CGLIB能够在运行时生成代理类的字节码,而无需依赖目标类的接口。这使得CGLIB可以代理那些没有实现接口的类,提供了更大的灵活性。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值