在Java中,动态代理是一种通过在运行时生成代理对象来拦截对目标对象的访问的技术。Java中的动态代理基于反射机制,利用反射生成代理类来实现对目标对象的代理。
一、Java中的动态代理主要有两种方式:基于接口的动态代理和基于类的动态代理。它们的特点如下:
1. 基于接口的动态代理(JDK动态代理):
基于接口的动态代理要求目标对象实现一个或多个接口。JDK动态代理使用'java.lang.reflect.Proxy'类来实现代理。它通过一个InvocationHandler对象来拦截对目标对象方法的调用,并在调用前后进行一些操作。
2. 基于类的动态代理(CGLIB动态代理):
基于类的动态代理不要求目标对象实现接口,它是通过继承目标类来生成代理类的子类。CGLIB动态代理使用'net.sf.cglib.proxy.Enhancer'类来实现代理。它通过一个MethodInterceptor对象来拦截对目标对象方法的调用,并在调用前后进行一些操作。
二、使用动态代理的方法如下:
1. 定义接口或目标类:
首先需要定义一个接口或者一个目标类,它是被代理对象的类型。
2. 实现InvocationHandler/MethodInterceptor接口:
实现一个InvocationHandler接口(对应JDK动态代理)或者一个MethodInterceptor接口(对应CGLIB动态代理),作为代理的调用处理器,用于在方法调用前后进行一些操作。
3. 创建代理对象:
通过Proxy.newProxyInstance()方法(对应JDK动态代理)或者Enhancer.create()方法(对应CGLIB动态代理)来创建代理对象,传入目标对象和调用处理器。
4. 调用代理对象方法:
通过代理对象调用方法,实际上会触发调用处理器的invoke()方法或者intercept()方法,在这些方法中可以进行额外的操作。
三、与其他比较:
相比静态代理,动态代理的优势在于更加灵活和动态。动态代理可以在运行时生成代理类,无需编写大量重复的代理类代码,可以更加方便地对目标对象进行代理。另外,动态代理可以实现对接口或者类的代理,更加具有通用性。
以下是一个使用JDK动态代理的示例代码,用于在调用目标对象方法前后进行一些操作:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello, world!");
}
}
class HelloInvocationHandler implements InvocationHandler {
private final Hello target;
public HelloInvocationHandler(Hello target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoking method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After invoking method: " + method.getName());
return result;
}
}
public class DynamicProxyExample {
public static void main(String[] args) {
Hello hello = new HelloImpl();
HelloInvocationHandler handler = new HelloInvocationHandler(hello);
Hello proxy = (Hello) Proxy.newProxyInstance(
hello.getClass().getClassLoader(),
hello.getClass().getInterfaces(),
handler
);
proxy.sayHello();
}
}
运行结果:
Before invoking method: sayHello
Hello, world!
After invoking method: sayHello
这段代码中,我们定义了一个Hello接口和其实现类HelloImpl。
然后,我们实现了一个InvocationHandler接口的实现类HelloInvocationHandler,它作为代理的调用处理器,在invoke()方法中,在调用目标方法前输出日志,然后调用目标方法,最后在调用后输出日志。
在主函数中,我们创建了一个代理对象,通过Proxy.newProxyInstance()方法传入目标对象和调用处理器来生成代理对象。最后,我们通过代理对象调用sayHello()方法,实际上会触发调用处理器的invoke()方法,在该方法中进行了额外的操作。
需要注意的是,代理对象实际上是实现了Hello接口的一个动态生成的匿名类的实例,这个类继承了Proxy类并实现了Hello接口。
(文章为作者在学习java过程中的一些个人体会总结和借鉴,如有不当、错误的地方,请各位大佬批评指正,定当努力改正,如有侵权请联系作者删帖。)