AOP是通过动态代理实现的,代理方式有两种:JDK动态代理和CGLIB代理
①、JDK 动态代理是基于接口的代理,只能代理实现了接口的类。
使用 JDK 动态代理时,Spring AOP 会创建一个代理对象,该代理对象实现了目标对象所实现的接口,并在方法调用前后插入横切逻辑。
优点:只需依赖 JDK 自带的 java.lang.reflect.Proxy
类,不需要额外的库;缺点:只能代理接口,不能代理类本身。
示例代码:
public interface Service {
void perform();
}
public class ServiceImpl implements Service {
public void perform() {
System.out.println("Performing service...");
}
}
public class ServiceInvocationHandler implements InvocationHandler {
private Object target;
public ServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method");
Object result = method.invoke(target, args);
System.out.println("After method");
return result;
}
}
public class Main {
public static void main(String[] args) {
Service service = new ServiceImpl();
Service proxy = (Service) Proxy.newProxyInstance(
service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new ServiceInvocationHandler(service)
);
proxy.perform();
}
}
②、CGLIB 动态代理是基于继承的代理,可以代理没有实现接口的类。
使用 CGLIB 动态代理时,Spring AOP 会生成目标类的子类,并在方法调用前后插入横切逻辑。
优点:可以代理没有实现接口的类,灵活性更高;缺点:需要依赖 CGLIB 库,创建代理对象的开销相对较大。
示例代码:
public class Service {
public void perform() {
System.out.println("Performing service...");
}
}
public class ServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method");
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Service.class);
enhancer.setCallback(new ServiceInterceptor());
Service proxy = (Service) enhancer.create();
proxy.perform();
}
}
那么,选择CGLIB还是JDK动态代理呢?
如果继续再问下,JDK动态代理和CGLIB实际开发中怎么用呢?
假设我们有这样一个小场景,客服中转,解决用户问题:
public interface ISolver {
void solve();
}
第二步,实现对应接口
public class Solver implements ISolver {
@Override
public void solve() {
System.out.println("疯狂掉头发解决问题……");
}
}
第三步,动态代理工厂:ProxyFactory,直接用反射方式生成一个目标对象的代理,这里用了一个匿名内部类方式重写 InvocationHandler 方法。
public class ProxyFactory {
// 维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 为目标对象生成代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("请问有什么可以帮到您?");
// 调用目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("问题已经解决啦!");
return null;
}
});
}
}
第五步,客户端:Client,生成一个代理对象实例,通过代理对象调用目标对象方法
public class Client {
public static void main(String[] args) {
//目标对象:程序员
ISolver developer = new Solver();
//代理:客服小姐姐
ISolver csProxy = (ISolver) new ProxyFactory(developer).getProxyInstance();
//目标方法:解决问题
csProxy.solve();
}
}
②、CGLIB 动态代理实现:
第一步:定义目标类(Solver),目标类 Solver 定义了一个 solve 方法,模拟了解决问题的行为。目标类不需要实现任何接口,这与 JDK 动态代理的要求不同。
public class Solver {
public void solve() {
System.out.println("疯狂掉头发解决问题……");
}
}
第二步:动态代理工厂(ProxyFactory),ProxyFactory 类实现了 MethodInterceptor 接口,这是 CGLIB 提供的一个方法拦截接口,用于定义方法的拦截逻辑。
public class ProxyFactory implements MethodInterceptor {
//维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//为目标对象生成代理对象
public Object getProxyInstance() {
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建子类对象代理
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("请问有什么可以帮到您?");
// 执行目标对象的方法
Object returnValue = method.invoke(target, args);
System.out.println("问题已经解决啦!");
return null;
}
}
第三步:客户端使用代理,首先创建目标对象(Solver 的实例),然后使用 ProxyFactory 创建该目标对象的代理。通过代理对象调用 solve 方法时,会先执行 intercept 方法中定义的逻辑,然后执行目标方法,最后再执行 intercept 方法中的后续逻辑。
public class Client {
public static void main(String[] args) {
//目标对象:程序员
Solver developer = new Solver();
//代理:客服小姐姐
Solver csProxy = (Solver) new ProxyFactory(developer).getProxyInstance();
//目标方法:解决问题
csProxy.solve();
}
}