Java中代理的实现方式
- 1. 静态代理
- 2. JDK动态代理
- 3. CGLIB动态代理
- 扩展
在Java中,有多种方式可以实现代理,包括:
-
静态代理:
- 创建一个代理类,实现与目标类相同的接口或继承与目标类相同的父类。
- 在代理类中持有一个目标类的引用。
- 在代理类的方法中,调用目标类的对应方法,并在其前后执行额外的逻辑。
- 使用代理对象来调用方法,实际上是通过代理类间接调用目标类的方法。
-
JDK动态代理:
- 定义一个接口,作为代理类和目标类的共同接口。
- 创建一个实现
InvocationHandler
接口的代理类。 - 通过
Proxy.newProxyInstance()
方法创建代理对象,传入目标类的类加载器、目标类实现的接口和代理类的实例。 - 在代理类的
invoke()
方法中,可以在调用目标方法之前和之后执行额外的逻辑。 - 使用代理对象来调用方法,实际上是通过代理类的
invoke()
方法间接调用目标类的方法。
-
CGLIB动态代理:
- 引入CGLIB库的依赖。
- 创建一个实现
MethodInterceptor
接口的代理类。 - 通过
Enhancer
类创建代理对象,设置目标类作为父类、代理类作为回调对象。 - 在代理类的
intercept()
方法中,可以在调用目标方法之前和之后执行额外的逻辑。 - 使用代理对象来调用方法,实际上是通过代理类的
intercept()
方法间接调用目标类的方法。
这些代理方式各有特点,可以根据具体需求选择适合的方式。静态代理相对简单,但需要为每个目标类编写一个代理类;JDK动态代理适用于基于接口的代理;CGLIB动态代理适用于没有实现接口的类的代理。
1. 静态代理
// 定义接口
interface Subject {void doSomething();
}// 目标类
class RealSubject implements Subject {@Overridepublic void doSomething() {System.out.println("RealSubject is doing something.");}
}// 代理类
class ProxySubject implements Subject {private RealSubject realSubject;public ProxySubject(RealSubject realSubject) {this.realSubject = realSubject;}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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可以代理那些没有实现接口的类,提供了更大的灵活性。