上篇Spring AOP学习中已经基本介绍了AOP是如何使用的,本文章来说说AOP注解方法的源码细节
先提几个问题,在接下来的源码学习中发现答案
-
<aop:aspectj-autoproxy />
的工作原理是什么,能带来什么作用 - @Aspect是在什么时候被操作的
- 各个切入点是按照什么样的顺序执行
- 切入点是如何和对应的bean绑定在一起的
具体的demo可以看Spring AOP学习#注解
XML配置解析
AOP的配置最简单的方法就是在xml中加入<aop:aspectj-autoproxy />
,应该很清楚spring是选择什么命名空间去解析了,直接定位到AopNamespaceHandler 类,而且定位的是AspectJAutoProxyBeanDefinitionParser解析器,如果这点有什么疑问的话,最好是再看看spring xml的bean提取 源码学习,看完就懂了为什么会直接定位到该解析器
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
// AspectJAutoProxyBeanDefinitionParser 是我们这次关注的类
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
AspectJAutoProxyBeanDefinitionParser 类
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 可以生成AnnotationAwareAspectJAutoProxyCreator类的beandefinition
// 并注册到IOC容器中
extendBeanDefinition(element, parserContext);
// 扩展该bean的属性信息
return null;
}
private void extendBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinition beanDef =
parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
// 该bean其实就是上面所说的AnnotationAwareAspectJAutoProxyCreator的beandefinition
if (element.hasChildNodes()) {
addIncludePatterns(element, parserContext, beanDef);
// 如果包含了子节点可以添加额外的includePattern
}
}
private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
ManagedList<TypedStringValue> includePatterns = new ManagedList<TypedStringValue>();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element) {
Element includeElement = (Element) node;
TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
// 获取子属性key为name的值
valueHolder.setSource(parserContext.extractSource(includeElement));
includePatterns.add(valueHolder);
}
}
if (!includePatterns.isEmpty()) {
includePatterns.setSource(parserContext.extractSource(element));
beanDef.getPropertyValues().add("includePatterns", includePatterns);
// 给该beandefinition赋属性值,includePatterns
}
}
}
如上述代码中的AnnotationAwareAspectJAutoProxyCreator类创建中,如果跳进去能够看到还可以为该类设置proxy-target-class
和expose-proxy
两个boolean属性值。
也可以设置子属性值name,例如下面的设置
<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true">
<aop:include name="******" />
</aop:aspectj-autoproxy>
这样就清楚了这个xml配置的原理是如何,其实就是新添加了一个beandefinition而已。
Aspect 扫描和实例化
spring正常的注册的bean,如果没有加@Aspect注解也是没有用的,那么就来学习下是在什么时候被扫描到,以及后续的操作是什么。
如果大概看了AnnotationAwareAspectJAutoProxyCreator类的相关内容,可以知道AOP所有的aspect以及pointCut都存储在该对象中,所以扫描所有的注解@Aspect类,肯定是在AnnotationAwareAspectJAutoProxyCreator类的实例化之后!
在refresh()代码中,在实例化具体的bean之前,已经完成了spring层面的bean实例
image.png
在接下来对org.springframework.context.event.internalEventListenerProcessor对象实例化的过程中会完成对@aspect类的扫描操作,并把相关信息注入到上图圈住的AnnotationAwareAspectJAutoProxyCreator类中。
随着代码调试到AbstractAutoProxyCreator文件
AbstractAutoProxyCreator 类
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
// 从当前的cache容器获取到bean的name
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
// 该advisedBeans已经包含了该key,则直接退出不考虑
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
// 该bean不符合所有获取到的切面,设置为false
// shouldSkip方法看下面的代码
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 所有的注解信息已经获取到了
// 具体通过代理类生成一个对象信息
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 利用ProxyFactory 生成一个新的对象
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
AspectJAwareAdvisorAutoProxyCreator 类
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 获取所有的advisor,也就是PointCut,具体细节可看下面的函数执行过程代码
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}
BeanFactoryAdvisorRetrievalHelper 类
这个类是AnnotationAwareAspectJAutoProxyCreator的一个对象
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 还没准备好,首次进入该函数时,为null
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
// 获取到IOC容器中,所有类的类型是Advisor.class的
// 当然就我们当前的demo而言肯定是没有的,只有加上了Advisor.class注解的类
// 会继续进入到**buildAspectJAdvisors函数**中去获取到注解为Advisor.class的类
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// 第一次进入,确实为null
synchronized (this) {
aspectNames = this.aspectBeanNames;
// spring中为了确保线程安全,存在大量的类似double-check的代码
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 获取IOC所有类型为Object的类名称(肯定包含了注解@Aspect的相关类)
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
// 类名和includePatterns正则匹配不通过,则跳过,起到一个过滤的作用
// 匹配的是类似于com.demo.*这样的类名称
// 和上面说的<aop:include name="******" />相关联
continue;
}
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
// 获取其类型,如果为null,无效,跳过
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
// 注解包含了@Aspect 并且没有被AspectJ编译(字段以ajc$开头)的类
aspectNames.add(beanName);
// 本demo的beanName就是animalAop
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 获取该类所有的方法,例如@Before、@After等
// 取到该类所有的方法,按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 的顺序排序
// 依次遍历,如果发现了上述的注解,则保存pointCut到一个容器中
// 获取该类所有的共有方法,如果符合要求,也保存到容器中,最后返回到List中
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
// 如果是单例,则保存到cache共,否则保存到工厂cache中
}
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));
}
}
}
// 这里给aspectNames 赋值
// 需要注意到一旦赋值了,就不会为空,则不会再去扫描所有的bean,得到全部的AOP信息
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
// 能运行到这里的肯定是第二次执行,获取到需要的AOP的pointCut信息
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
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;
}
最后实例化代理对象AnimalImpl对象,经过调试来到了
image.png
AbstractAutoProxyCreator 文件
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && 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);
// 得到相关的advice
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;
}
如下图,调试中生成了最终的代理类
image.png
至此,整个的代理类的实现过程就全部完成了。
总结下整个AOP注解操作的过程
1、先利用xml配置,添加AnnotationAwareAspectJAutoProxyCreator类到IOC容器中
2、在实例化各种beanpostprocessor的时候,扫描IOC所有的bean,如果配置了includePattern属性,还需要对IOC容器的所有bean进行正则匹配,通过的才会进行接下来的操作
3、所有合适的bean遍历找到注解为@Aspect的类,轮询bean的方法,如果包含了Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
的注解方法,也需要收集起来,最后形成kv对,添加到AnnotationAwareAspectJAutoProxyCreator的cache容器中
4、实例化被代理的类之前需要实例化本身
5、从AnnotationAwareAspectJAutoProxyCreator存储的所有advisor匹配出符合规则的advisor
具体可看AopUtils抽象类的findAdvisorsThatCanApply 方法
6、最后生成一个ProxyFactory,添加上述得到的各种数据,生成代理类
再来回答文章前提到的几个问题
-
<aop:aspectj-autoproxy />
的工作原理是什么,能带来什么作用
无需再强调,如果还是无法理解,可以仔细阅读spring xml的bean提取 源码学习,带来的作用就是新增了一个管理Aspect的类,所有的advisor都是存放在这个类中
- @Aspect是在什么时候被操作的
beanpostprocessor实例化的时候,特指
org.springframework.context.event.internalEventListenerProcessor
类的实例化时,会去扫描所有的bean,检查是否存在@Aspect注解,如果有该注解,则添加到AnnotationAwareAspectJAutoProxyCreator中
- 各个切入点是按照什么样的顺序执行
切入点是按照
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
自定义的排序规则sort的操作的
- 切入点是如何和对应的bean绑定在一起的
相互独立的,只有在bean具体生成的时候从AnnotationAwareAspectJAutoProxyCreator中获取到合适的切面以及切点信息,最后生成代理类。
网友评论