spring 14 jdk 和 cglib 的统一
Spring 中对切点、通知、切面的抽象如下
- 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut
- 通知:典型接口为 MethodInterceptor 代表环绕通知
- 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut
代理相关类图
- AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现
- AopProxy 通过 getProxy 创建代理对象
- 图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)
- 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor
底层切点、通知、切面
模拟
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class S14 {
public static void main(String[] args) {
testSpringProxy1();
}
private static void testSpringProxy1() {
//定义切点 pointcut
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* cn.xyf.spring.s14.*.a(..))");
//定义通知 advice
MethodInterceptor advice = invocation -> {
System.out.println("前置增强...");
Object result = invocation.proceed();
System.out.println("后置增强...");
return result;
};
//定义切面 advisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
//使用工厂创建代理
// * 如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy
// * 如果没有指定接口,或者 proxyTargetClass = true,使用 ObjenesisCglibAopProxy
// * 例外:如果目标是接口类型或已经是 Jdk 代理,使用 JdkDynamicAopProxy
S14Bean2 target = new S14Bean2();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(target.getClass().getInterfaces());
proxyFactory.setProxyTargetClass(true);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
S14Bean1 proxy = (S14Bean1) proxyFactory.getProxy();
System.out.println(proxy.getClass());
proxy.a();
proxy.b();
}
}
class S14Bean2 implements S14Bean1{
@Override
public void a() {
System.out.println("S14Bean2 a running...");
}
public void a(int i) {
System.out.println("S14Bean2 a running" + i);
}
@Override
public void b() {
System.out.println("S14Bean2 b running...");
}
}
interface S14Bean1 {
void a();
void b();
}
- 底层的切点实现
- 底层的通知实现
- 底层的切面实现
- ProxyFactory 用来创建代理
- 如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy
- 如果没有指定接口,或者 proxyTargetClass = true,使用 ObjenesisCglibAopProxy
- 例外:如果目标是接口类型或已经是 Jdk 代理,使用 JdkDynamicAopProxy
注意
- 要区分本章节提到的 MethodInterceptor,它与之前 cglib 中用的的 MethodInterceptor 是不同的接口
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现