Java动态代理机制
- JDK动态代理
- 原理:JDK动态代理是基于接口实现的。它利用反射机制在运行时创建代理类的字节码,该代理类实现了目标接口,并在代理类的方法中调用InvocationHandler的invoke方法来处理实际的业务逻辑。
- 实现方式:
- 定义一个接口,目标类实现该接口。
- 创建一个实现InvocationHandler接口的类,在invoke方法中编写代理逻辑。
- 使用Proxy类的静态方法newProxyInstance创建代理对象。
- InvocationHandler接口:该接口只有一个invoke方法,代理对象的方法调用都会转发到这个invoke方法。invoke方法接收三个参数:代理对象本身、被调用的方法对象、方法的参数数组。通过反射调用目标对象的方法,并可以在前后添加额外的逻辑。
- Proxy类:提供了创建代理对象的静态方法newProxyInstance。该方法接收三个参数:类加载器、目标对象实现的接口数组、InvocationHandler实现类的实例。通过这个方法创建的代理对象会实现指定接口,并将方法调用转发给InvocationHandler。
- CGLIB动态代理
- 原理:CGLIB动态代理是基于继承实现的。它通过字节码生成库,在运行时生成目标类的子类,并重写目标类的方法,在子类方法中加入代理逻辑。
- 实现方式:
- 创建一个目标类(可以是普通类,不一定非要实现接口)。
- 创建一个实现MethodInterceptor接口的类,在intercept方法中编写代理逻辑。
- 使用Enhancer类来设置目标类、回调接口等信息,并创建代理对象。
- Enhancer类:CGLIB的核心类之一,用于生成代理类。通过设置目标类、回调接口等属性,调用create方法生成代理对象。它会在运行时动态生成目标类的子类,并将方法调用委托给MethodInterceptor。
- 区别
- JDK动态代理:要求目标对象必须实现接口,代理类实现相同接口;基于反射,性能相对较低。
- CGLIB动态代理:目标对象可以是普通类,代理类是目标类的子类;基于字节码生成,性能相对较高。
- 应用场景
- JDK动态代理:适用于目标对象实现了接口的场景,如常见的业务逻辑接口。
- CGLIB动态代理:适用于目标对象没有实现接口的场景,或者对性能要求较高的场景。
代码示例
- JDK动态代理示例
// 定义接口
interface HelloService {
void sayHello();
}
// 目标类实现接口
class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
System.out.println("Hello!");
}
}
// InvocationHandler实现类
class HelloInvocationHandler implements InvocationHandler {
private Object target;
public HelloInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
// 创建代理对象并调用方法
public class JDKProxyExample {
public static void main(String[] args) {
HelloService target = new HelloServiceImpl();
HelloInvocationHandler handler = new HelloInvocationHandler(target);
HelloService proxy = (HelloService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
proxy.sayHello();
}
}
- CGLIB动态代理示例
// 目标类
class HelloService {
public void sayHello() {
System.out.println("Hello!");
}
}
// MethodInterceptor实现类
class HelloMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invocation");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method invocation");
return result;
}
}
// 创建代理对象并调用方法
public class CGLIBProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloService.class);
enhancer.setCallback(new HelloMethodInterceptor());
HelloService proxy = (HelloService) enhancer.create();
proxy.sayHello();
}
}
性能优化方面
- 缓存代理对象:避免重复创建代理对象,减少创建代理对象的开销。
- 减少反射调用:在InvocationHandler或MethodInterceptor中,尽量减少反射调用的次数,例如可以缓存Method对象。
- 使用合适的代理方式:根据场景选择JDK动态代理或CGLIB动态代理,对于性能要求高且目标类未实现接口的场景,优先选择CGLIB。
- 优化字节码生成:对于CGLIB,可以通过调整字节码生成的参数来优化性能,如设置合适的缓存策略。