AbstractApplicationContext context = new FileSystemXmlApplicationContext("beans.xml");这个过程不仅会解析普通的<bean>标签,<aop>标签也会被解析。
1.IoC在解析XML的时候,DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)中解析根节点的子节点。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
isDefaultNamespace()判断标签的命名空间是不是http://www.springframework.org/schema/beans,不是的话表示该标签为自定义标签,调用parseCustomElement解析节点。<aop>竟然也算是自定义标签。
delegate在DefaultBeanDefinitionDocumentReader.createHelper方法创建的。
BeanDefinitionParserDelegate.parseCustomElement(Element ele):
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
readerContext是XmlReaderContext类的对象,是在DefaultBeanDefinitionDocumentReader中创建BeanDefinitionParserDelegate时,当构造函数的参数传入的。
this.delegate = createHelper(readerContext, root, parent);
protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
而DefaultBeanDefinitionDocumentReader的readerContext是在XmlBeanDefinitionReader.registerBeanDefinitions中创建DefaultBeanDefinitionDocumentReader的时候通过赋值的:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//返回DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
//createReaderContext(resource)就是readerContext的来源,返回XmlReaderContext对象
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
XmlBeanDefinitionReader.createReaderContext(resource)是readerContext的来源
protected XmlReaderContext createReaderContext(Resource resource) {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, this.namespaceHandlerResolver);
}
而这个this.namespaceHandlerResolver就是BeanDefinitionParserDelegate.parseCustomElement方法中this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);要调用的。
如果此对象为空,就创建一个createDefaultNamespaceHandlerResolver():
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
}
2.回到BeanDefinitionParserDelegate.parseCustomElement中,DefaultNamespaceHandlerResolver.resolve(String namespaceUri),根据标签<aop:config>去取相关的命名空间,在根据虚拟的命名空间去取对应的解析类。
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}
getHandlerMappings():
private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>();
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return this.handlerMappings;
}
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);载入配置文件的信息,配置文件地址变量this.handlerMappingsLocation的来源:
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
private final String handlerMappingsLocation;
public DefaultNamespaceHandlerResolver() {
this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
this.handlerMappingsLocation = handlerMappingsLocation;
}
将所有包/META-INF/spring.handlers文件内容保存到Map类型的handlerMappings属性中。
AOP的标签<aop>对应的命名空间是http://www.springframework.org/schema/aop,在/spring-aop/src/main/resources/META-INF/spring.handlers这个文件中看看spring.handlers的内容:http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
这里将配置文件开头的命名空间虚拟路径和真实的类关联起来。
暂时回到DefaultNamespaceHandlerResolver.resolve(String namespaceUri)中,AopNamespaceHandler被创建时会执行init初始化操作:
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
3.将由这个AopNamespaceHandler类将<aop:config>的配置信息转为BeanDefinition
AopNamespaceHandler继承NamespaceHandlerSupport,
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
返回<aop:config>标签对应的解析类,AopNamespaceHandler.init()方法中已经配置了——ConfigBeanDefinitionParser。
4.到了这里,spring才有解析<aop:config>的意思,ConfigBeanDefinitionParser.parse(Element element, ParseContext parserContext):
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
configureAutoProxyCreator(parserContext, element);创建AspectJAwareAdvisorAutoProxyCreator实例,备用。
/**
* Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions}
* created by the '<code><aop:config/></code>' tag. Will force class proxying if the
* '<code>proxy-target-class</code>' attribute is set to '<code>true</code>'.
* @see AopNamespaceUtils
*/
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary()
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, 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;
}
registry是DefaultListableBeanFactory的实例,registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
将BeanDefinition保存到其beanDefinitionMap属性中。
在AbstractApplicationContext.refresh()中会调用registerBeanPostProcessors()方法将此bean实例化, 并调用beanFactory.addBeanPostProcessor()将其保存到AbstractBeanFactory的属性beanPostProcessors中。(AspectJAwareAdvisorAutoProxyCreator通过复杂继承关系算是实现了BeanPostProcessor接口)
5.开始解析<aop:aspect>标签ConfigBeanDefinitionParser.parseAspect():
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
List<BeanReference> beanReferences = new ArrayList<BeanReference>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
for循环中的isAdviceNode(node, parserContext)做为过滤条件将只解析before、after、after-returning、after-throwing、around这样的子标签
/**
* Return <code>true</code> if the supplied node describes an advice type. May be one of:
* '<code>before</code>', '<code>after</code>', '<code>after-returning</code>',
* '<code>after-throwing</code>' or '<code>around</code>'.
*/
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
if (!(aNode instanceof Element)) {
return false;
}
else {
String name = parserContext.getDelegate().getLocalName(aNode);
return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
}
}
将aspectName=log,aspectElement=<aop:aspect>,adviceElement=<aop:after>...当参数传入parseAdvice,解析切面类。
/**
* Parses one of '<code>before</code>', '<code>after</code>', '<code>after-returning</code>',
* '<code>after-throwing</code>' or '<code>around</code>' and registers the resulting
* BeanDefinition with the supplied BeanDefinitionRegistry.
* @return the generated advice RootBeanDefinition
*/
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
methodDefinition切面信息,包含切面类、方法
createAdviceDefinition()方法将切面信息、切入点信息的整合关联。advisor=advice+pointCut
/**
* Creates the RootBeanDefinition for a POJO advice bean. Also causes pointcut
* parsing to occur so that the pointcut may be associate with the advice bean.
* This same pointcut is also configured as the pointcut for the enclosing
* Advisor definition using the supplied MutablePropertyValues.
*/
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));根据切面的类型(如before、after等)调取相应的类,创建切面类信息。
private Class getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
Object pointcut = parsePointcutProperty(adviceElement, parserContext);返回切入点信息(例子中,配置文件beans.xml中的servicesPointcut)。
/**
* Parses the <code>pointcut</code> or <code>pointcut-ref</code> attributes of the supplied
* {@link Element} and add a <code>pointcut</code> property as appropriate. Generates a
* {@link org.springframework.beans.factory.config.BeanDefinition} for the pointcut if necessary
* and returns its bean name, otherwise returns the bean name of the referred pointcut.
*/
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
parserContext.getReaderContext().error(
"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
else if (element.hasAttribute(POINTCUT)) {
// Create a pointcut for the anonymous pc and register it.
String expression = element.getAttribute(POINTCUT);
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(element));
return pointcutDefinition;
}
else if (element.hasAttribute(POINTCUT_REF)) {
String pointcutRef = element.getAttribute(POINTCUT_REF);
if (!StringUtils.hasText(pointcutRef)) {
parserContext.getReaderContext().error(
"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
return null;
}
return pointcutRef;
}
else {
parserContext.getReaderContext().error(
"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
}
advisor封装advice的信息(1:1),advice含有pointCut的信息(1:1)。
每个<aop:before>这种标签包含了类-方法信息,配置成一个advice。advisor是advice它的封装。