今天记录一下Spring#Aop的功能实现过程,以及一些源码解析。
1、首先呢,Aop是从哪里开始的激活的?答案是@EnableAspectJAutoProxy
,这是基于注解驱动的,以前基于xml,我们开启注解功能,是用<aop:aspectj-autoproxy/>
。那么这两个操作都是怎么开启Spring#Aop功能的呢?直接进入源码,以注解版的为例子:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
//配置为true强行使用CGLIB动态代理,默认false的时候当类有接口的时候会自动使用Jdk原生的动态代理
boolean proxyTargetClass() default false;
//这个属性主要是用来在一些场景下开启动态代理 ex : (在同一service中调用同类方法会让@Transactional注解失效)
boolean exposeProxy() default false;
}
该注解是一个@Import
的派生注解,给容器中加入了一个名为AspectJAutoProxyRegistrar
的bean,查看该bean申明,发现其实现了ImportBeanDefinitionRegistrar
接口,该接口可以根据像容器中注册一些bean
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//核心代码
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
其中registerAspectJAnnotationAutoProxyCreatorIfNecessary
方法,见名知意,如果需要的话注册一个名为AspectJAnnotationAutoProxyCreator
的bean,根据猜想继续跟进
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
果然如猜想一样,那么registerOrEscalateApcAsRequired
又完成了什么操作呢?
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
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;
}
主要完成了两个操作:
其中AUTO_PROXY_CREATOR_BEAN_NAME
是一个字符串常量org.springframework.aop.config.internalAutoProxyCreator
- 如果容器中已经含有了
AUTO_PROXY_CREATOR_BEAN_NAME
,那么会拿将要注入的和容器中存在的bean的Order顺序做比较,优先级高的设置到ioc中 - 如果不存在,那么直接设置一个优先级最高的
AnnotationAwareAspectJAutoProxyCreator
,且他的名称为AUTO_PROXY_CREATOR_BEAN_NAME
然后我们要开始分析AnnotationAwareAspectJAutoProxyCreator
,使用IDEA查看继承关系:
Aop继承类图
其中红线会发现,这个bean其实是一个
BeanPostProcessor
的实现类,那么前面后置处理器分析文章我们知道BeanPostProcessor
会在Bean的初始化前后执行其后置方法,那么我们进入到继承体系中的AbstractAutoProxyCreator.postProcessAfterInitialization()方法
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//这里的cacheKey其实就是beanName,若beanName不存在,那么则是beanClass
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//如果提前的代理引用缓存中没有该bean的存在,那么将执行下面的包装方法
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
其中两个重要的地方,我写了注释,那么我们废话不多少直接进入关键的wrapIfNecessary(bean, beanName, cacheKey)
方法
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.
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;
}
其中主要步骤有下列几个:
- 缓存处理,这个是Spring会将所有bean都用
advisedBeans
给缓存起来,其属性申明如下,k是cacheKey,v是true/false,true则为需要增强的bean
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
- 判断是否是需要包装的类,这里会排出一些aop相关基础设施类和设置需要跳过的类,
- 其中
isInfrastructureClass
是用来判断是否是切面相关类,是则返回true -
shouldSkip
表明是否要跳过,其中主要逻辑就是判断是否以String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL"
结尾
- 其中
protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
return retVal;
}
//这是shouldSkip的核心逻辑
static boolean isOriginalInstance(String beanName, Class<?> beanClass) {
if (!StringUtils.hasLength(beanName) || beanName.length() !=
beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {
return false;
}
return (beanName.startsWith(beanClass.getName()) &&
beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
}
- 获取切面相关信息组装成
List<Advisosr>
,其中的Advisor
是封装了Advice
的接口类,这里是获取切面相关类的主要方法,可以调用练比较深,下面展示源码调用
1.入口,获取通知方法
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//获取符合条件的Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
//转化成数组
return advisors.toArray();
}
2.获取所有符合条件的Advisor
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//查找所有可用的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//查看所有可以申请的Advisor,使用注解获取方法上面的切入点方法是否一致
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
3.获取所有候选的Advisor,这里会调用子类AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors
扩展
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
//获取所有的Advisor类
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
//构建Advisor,主要就是通过切入点表达式来校验看时候匹配,以及将所有对应的通知方法转化为对应的xxxAdvice类
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
4.通过AspectMetadata
元数据来获取对应通知类的值,调用栈过深,直接到核心方法ReflectiveAspectJAdvisorFactory.getAdvisor
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;
}
//构造通过Advisor实现类,其中构造方法中有根据不同的通知方法类型,获取不同的Advisor实现类
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
5.调用InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice中的getAdvice方法构造返回对应通知方法的xxxAdvice类
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
AbstractAspectJAdvice springAdvice;
//根据不同通知注解获取不同的通知类
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
枚举对应关系:
其中枚举对应关系
最后根据不同注解类型获取的不同通知类:
所有通知类
- 最后使用动态代理创建代理类,会根据类是否具有接口来判断是启动jdk动态代理还是CGLIB
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
那么最后创建完了代理对象,当我们执行目标方法的时候自然就是执行代理对象的方法,Spring中使用JdkDynamicAopProxy
和CglibAopProxy
两个类来实现代理方法
以JdkDynamicAopProxy
为例,当执行目标方法的时候,会执行JdkDynamicAopProxy.invoke()
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
这里处理逻辑主要有三个地方
-
getInterceptorsAndDynamicInterceptionAdvice
,这里会将传递过来的Advisor []
转化成List<MethodInterceptor> chain
- 若拦截器链是空的,那么直接执行目标方法
- 若不为空,则包装成
MethodInvocation
,然后执行proceed()
方法,这里proceed()
方法是执行通知的最核心逻辑
public Object proceed() throws Throwable {
//这里是讲传递过来的List<MethodInterceptor>的size -1 和当前索引(默认初始化为-1)进行比较判断,若相等则执行目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 依次获取下一个拦截器`MethodInterceptor`
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果拦截器的类型是InterceptorAndDynamicMethodMatcher,则需要进行切入点表达式匹配
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
//通过则执行拦截器方法
return dm.interceptor.invoke(this);
}
else {
//不执行拦截器方法。
return proceed();
}
}
else {
//直接执行拦截器方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
而我们能看到这些MethodInterceptor
的类型都是
- MethodBeforeAdviceInterceptor
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
- AspectJAfterAdvice (无论如何都会在方法结束调用,源码在finally块里面调用说明了这一点)
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
网友评论