深入理解Sping AOP(二)
1.开启AOP
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
基于AspectJ注解形式开启AOP需要使用@EnableAspectJAutoProxy注解,进入这个注解,它通过@Import标签向容器当中导入了一个注册器AspectJAutoProxyRegistrar。
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;
}
然后AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar 接口,熟悉IOC容器的话应该能理解实现了在ImportBeanDefinitionRegistrar .registerBeanDefinitions()方法中可以动态的往容器里面添加Bean的配置(BeanDefinition)信息,也就是向BeanFactory中注册AnnotationAwareAspectJAutoProxyCreator对象的BeanDefinition信息。
观察继承关系图,因为它是后置处理器,所有在容器启动的Refresh()方法中会执行registerBeanPostProcessors(beanFactory) 方法时候会创建它。
打断点能看到未执行registerBeanPostProcessors方法前BeanDefinitionMap中是存在这个BeanDefinition的。
单例池中和BeanPostProcessors是没有生成这个bean的。
执行该方法后能够看到单例池和BeanPostProcessors中存在了这个后置处理器的Bean。
以上都是IOC的内容。
上图是AnnotationAwareAspectJAutoProxyCreator后置处理器的注册和创建阶段的流程图。
到此为止,我们已经知道Refresh()方法中的registerBeanPostProcessors() 方法已经初始化这个Bean了,在singletonObjects(即单例池)中是能看到这个bean的。
那么这个后置处理器是如何操作的呢?
在Refresh()方法中的registerBeanPostProcessors() 后面有一个方法finishBeanFactoryInitialization() ,会初始化所有的单例对象,而后置处理器就是在实例化和初始化这些对象的过程中发挥作用的。
2.切面通知加载
AnnotationAwareAspectJAutoProxyCreator的父类实现了InstantiationAwareBeanPostProcessor,而该接口继承了后置处理器BeanPostProcessor接口,他的父类有这么几个实现方法;
//bean实例化前的回调操作
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
}
//bean实例化后的回调操作
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
}
//bean实例化完成后初始化之前回调操作
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
}
//bean实例化完成初始化之后回调操作
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
}
这里提前介绍说明一下:postProcessBeforeInstantiation方法中会加载切面及通知。
SpringIOC的refresh()方法包含了许多逻辑,其中在finishBeanFactoryInitialization()方法中,开始了解析AnnotationAwareAspectJAutoProxyCreator的工作。
熟悉一下IOC初始化bean的过程:
preInstantiateSingletons() -----> getBean() -----> doGetBean() ----->getSingleton(尝试从缓存中获取)---->lamda内部类方法getObject----->CreatBean();
在CreatBean方法中有一个方法:resolveBeforeInstantiation(beanName, mbdToUse);
该方法就会遍历所有后置处理器,调用InstantiationAwareBeanPostProcessor类型的后置处理器的postProcessBeforeInstantiation方法。
正好容器中@EnableAspectJAutoProxy为我们添加了该类型的后置处理器。所以每次单实例bean创建的时候都会调用该方法。
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
会先尝试返回一个代理对象,如果返回不成功,那么就执行doCreatBean方法。
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 调用AnnotationAwareAspectJAutoProxyCreator的postProcessorsBeforeInstantiation()
// 其实是父类AbstractAutoProxyCreator中的
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
//调用AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
在看postProcessBeforeInstantiation()之前先看下我写的切面类,
@Component
@Aspect
public class Aop {
/**
* 切面
*/
@Pointcut("execution(* com.yang.service..*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before() {
System.out.println("增强-------------------------------------------");
}
}
我的demo中切面类叫AOP,接下来就看postProcessBeforeInitialization()是如何解析@Aspect修饰的类的;
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String 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;
}
getAdvicesAndAdvisorsForBean方法,该方法的目的是获取并生成Advisor Bean。其中包含了扫描通过@Aspect注解配置且与Bean方法的匹配的Advice。
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
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;
}
什么是Advisor? 首先,Advice是增强方法,即@Around, @Before等注解修饰的方法。而Advisor则是在Advice之上再包了一层。例如PointcutAdvisor则包有Advice和Pointcut
findCandidateAdvisors()
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) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
这里findCandidateAdvisors在AbstractAdvisorAutoProxyCreator中有实现,同时被AnnotationAwareAspectJAutoProxyCreator重写了。
不过可以看到重写的方法中先调用了super.findCandidateAdvisor。
this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 从所有Bean中获取@Aspect配置的Bean并创建Advisor,也是我们关注的内容。
由于这段代码比较长,这里就不细说了,深挖的话还能再写一篇文章。
主要是通过beanName扫描@Aspect配置并生成Advisor的过程了。
其中this.advisorFactory.getAdvisors(factory)是生成Advisor类的具体内容。
findAdvisorsThatCanApply()
现在我们获得了所有的候选Advisor,那么找出和当前Bean匹配的Advisor呢?
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
会执行AopUtils.findAdvisorsThatCanApply
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;
}
最后定位到canApply()
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;
}
}
可以看出判断是否是该bean合适的advisor,是通过advisor.getPointcut().getClassFilter().matches(targetClass)方法来判断的。匹配完class以后下面还有MethodMatcher来匹配method。回想我们在配置pointcut的时候不仅仅有class的规则,也有method的规则。
当然,再深入matches方法进去的话就是pointcut的匹配语法实现了。有兴趣的可以自行阅读。
补充:代理对象创建流程链接深入理解Sping AOP(一)
转载自:https://juejin.cn/post/7107498277817286686