更多Java基础相关知识点详见个人主页【Java基础相关】专栏
静态代理和动态代理
静态代理
定义
- 静态代理是一种在【编译时】确定代理类的代理方式。它通过手动创建代理类,该代理类实现了与被代理类相同的接口,并在方法中调用实际的被代理对象来完成相应的工作
工作流程
- 定义一个接口,该接口包含了要被代理对象的方法
- 创建一个代理类,实现上述接口,并在方法中调用实际的被代理对象来执行相应的操作
- 创建一个被代理对象的实例
- 创建代理对象的实例,将被代理对象的实例传递给代理对象
- 调用代理对象的方法,代理对象将方法调用传递给被代理对象进行处理
优缺点
- 优点:简单易懂
- 缺点:手动创建代理类,如果被代理类的方法很多,会导致代码冗余
动态代理
定义
- 动态代理是一种在【运行时】通过反射机制动态生成代理对象,并在代理对象上进行方法调用的编程技术,主要用于在不修改原有代码的基础上,增加或改变某些功能的执行流程
- 动态代理广泛应用于AOP(面向切面编程),RPC(远程过程调用)、事务管理等领域
- 在Java中,主要有JDK动态代理和CGLIB动态代理两种实现方式
JDK动态代理
原理
- JDK动态代理是基于接口的代理技术
- 它使用
java.lang.reflect.proxy
类和java.lang.reflect.InvocationHandler
接口来创建代理对象。当你调用代理对象的任何方法时,调用会被转发到InvocationHandler
的invoke
方法。你可以在这个invoke
方法中定义拦载逻辑,比如前置处理,后置处理等 - 为了使用 JDK动态代理,你的类必须实现一个或多个接口。JDK动态代理的局限性在于,它只能代理接口方法,如果你有一个类并希望代理其非接口方法,则不能使用 JDK动态代理
工作流程
- 定义一个接口及其实现类
- 创建一个实现了
InvocationHandler
接口的类,在该类的invoke
方法中定义代理逻辑 - 通过
Proxy.newProxyInstance
方法动态创建接口的代理对象
优缺点
- 优点:原生支持,无需引入额外依赖
- 缺点:只能代理接口,如果一个类没有实现任何接口,则不能使用JDK动态代理
代码实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 目标接口
interface MyService {
void doSomething();
}
// 目标对象的实现
class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("Doing something...");
}
}
// 动态代理处理器
class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(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) {
MyService target = new MyServiceImpl();
MyService proxy = (MyService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvocationHandler(target)
);
proxy.doSomething();
}
}
CGLIB动态代理
- CGLlB(Code Generation library)是一个强大的、高性能、高质量的代码生成库,它可以在运行时扩展 Java 类和实现,Java 接口
- 不同于JDK动态代理,CGLIB 不需要接口,它是通过继承方式实现代理的
- CGLB 底层通过使用一个小而快的字节码处理框架 ASM ,来转换字节码并生成新的类。不仅可以代理普通类的方法,还能代理那些没有接口的类的方法
工作流程
- 创建一个需要被代理的类
- 创建一个继承
MethodInterceptor
的代理类,在intercept
方法中定义代理逻辑 - 使用
Enhancer
类创建被代理类的子类,并设置回调
优缺点
- 优点:无需接口实现,在大量调用的场景下,其生成的代理对象在调用时性能比JDK动态代理高对
- 缺点:final 方法无效,需添加额外的依赖
代码实现
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 目标类
class MyService {
public void doSomething() {
System.out.println("Doing something...");
}
}
// CGLIB 代理处理器
class MyInterceptor 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;
}
}
// 使用 CGLIB 动态代理
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallback(new MyInterceptor());
MyService proxy = (MyService) enhancer.create();
proxy.doSomething();
}
}
静态代理和动态代理的区别
具体区别
- 静态代理:由程序员创建或者是由特定工具创建,在代码编译时就确定了被代理的类是一个静态代理。静态代理通常只代理一个类
- 动态代理:在代码运行期间,运用反射机制动态创建生成。动态代理代理的是一个接口下的多个实现类