Spring Framework Aop原理
缘由
Spring Framework 提供了除IOC之外的很多有意思的功能,深入研究其技术原理,可在项目技术选型上提供更多的思路和技术把控。Spring Framewrok 代码由大佬精心打磨,可以从功能实现上学习和模仿。另外Spring Framework是Java项目开发的基础,其他技术框架都会基于或者与Spring 兼容,研究其中的技术原理,可快速掌握其他技术框架的技术原理,比如 Spring boot \ Spring cloud...
简述
Spring Framework 出现的背景是,Java 对象之间调用关系复杂,为简化对象调用,Spring Framework 基于Dependency Injection,将对象的控制权转移到BeanFactory,由框架负责对象的生命周期,将对象与Bean进行映射,Bean的生命周期由完善的管理机制。
Aop切面编程是区别于面向对象编程的,Spring Framework也提供了实现,成为 Spring's Aop,仅支持方法级别的切面编程,属于运行期织入,大名鼎鼎的Aspectj,属于更高级的一种框架,能够支持到构造器、方法、属性级别。
前提
Spring Framework 推出的Aop功能是基于Ioc实现的。需要对IOC的技术原理有一定的了解,另外对切面编程的基础有个基本的了解。
正文
应用
maven pom dependency
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
Application 项目EntryPoint
@ComponentScan
@Configuration
// 开启Aspectj注解支持
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
ServiceB serviceB = context.getBean("serviceB", ServiceB.class);
serviceB.say();
}
}
切面逻辑
@Aspect
@Component
public class AopTest {
@Pointcut("execution(* org.example.circularReference.*.*(..))")
public void pointCut() {
}
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AopTest ... ");
return pjp.proceed();
}
}
代码逻辑
@Service
public class ServiceB {
public void say() {
System.out.println("Application say ...");
}
}
@EnableAspectJAutoProxy
- 能够支持处理@Aspect标注的Component。
- 搭配@Configuration 注解一起使用。
- 设置属性 proxyTargetClass=true,仅用Cglib生成代理,接口或者对象代理,接口的默认代理实现是JDK proxy.
- 需要引入 aspectjweaver。
- 通过 @Import 注解引入 AspectJAutoProxyRegistrar。
AspectJAutoProxyRegistrar
注册AnnotationAwareAspectJAutoProxyCreator 到BeanDefinitionRegistry当中。
具体代码在:AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry)
RootBeanDefinition beanDefinition = new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
AnnotationAwareAspectJAutoProxyCreator
处理应用上下文所有AspectJ注解的aspects \ Spring Advisors,处理逻辑在 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
.
任何设置AspectJ注解的类都将被自动识别,Spring AOP的基于代理的model、方法连接点可以按照规则匹配。
通过UML图,creator 实现了 SmartInstantiationAwareBeanPostProcessor
接口,在 AbstractAutoProxyCreator
抽象类中实现了 postProcessBeforeInstantiation
postProcessAfterInitialization
方法,将Spring Aop 功能实现参与到 Bean 创建的过程中,将Bean的信息进行反射,获得Class信息与Advisor进行匹配,生成对应的代理类。
postProcessBeforeInstantiation 处理customeTargetSource。
postProcessAfterInitialization 处理实例化后的Bean,匹配Pointcut。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 通过早期代理的检查后,开始执行真正的aop逻辑
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
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);
return bean;
}
// Create proxy if we have advice. getAdvicesAndAdvisorsForBean 会是一个精彩的逻辑。
// 查找可以匹配的所有Advisor
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;
}
上述部分是由Aop实现一个大致逻辑。下面将会介绍Aop的具体工作原理。
getAdvicesAndAdvisorsForBean
查找可以匹配的所有Advisor。具体实现在 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
。
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 关键逻辑会在findEligibleAdvisors中延续。
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 关键逻辑将在buildAspectJAdvisors()中延续。
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
将Spring Beanfactory中@Aspect注解修饰的类转换为Spring Advisors.
- 获取所有的BeanDefinition集合
- 获取 Class 对象
- 判断类上是否有Aspect注解
- 获取类上的所有Advisor.
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 1.获取所有的BeanDefinition集合
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// 2.获取 Class 对象
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 3.判断是否有Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 4.获取类上的所有Advisor.
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
解析Aspect注解获取Advisor的关键代码:
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
advisorFactory:AspectJAdvisorFactory -> AbstractAspectJAdvisorFactory -> ReflectiveAspectJAdvisorFactory
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory
使用反射技术解析@Aspect修饰的类。
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 重点关注 getAdvisorMethods
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
// 重点关注 如何将解析后method转换为 advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();
// 解析@Aspect修饰的类,获取其中Advisor相关的方法。
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
if (methods.size() > 1) {
methods.sort(adviceMethodComparator);
}
return methods;
}
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
// AspectJExpressionPointcut
BeanFactoryAspectInstanceFactory
org.springframework.aop.aspectj.AspectInstanceFactory
接口的实现。
若使用原型模式,会被实例化多次,可能得到不正确的语义,可以使用 LazySingletonAspectInstanceFactoryDecorator 来装饰类,达到只实例化一次的效果。
InstantiationModelAwarePointcutAdvisorImpl
AspectJPointcutAdvisor的内部实现,@Aspect 修改的类中的每个方法都是一个advisor,也会只有一个实例就是此类。
AspectJExpressionPointcut
org.springframework.aop.Pointcut
接口的内部实现。使用Aspectj技术计算 pointcut 表达式(aspect表达式),表达式最后还是由Spring aop model 处理,只能支持到method级别。
以上是Spring Advisor 形成的过程。下面开始执行advisor匹配的过程。
// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 转移到 AopUtils 中
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
// AopUtils
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 转移方法
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// 执行重载方法的逻辑
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
// 真正执行匹配的逻辑
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
// AspectJExpressionPointcut
// 具体匹配逻辑在 aspectj 中,有兴趣的可以深入研究下。
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
obtainPointcutExpression();
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
// and there will never be matching subclass at runtime.
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
以上是 Spring Advisor 匹配的过程。
创建代理的部分就不做解释了。
以上就是Spring Aop 技术的原理。通读后可对Aop实现有个大致的理解,Spring 借助 AspectJ 的注解和表达式匹配,完成Spring Aop 的基础功能,同时又和Spring Ioc 进行融合。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。