文章目录
引言
这篇文章,我们讲讲 Spring 的核心机制 AOP(Aspect-Oriented Programming,面向切面编程)是如何实现的?这种编程范式的核心思想,无论你是用哪种语言开发,一定对你有所帮助。
Spring AOP 官方解释
在 Spring 官网中有对 Spring AOP 的解释:

全文的意思是:
面向切面编程(AOP)通过提供另一种程序结构的思维方式,对面向对象编程(OOP)进行了补充。在 OOP 中,模块化的核心单元是类,而在 AOP 中,模块化的核心单元是切面。切面能够将那些横跨多个类型和对象的关注点(例如事务管理)进行模块化封装。(此类关注点在 AOP 领域常被称为**“横切关注点”**)。
Spring 框架的核心组件之一是 AOP 框架。尽管 Spring 的 IoC 容器并不依赖于 AOP(即您可以不启用 AOP 功能),但 AOP 与 Spring IoC 的结合,共同提供了一个功能强大的中间件解决方案。
在 Spring 框架中,AOP 主要用于以下场景:
- 提供声明式企业服务:其中最重要的服务是声明式事务管理(例如通过
@Transactional注解实现)。 - 支持用户自定义切面:允许开发者通过 AOP 扩展 OOP 的能力,将业务逻辑与横切关注点解耦。
源码解析
调试用例
假如我们有这么一个Aspect(切面):
@Aspect
@Component
public class LogAspect {
@After("execution(* org.springframework.boot.launchscript.controller.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature());
}
@Before("execution(* org.springframework.boot.launchscript.controller.Laun*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature());
}
}
@RestController
public class LaunchVerificationController {
@RequestMapping("/testJdkProxy")
public String testJdkProxy() {
userService.createUser("testJdkProxy");
System.out.println("是否为JDK代理: " + AopUtils.isJdkDynamicProxy(userService));
System.out.println("是否为CGLIB代理: " + AopUtils.isCglibProxy(userService));
return "testJdkProxy done";
}
}
创建AOP代理对象的过程
applyBeanPostProcessorsAfterInitialization 初始化后置处理
Spring Boot 启动后,我们在 createBean 的 初始化阶段,也就是 initializeBean 方法中,在 invokeInitMethods 执行完初始化后,执行 applyBeanPostProcessorsAfterInitialization,内部是遍历 BeanPostProcessor 进行责任链式的处理


其中,其中一个 BeanPostProcessor 实现类 AbstractAutoProxyCreator 执行了postProcessAfterInitialization,这里就是代理的执行入口。
AbstractAutoProxyCreator#wrapIfNecessary 如需要就包装

AbstractAutoProxyCreator#postProcessAfterInitialization 执行了 AbstractAutoProxyCreator#wrapIfNecessary 方法。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { // 1. 检查是否为手动指定的 TargetSource Bean(例如通过 @Bean 自定义 TargetSource)
return bean; // 已自定义 TargetSource,无需代理
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { // 2. 检查缓存是否已标记该 Bean 不需要代理
return bean; // 直接返回原始 Bean
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 3. 排除基础设施类(如 Advice/Advisor 等)和应跳过的类(如切面类自身)
this.advisedBeans.put(cacheKey, Boolean.FALSE); // 标记为不代理
return bean;
}
/// 4. 核心逻辑:获取适用于该 Bean 的增强(Advice)和切面(Advisor)
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) { // 5. 判断是否需要创建代理 // 存在适用的增强逻辑
this.advisedBeans.put(cacheKey, Boolean.TRUE); // 标记为已代理
Object proxy = createProxy( // 6. 创建代理对象(JDK 或 CGLIB)
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 封装原始 Bean 为 TargetSource
this.proxyTypes.put(cacheKey, proxy.getClass()); // 记录代理类型
return proxy; // 返回代理对象
}
// 7. 无增强逻辑,标记为不代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
AbstractAutoProxyCreator#wrapIfNecessary 最重要的两个步骤
- 用 getAdvicesAndAdvisorsForBean 获取 我们定义的Aspect的拦截器数组 specificInterceptors,这里底层是通过匹配表达式来做的。
- 调用 AbstractAutoProxyCreator#createProxy 去创建代理对象 proxy,最终获取到的 obj 对象为 LaunchVerificationController$$EnhancerBySpringCGLIB$$c16af234@6495
CGLIB 代理对象的命名规则:
LaunchVerificationController:原始目标类的类名。$$EnhancerBySpringCGLIB$$:Spring 使用 CGLIB 生成代理类的固定前缀。c16af234:CGLIB 生成的唯一标识符(十六进制哈希值)。@6495:代理对象实例的内存地址哈希码(Object.toString()默认输出)。

从截图的表达式可以看出,我们从 getAdvicesAndAdvisorsForBean 获取了我们写的 @Aspect 的拦截器 pointcut(切入点)。
AbstractAutoProxyCreator#createProxy 创建代理
接下来就是创建代理:AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 1. 暴露目标类的 Class 到 BeanFactory(用于其他后处理器识别原始类型)
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 2. 创建代理工厂并继承全局配置(如 proxyTargetClass、exposeProxy 等)
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); // 从当前 AutoProxyCreator 继承配置
// 3. 确定代理类型(JDK 动态代理 或 CGLIB)
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) { // 根据条件判断是否强制使用 CGLIB 代理
proxyFactory.setProxyTargetClass(true); // 启用 CGLIB
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory); // 检查 Bean 是否有接口,决定是否使用 JDK 动态代理
}
}
// 4. 构建 Advisor 链(将拦截器转换为 Spring AOP 的 Advisor 对象)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource); // 5. 设置目标源(原始 Bean 的包装)
customizeProxyFactory(proxyFactory); // 6. 允许子类自定义 ProxyFactory(扩展点)
proxyFactory.setFrozen(this.freezeProxy); // 7. 冻结配置(代理生成后禁止修改,提升性能)
if (advisorsPreFiltered()) { // 8. 标记 Advisors 是否已预过滤(优化拦截器执行)
proxyFactory.setPreFiltered(true);
}
/// 9. 生成代理对象(根据 proxyTargetClass 选择 JDK/CGLIB)
return proxyFactory.getProxy(getProxyClassLoader());
}
步骤拆解:
- buildAdvisors 构建 Advisor 链(将拦截器转换为 Spring AOP 的 Advisor 对象)
- proxyFactory.getProxy 生成代理对象(根据 proxyTargetClass 选择 JDK/CGLIB)
buildAdvisors 是做了转换,先不深入,主要看 proxyFactory.getProxy(ProxyFactory#getProxy)
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader); // 创建一个 AOP 代理对象,并通过指定的类加载器获取代理实例
}
getProxy 分为了两步,createAopProxy 创建AOP代理 -> getProxy 获取AOP代理
DefaultAopProxyFactory#createAopProxy 进行 CGLIB/JDK 的选择
createAopProxy 走到了这里,去执行动态代理方案 CGLIB/JDK 的选择:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 条件1: 优化模式开启 | 强制代理目标类 | 无用户指定接口 → 倾向使用 CGLIB
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");// 无法确定目标类:创建代理需要至少一个接口或具体目标类
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { // 条件2: 目标类本身是接口 或 已为 JDK 代理类 → 回退 JDK 代理
return new JdkDynamicAopProxy(config); /// JDK 动态代理
}
return new ObjenesisCglibAopProxy(config); /// 否则使用 CGLIB(优先 Objenesis 绕过构造器优化)
}
else {
return new JdkDynamicAopProxy(config); /// 默认使用 JDK 动态代理(需存在接口)
}
}
我们的用例则是获取到了 ObjenesisCglibAopProxy,可以看出是要执行 Cglib 代理
createAopProxy 创建了AOP代理,接下来就是去getProxy获取代理 ,CglibAopProxy#getProxy 逻辑,核心就是通过配置 Enhancer 去创建代理对象,最终 enhancer.create 去创建代理对象。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass(); // 1. 获取目标类并校验
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
// 2. 处理 CGLIB 多层代理场景
Class<?> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { // 判断是否已是 CGLIB 代理类
proxySuperClass = rootClass.getSuperclass(); // 如果是 CGLIB 代理类,取其父类作为代理基类
Class<?>[] additionalInterfaces = rootClass.getInterfaces(); // 将原代理类的接口继承到新代理配置中
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader); // 3. 类合法性校验(如 final 修饰符检查)
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer(); // 4. 配置 CGLIB Enhancer(核心代理生成器)
if (classLoader != null) {
enhancer.setClassLoader(classLoader); // 4.1 设置类加载器
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false); // 动态类加载器优化:禁用缓存确保热加载生效
}
}
enhancer.setSuperclass(proxySuperClass); // 4.2 设置父类(代理类将继承此类)
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); // 4.3 设置代理接口(合并用户指定的接口和 SpringProxy 标记接口)
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); // 4.4 命名策略(生成类似 UserService$$EnhancerBySpringCGLIB$$12345a 的类名)
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); // 4.5 生成策略(处理类加载器上下文)
Callback[] callbacks = getCallbacks(rootClass); // 5. 创建回调链(包含拦截器、目标方法调用等)
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass(); // 5.1 获取回调类型数组(用于后续CallbackFilter匹配)
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter( // 6. 设置回调过滤器(决定不同方法使用哪个Callback)
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks); /// 7. 生成代理类并创建实例(核心生成逻辑)
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex); // 典型异常:目标类是 final 类或非可见类
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex); // 其他未知异常(如目标对象获取失败)
}
}
进入到 ObjenesisCglibAopProxy#createProxyClassAndInstance
@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass(); // 1. 生成代理类字节码并加载到JVM
Object proxyInstance = null;
// 2. 优先尝试通过Objenesis库创建实例(绕过构造器)
if (objenesis.isWorthTrying()) { // 检查是否值得尝试(根据黑名单/白名单配置)
try { // 2.1 Objenesis的newInstance方法不需要调用构造器
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) { // 2.2 Objenesis创建失败时记录日志(非致命错误,可回退)
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex); // 无法通过Objenesis实例化代理,将回退到常规构造方法创建
}
}
// 3. Objenesis创建失败时的备选方案:反射调用默认构造器
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try { // 3.1 根据是否预定义构造器参数选择构造器
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor); // 3.2 确保私有构造器可访问
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance()); // 3.3 通过反射创建实例
}
catch (Throwable ex) { // 3.4 反射创建失败时抛出致命异常
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex); // Objenesis和常规构造器实例化均失败
}
}
// 4. 将回调链设置到代理实例(CGLIB的Factory接口方法)
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
CGLIB 下 Enhancer 创建代理

这里 Enhancer 创建动态代理的逻辑可以简化为:(仅供参考)
// 生成CGLIB代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Xxx.class); // 继承方式代理
Class<?> proxyClass = enhancer.createClass(); // 生成代理类字节码并加载到JVM
Object proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); // 绕过构造函数创建对象实例
((Factory) proxyInstance).setCallbacks(new Callbacks[]{(MethodInterceptor) (obj, method, args, proxy) -> {
// AOP 逻辑在这里..
return proxy.invokeSuper(obj, args);
}}); // 设置回调
return proxyInstance; // 最终代理对象
我们创建的对象就会返回CGLIB代理过的对象,这个代理对象取代了原先的 Bean,存在于IOC容器中。TODO CGLIB 底层原理我们暂且不深入探究,留个坑~
补充:getAdvicesAndAdvisorsForBean 扫描匹配的 Aspect
我们刚刚还有一个点没讲到,getAdvicesAndAdvisorsForBean 是如何匹配表达式的呢?
我持续深入debug,这里给出执行栈:
org.aspectj.weaver.patterns.SignaturePattern.matchesExactlyMethod(SignaturePattern.java:471)
at org.aspectj.weaver.patterns.SignaturePattern.matchesExactly(SignaturePattern.java:363)
at org.aspectj.weaver.patterns.SignaturePattern.matches(SignaturePattern.java:323)
at org.aspectj.weaver.patterns.KindedPointcut.matchInternal(KindedPointcut.java:202)
at org.aspectj.weaver.patterns.Pointcut.match(Pointcut.java:137)
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.getShadowMatch(PointcutExpressionImpl.java:319)
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesExecution(PointcutExpressionImpl.java:129)
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesMethodExecution(PointcutExpressionImpl.java:110)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getShadowMatch(AspectJExpressionPointcut.java:462)
- locked <0xffa> (a java.util.concurrent.ConcurrentHashMap)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getTargetShadowMatch(AspectJExpressionPointcut.java:447)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:295)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:251)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:289)
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:321)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:430)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1798)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
at
匹配方法:
org.aspectj.weaver.patterns.SignaturePattern#matchesExactlyMethod
/**
* 精确匹配方法签名是否符合切点表达式
*
* @param aMethod 待匹配的方法签名
* @param world 类型解析上下文(用于处理泛型等)
* @param subjectMatch 是否校验异常声明(当切点包含throws时启用)
* @return FuzzyBoolean 匹配结果(YES-匹配 / NO-不匹配 / MAYBE-可能匹配)
*/
private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) {
// 1. 快速失败:参数数量或类型明显不匹配
if (this.parametersCannotMatch(aMethod)) {
return FuzzyBoolean.NO;
}
// 2. 方法名不匹配(如切点表达式指定了特定方法名)
if (!this.name.matches(aMethod.getName())) {
return FuzzyBoolean.NO;
}
// 3. 校验异常声明(当切点包含throws子句时)
if (subjectMatch && !this.throwsPattern.matches(aMethod.getExceptions(), world)) {
return FuzzyBoolean.NO;
}
// 4. 校验声明类(declaring type)
if (!this.declaringType.isStar() &&
!this.declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
return FuzzyBoolean.MAYBE; // 可能因泛型擦除导致不确定
}
// 5. 校验返回类型
if (!this.returnType.isStar()) {
boolean isBangVoid = this.returnType.isBangVoid(); // 匹配非void类型
if (isBangVoid) {
String returnSig = aMethod.getReturnType().getSignature();
if (returnSig.length() == 1 && returnSig.charAt(0) == 'V') { // 'V'表示void
return FuzzyBoolean.NO; // 返回void但需要非void → 不匹配
}
} else if (this.returnType.isVoid()) { // 匹配void返回类型
String returnSig = aMethod.getReturnType().getSignature();
if (returnSig.length() != 1 || returnSig.charAt(0) != 'V') {
return FuzzyBoolean.NO; // 非void返回 → 不匹配
}
} else if (!this.returnType.matchesStatically(aMethod.getReturnType().resolve(world)) &&
!this.returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
return FuzzyBoolean.MAYBE; // 泛型类型可能擦除导致不确定
}
}
// 6. 处理可变参数(如切点表达式中的...)
if (this.parameterTypes.size() == 1 && this.parameterTypes.get(0).isEllipsis()) {
return FuzzyBoolean.YES; // 可变参数直接匹配
}
// 7. 参数数量不匹配
if (!this.parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
return FuzzyBoolean.NO;
}
// 8. 参数类型匹配
ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
ResolvedType[][] paramAnnotations = null;
// 9. 校验参数注解(当切点包含参数注解匹配时)
if (this.isMatchingParameterAnnotations()) {
paramAnnotations = aMethod.getParameterAnnotationTypes();
if (paramAnnotations != null && paramAnnotations.length == 0) {
paramAnnotations = null; // 无注解时忽略
}
}
// 10. 参数类型或注解不匹配
if (!this.parameterTypes.matches(rtl, TypePattern.STATIC, paramAnnotations).alwaysTrue() &&
!this.parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()),
TypePattern.STATIC, paramAnnotations).alwaysTrue()) {
return FuzzyBoolean.MAYBE; // 泛型导致可能匹配
}
// 11. 可变参数特殊处理(如匹配最后一个参数是数组)
if (!this.matchesVarArgs(aMethod, world)) {
return FuzzyBoolean.MAYBE;
}
// 12. 所有条件满足 → 完全匹配
return FuzzyBoolean.YES;
}
其实就是一直匹配下去,全部true才是匹配成功。
以小见大 —— 类名匹配算法
匹配逻辑有点多,我们只看类名匹配逻辑, this.declaringType.matchesStatically 走下去,直到 org.aspectj.weaver.patterns.WildTypePattern#innerMatchesExactly 这段逻辑。
/**
* 精确匹配输入字符串是否符合预定义的分段模式规则
*
* @param s 待匹配的原始字符串(例如类全限定名)
* @param isAnonymous 是否处理匿名类(影响结尾模式校验)
* @param convertDollar 是否将$视为分隔符(用于处理内部类)
* @return 是否完全匹配模式规则
*/
private boolean innerMatchesExactly(String s, boolean isAnonymous, boolean convertDollar) {
List<char[]> ret = new ArrayList(); // 存储分割后的字符串段
int startIndex = 0; // 当前处理段的起始位置
// 循环分割字符串(按.或$分隔)
while(true) {
// 查找下一个分隔符位置(优先.,convertDollar为true时考虑$)
int breakIndex = s.indexOf('.', startIndex);
if (convertDollar && breakIndex == -1) {
breakIndex = s.indexOf('$', startIndex); // 处理内部类分隔符
}
// 处理最后一段字符串
if (breakIndex == -1) {
// 添加最后一段字符数组
ret.add(s.substring(startIndex).toCharArray());
int segmentCount = ret.size(); // 总段数
int patternsLength = this.namePatterns.length; // 模式规则数量
// --- 规则校验阶段 ---
// 规则1:匿名类要求最后一个模式必须是通配符(如com.example..*)
if (!this.namePatterns[patternsLength - 1].isAny() && isAnonymous) {
return false;
}
// 场景1:无省略号模式(要求严格分段匹配)
if (this.ellipsisCount == 0) {
// 段数必须与模式数量严格一致
if (segmentCount != patternsLength) return false;
// 逐段匹配模式
for (int i=0; i<patternsLength; i++) {
if (!this.namePatterns[i].matches(ret.get(i))) {
return false;
}
}
return true; // 全匹配
}
// 场景2:单省略号模式(允许中间段数可变)
if (this.ellipsisCount == 1) {
// 最少需要满足 patternsLength-1 段(省略号占一个模式位)
if (segmentCount < patternsLength - 1) return false;
int matchIndex = 0; // 当前匹配段索引
for (int patternIndex=0; patternIndex<patternsLength; patternIndex++) {
NamePattern pattern = this.namePatterns[patternIndex];
if (pattern == NamePattern.ELLIPSIS) { // 遇到省略号模式
// 跳过后面的段,直到剩余模式能匹配剩余段
matchIndex = segmentCount - (patternsLength - patternIndex - 1);
} else if (!pattern.matches(ret.get(matchIndex++))) {
return false;
}
}
return true;
}
// 场景3:多个省略号模式(递归处理复杂匹配)
return outOfStar(
this.namePatterns,
ret.toArray(new char[0][]), // 转换成分段数组
0, // 当前模式索引
0, // 当前段索引
patternsLength - this.ellipsisCount, // 非省略号模式数
segmentCount, // 总段数
this.ellipsisCount // 省略号数量
);
}
// 截取当前段并存储
char[] segment = s.substring(startIndex, breakIndex).toCharArray();
ret.add(segment);
startIndex = breakIndex + 1; // 跳过分隔符继续处理
}
}
这个就是表达式匹配逻辑,是用分段匹配的方式进行,用“点”进行分割为数组,然后逐个匹配,我们的 namePatterns 如下:

我们的表达式是:org.springframework.boot.launchscript.controller.Laun*,被拆成了6段,然后等待被逐一匹配。
我们的待匹配类是:org.springframework.boot.launchscript.controller.LaunchVerificationController,被循环根据“点”号拆成了6段,然后依次加入到 ret 数组中。下一次循环,由于"点"号再也取不到, breakIndex = s.indexOf(46, startIndex) ,breakIndex 是 -1,所以进入最终匹配逻辑。
我们由于没有省略号 ellipsisCount == 0,所以进入以下循环:
while(patternsIndex < patternsLength) {
if (!this.namePatterns[patternsIndex++].matches((char[])ret.get(namesIndex++))) {
return false;
}
}
匹配的方法 org.aspectj.weaver.patterns.NamePattern#matches(char[]) 也是 aspectj 提供的匹配逻辑。

这里的匹配逻辑,就是一个算法:匹配有“星号”的字符串。
到这里,我们就知道了,我们提供的 Aspect 的表达式是如何被 match/canApply 的了。
被代理对象长什么样?
拓展:MVC 请求链路
我们知道代理Bean是如何被创建的,那么,代理完成的 Bean到底长什么样呢?
我们第一次 HTTP 请求,会有很多懒加载的 MVC 相关的 Bean 创建,走了代理流程,我们先不管,直接进入第二次请求。

执行栈为:
logBefore:17, LogAspect (org.springframework.boot.launchscript.aop)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeAdviceMethodWithGivenArgs:644, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invokeAdviceMethod:626, AbstractAspectJAdvice (org.springframework.aop.aspectj)
before:44, AspectJMethodBeforeAdvice (org.springframework.aop.aspectj)
invoke:55, MethodBeforeAdviceInterceptor (org.springframework.aop.framework.adapter)
proceed:186, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:749, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:95, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:186, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:749, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:691, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
testJdkProxy:-1, LaunchVerificationController$$EnhancerBySpringCGLIB$$59a6f870 (org.springframework.boot.launchscript.controller)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
doInvoke:190, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:138, InvocableHandlerMethod (org.springframework.web.method.support)
invokeAndHandle:105, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)
invokeHandlerMethod:878, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handleInternal:792, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handle:87, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)
doDispatch:1040, DispatcherServlet (org.springframework.web.servlet)
doService:943, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doGet:898, FrameworkServlet (org.springframework.web.servlet)
service:497, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:584, HttpServlet (javax.servlet.http)
handleRequest:74, ServletHandler (io.undertow.servlet.handlers)
doFilter:129, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
doFilterInternal:100, RequestContextFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:61, ManagedFilter (io.undertow.servlet.core)
doFilter:131, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
doFilterInternal:93, FormContentFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:61, ManagedFilter (io.undertow.servlet.core)
doFilter:131, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:61, ManagedFilter (io.undertow.servlet.core)
doFilter:131, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
handleRequest:84, FilterHandler (io.undertow.servlet.handlers)
handleRequest:62, ServletSecurityRoleHandler (io.undertow.servlet.handlers.security)
handleRequest:68, ServletChain$1 (io.undertow.servlet.handlers)
handleRequest:36, ServletDispatchingHandler (io.undertow.servlet.handlers)
handleRequest:68, RedirectDirHandler (io.undertow.servlet.handlers)
handleRequest:111, SSLInformationAssociationHandler (io.undertow.servlet.handlers.security)
handleRequest:57, ServletAuthenticationCallHandler (io.undertow.servlet.handlers.security)
handleRequest:43, PredicateHandler (io.undertow.server.handlers)
handleRequest:46, AbstractConfidentialityHandler (io.undertow.security.handlers)
handleRequest:64, ServletConfidentialityConstraintHandler (io.undertow.servlet.handlers.security)
handleRequest:60, AuthenticationMechanismsHandler (io.undertow.security.handlers)
handleRequest:77, CachedAuthenticatedSessionHandler (io.undertow.servlet.handlers.security)
handleRequest:43, AbstractSecurityContextAssociationHandler (io.undertow.security.handlers)
handleRequest:43, PredicateHandler (io.undertow.server.handlers)
handleRequest:43, PredicateHandler (io.undertow.server.handlers)
handleFirstRequest:269, ServletInitialHandler (io.undertow.servlet.handlers)
access$100:78, ServletInitialHandler (io.undertow.servlet.handlers)
call:133, ServletInitialHandler$2 (io.undertow.servlet.handlers)
call:130, ServletInitialHandler$2 (io.undertow.servlet.handlers)
call:48, ServletRequestContextThreadSetupAction$1 (io.undertow.servlet.core)
call:43, ContextClassLoaderSetupAction$1 (io.undertow.servlet.core)
dispatchRequest:249, ServletInitialHandler (io.undertow.servlet.handlers)
access$000:78, ServletInitialHandler (io.undertow.servlet.handlers)
handleRequest:99, ServletInitialHandler$1 (io.undertow.servlet.handlers)
executeRootHandler:376, Connectors (io.undertow.server)
run:830, HttpServerExchange$1 (io.undertow.server)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:750, Thread (java.lang)

请求先通过 undertow worker 线程,用 Connectors 处理 IO流,用 HttpServerExchange 封装请求进行流转,到经典的 DispatcherServlet#doDispatch,分发,其中 mappedHandler = this.getHandler(processedRequest); 就是拿到我们的处理器,也就是我们被代理的控制器的方法。其中,我们是从 requestMappingHandlerMapping 的 mappingRegistry 中通过 请求 url ,从 mappingLookup (url 和 beanName 、method 的映射情况 Map)拿到的匹配情况,然后后续再拿到 handler(HandlerMethod)。这时我们拿到的还只是 bean 名称。


那我们要看看如何拿到代理对象的?是后面通过 handlerMethod.createWithResolvedBean() ,直接从 beanFactory 也就是 IOC 容器中,根据名称获取 bean,当然我们这个流程已经是在 Spring Boot 启动后了,所以直接从 singletonObjects 一级缓存中获取。

我们逻辑往外走,后续是通过 InvocableHandlerMethod#doInvoke 桥接 Method 进行反射调用 bean(被代理的) 的mvc方法。

我们可以通过堆栈分析,执行到了 testJdkProxy:-1,也就是说这部分是动态生成的没有对应的源代码文件(字节码生成 class),这部分是没有源代码的,也就是说字节码是一个动态的东西,源码无法体现。我们看下字节码长什么样。
-Dcglib.debugLocation=./.cglib
-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
VM 参数加上这两个,就可以运行后看到cglib字节码。

我们看到的都是 IDEA 反编译后的,cglib 将 MethodInterceptor 织入到了逻辑里。
那我们继续往下调试,发现又到了有源代码的 DynamicAdvisedInterceptor#intercept,从这里我们可以看出,cglib 的代码是通过将拦截器的逻辑“织入”到字节码,然后在执行这个代理对象的被代理的方法的时候,调试时就会先走到“织入”的“盲区”,也就是字节码区,然后再回到程序的代码中来。来到 DynamicAdvisedInterceptor#intercept 进行处理。

DynamicAdvisedInterceptor#intercept 执行步骤如图:

拓展:不同的动态代理方案的对比
各种代理方式的对比:(网上提供的资料,真实性有待考究,仅供参考)
| 实现方式 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| JDK 动态代理 | 基于接口生成代理类($Proxy0) | 无额外依赖,标准 JVM 支持 | 要求目标类必须实现接口 |
| CGLIB 字节码增强 | 通过继承目标类生成子类(UserService$$EnhancerBySpringCGLIB$$...) | 支持代理无接口的类 | 无法代理 final 类/方法 |
| AspectJ 织入 | 编译时或类加载时直接修改字节码 | 性能高,支持更细粒度的切点(如构造器、字段) | 需要额外编译器(如 AspectJ Maven 插件) |
参考:
Spring技术内幕:深入解析Spring架构与设计原理(第2版)
Spring官方:https://docs.spring.io/spring-framework/reference/core/aop.html
Spring源码:https://github.com/spring-projects/spring-framework
关注公众号:【源码启示录】,解锁更多源码知识


877

被折叠的 条评论
为什么被折叠?



