Spring AOP
Spring AOP
Spring AOP(Aspect-Oriented Programming)是Spring框架的一部分,用于实现面向切面编程。它允许开发者分离横切关注点(cross-cutting concerns),比如日志记录、事务管理、安全检查等,从而提高代码的可维护性和重用性。
AOP 是 IOC 的一个扩展功能,是 IOC 流程中新增的一个扩展点,
Spring AOP的原理:动态代理。实例化的时候生成代理类,替代真实类对外提供服务。
1. 核心组件
1.1 @Aspect
作用
@Aspect的主要作用是标记一个类为一个切面(Aspect),表明该类包含了一些切面逻辑(如通知、切入点等)。Spring 会自动检测带有 @Aspect 注解的类,并为其创建代理对象。代理对象会在适当的时候调用切面中的通知方法。Spring 使用动态代理(JDK 动态代理或 CGLIB)来实现这一过程。
源码
@Retention(RetentionPolicy.RUNTIME)
@Target({ELementType.TYPE})
public @interface Aspect {
String value() default "";
}
切面通知类型
前置通知:@Before
后置通知:@After
返回通知:@AfterReturning
抛出通知:@AfterThrowing
环绕通知:@Around
2. 切面实现
Spring AOP 通过一系列机制自动识别这些被@Aspect标识的切面类,并为其创建代理对象,从而应用相应的通知(Advice)逻辑。
2.1 组件扫描
@ComponentScan
源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScan.class)
public @interface ComponentScan {
}
字段含义
basePackages、value: 扫描的基础包
nameGenerator: 自定义 Bean 名称生成器
scopeResolver: Bean 的作用域
lazyInit: 是否懒加载
ClassPathBeanDefinitionScanner
核心方法
scan
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
doScan
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// bean名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition abstractBeanDefinition) {
postProcessBeanDefinition(abstractBeanDefinition, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 应用代理模式
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
} else {
return scanCandidateComponents(basePackage);
}
}
scanCandidateComponents
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
String fileName = resource.getFilename();
if (fileName != null && fileName.contains(ClassUtils.CGLIB_CLASS_SEPERATOR)) {
// 忽略CGLIB生成的类文件
continue;
}
try {
MetadataReader metaDataReader = getMetaDataReaderFactory().getMetaDataReader(resource);
if (isCandidateComponent(metaDataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metaDataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
} catch (...) {
...
}
}
} catch (IOException ex) {
// ... ...
}
return candidates;
}
2.2 创建代理
核心类
AbstractAutoProxyCreator
DefaultAopProxyFactory
AbstractAutoProxyCreator
实现了接口 BeanPostProcessor
核心方法
postProcessBeforeInstantiation:在目标对象实例化之前创建代理对象
public @Nullable Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
// 判断是否需要跳过代理创建
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 如果 beanClass 是基础设施类或应该跳过代理创建,将其标记为非代理对象
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
}
}
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
buildProxy : 创建代理对象的具体实现
private Object buildProxy(Class<?> beanClass, @Nullable String beanName,
Object @Nullable [] specificInterceptors, TargetSource targetSource, boolean classOnly) {
// 暴露目标类信息
if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {
AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);
}
// 初始化代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 判断是否使用 CGLIB 动态代理,返回true,表示使用CGLIB
if (proxyFactory.isProxyTargetClass()) {
// 显式处理JDK代理对象 或 lambda表达式,保持兼容
if(Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
} else {
// 没有强制使用 CGLIB 代理标志,应用默认检查
// 判断是否应该使用 CGLIB 代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
// 评估代理接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader smartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = smartClassLoader.getOriginalClassLoader();
}
return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));
}
代理模式的选择 JDK 动态代理:需要目标对象至少实现一个接口。 CGLIB 代理:如果目标对象没有实现接口,则使用 CGLIB 生成子类代理。
postProcessAfterInitiation:在目标对象实例化之后创建代理对象
public @Nullable Object postProcessAfterInitiation(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
/**
* 如果 earlyBeanReferences 中存储的引用已经被更新或替换
* 说明 bean 可能已经经历了某种形式的变化或初始化。
* 需要重新评估是否需要为 bean 创建代理,以确保代理的正确性和一致性。
*/
if (this.earlyBeanReference.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
earlyBeanReferences:用来存储早期已经被初始化,但还未完全装配完毕的bean引用,可用于解决循环依赖问题。
wrapIfNecessary:给需要的类创建代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
targetSourcedBeans:允许开发者明确指定哪些bean需要特殊的代理处理
DefaultAopProxyFactory
createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || !config.hasUserSuppliedInterfaces()) {
// 使用Cglib代理模式
Class<?> targetClass = config.getTargetClass();
if (targetClass == null && config.getProxiedInterfaces().length == 0) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass == null || targetClass.isInterface() ||
Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
} else {
// 使用JDK动态代理
return new JdkDynamicAopProxy(config);
}
}
2.3 切面执行
核心类
DynamicAdvisedInterceptor ReflectiveMethodInvocation
DynamicAdvisedInterceptor
核心方法
intercept
public @Nullable Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// 设置当前代理到上下文
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获取目标对象
target = targetSource.getTarget();
Class<?> targetClass = target != null ? target.getClass() : null;
// 获取拦截器和动态拦截advice链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty()) {
// 直接调用目标
@Nullable Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
retVal = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain).proceed();
}
return processReturnType(proxy, target, method, args, retVal);
} finally {
// 释放目标资源
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
// 恢复旧的代理引用
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
ReflectiveMethodInvocation
核心方法
proceed
public @Nullable Object proceed() throws Throwable {
// 判断是否已经到达最后一个拦截器,如果是的话,调用实际的目标方法,即切入点方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() -1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.matcher().matches(this.method, targetClass, this.arguments)) {
return dm.interceptor().invoke(this);
} else {
return proceed();
}
} else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}