Summary
Spring's AOP namespace provides three tags <aop:config>, <aop:aspectj-autoproxy> and <aop:scoped-proxy>. The role of the first two tags is to specify pointcut to provide adivce processing, while the role of < aop: scoped-proxy > is to decorate beans with short lifecycles so that beans with short lifecycles can be correctly invoked by beans with long lifecycles. This article will not discuss the label of <aop:scoped-proxy>, but the discussion of <aop:config>. Resolving the config tag of aop namespace Now let's explore how spring resolves the < aop: aspectj-autoproxy > tag.
Parse < aop: aspectj-autoproxy > tag
The parser of <aop:aspectj-autoproxy> is AspectJAutoProxyBeanDefinitionParser, which directly implements the parse method of BeanDefinitionParser interface. Here is the source code of this method.
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
The parse method consists of two lines of code, one is to register the automated agent builder object in the container and the other is to parse the sublabel < aop: aspectj-autoproxy > < aop: include >. Let's look at the details of these two things separately.
1 Create an automatic agent builder object
The parse method calls the registerAspectJAnnotationAutoProxyCreator IfNecessary method of the AOP namespace tool class AopNamespace Utils to complete the task of registering the automatic proxy builder object in the container. The source code is as follows.
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// Register Auto Proxy Builder Object
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// Parsing proxy-target-class and expose-proxy attributes
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
Continue to look at the registerAspectJAnnotationAutoProxyCreatorIfNecessary method of the AOP configuration tool class AopConfigUtils, with the source code as follows.
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
// Register an AnnotationAwareAspectJAutoProxyCreator object in the container
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
Here is the registerOrEscalateApcAsRequired method of the AopConfigUtils tool class
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// Defined as AUTO_PROXY_CREATOR_BEAN_NAME= "org.spring framework.aop.config.internalAutoProxyCreator"
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// If an automatic proxy builder already exists in the container, compare the priorities of the two builders
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
// Save a high priority builder
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// If there is no automatic agent builder in the container
// Create the BeanDefinition object corresponding to the builder
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// Register the BeanDefinition object of the proxy builder in the container
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
AopConfigUtils gets the priority method of the agent builder as follows.
private static int findPriorityForClass(Class<?> clazz) {
return APC_PRIORITY_LIST.indexOf(clazz);
}
The following automatic agent builder is defined in AopConfigUtils
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>();
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
From the above code, we can see that Annotation Aware Aspect JAuto Proxy Creator has the highest priority, followed by Aspect JAware Advisor AutoProxy Creator, and Infrastructure Advisor AutoProxy Creator has the lowest priority.
2. parse < aop: include > subtags
The parse method of AspectJAutoProxyBeanDefinitionParser calls the extended BeanDefinition method of this class to parse the < aop: include > tag. The source code of this method is as follows.
private void extendBeanDefinition(Element element, ParserContext parserContext) {
// BeanDefinition to get the automated agent builder
BeanDefinition beanDef =
parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
if (element.hasChildNodes()) {
addIncludePatterns(element, parserContext, beanDef);
}
}
The purpose of the extended BeanDefinition method is to obtain the BeanDefinition object of the automatic proxy builder and to determine whether the definition of <aop:aspectj-autoproxy> in the configuration file still has child nodes. Let's continue to look at the addIncludePatterns method of AspectJAutoProxyBeanDefinitionParser with the following source code.
private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
ManagedList<TypedStringValue> includePatterns = new ManagedList<TypedStringValue>();
NodeList childNodes = element.getChildNodes();
// Traversing subnodes
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
// The apsect-autoproxy tag has only one subtag, which is the include tag.
// Here we determine whether a node is an Element object or not.
if (node instanceof Element) {
Element includeElement = (Element) node;
// Get the name attribute of the include tag
TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
valueHolder.setSource(parserContext.extractSource(includeElement));
includePatterns.add(valueHolder);
}
}
if (!includePatterns.isEmpty()) {
includePatterns.setSource(parserContext.extractSource(element));
// IncludePatterns obtained by parsing inculde tags are used to set the includePatterns attribute of the agent builder.
beanDef.getPropertyValues().add("includePatterns", includePatterns);
}
}
summary
Like <aop:aspectj-autoproxy> and <aop:config>, the automatic agent builder is first registered with the spring container. <aop:config> registers the AspectJAware Advisor AutoProxyCreator object, which is used to expose AspectJ's execution context and to follow AspectJ's rules for interpreting the execution order of multiple advice (enhancement) from the same aspect (aspect). <aop: aspectj-autoproxy> registers the Annotation Aware AspectJAutoProxyCreator object, which inherits the AspectJAware Advisor AutoProxyCreator class and handles all AspectJ annotations in the current spring container.