- 默认标签解析
parseDefaultElement
// 如果在默认标签中有自定义标签属性,还需要进行自定义标签解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); // 装饰者模式 + SPI
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
- 自定义标签解析:详细见下面分析。以 context:component-sacn 为例,在 ClassPathBeanDefinitionScanner 中,创建 BeanDefinition,
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
,然后对属性或注解进行解析,setXxx
两种标签都是先封装成 BeanDefinitionHolder,BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
、beanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
,再从 BeanDefinitionHolder 中拿出 beanDefinition、beanName,注册到 DefaultListableBeanFactory 中的 beanDefinitionMap、beanDefinitionNames 中,从 BeanDefinitionHolder 中拿出 alias,注册到 SimpleAliasRegistry 中的 aliasMap 中。
3. 自定义标签解析
3.1 自定义标签创建步骤
- 创建一个需要扩展的组件
- 定义一个 XSD 文件描述组件内容
- 创建一个类,实现 BeanDefinitionParser 接口,用来解析 XSD 文件中的定义、组件定义
- 创建一个 Handler 类,继承自 NamespaceHandlerSupport
- 编写 .handlers、.schemas
3.2 自定义标签创建举例
- 创建一个需要扩展的组件
public class Contact {
private String id;
private String userName;
private String email;
// getter、setter
}
- 定义一个XSD文件描述组件内容
META-INF/user.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.mustang.com/schema/user"
elementFormDefault="qualified">
<element name="contact">
<complexType>
<attribute name="id" type="string"/>
<attribute name="userName" type="string"/>
<attribute name="email" type="string"/>
</complexType>
</element>
</schema>
- 创建一个类,实现 BeanDefinitionParser 接口,用来解析 XSD 文件中的定义、组件定义
public class ContactBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
/**
* Element 对应的类
*/
@Override
protected Class<?> getBeanClass(Element element) {
return Contact.class;
}
/**
* 从 element 中解析并提取对应的元素
*/
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String userName = element.getAttribute("userName");
String email = element.getAttribute("email");
// 将提取的数据放入到 BeanDefinitionBuilder 中,待到完成所有 bean 的解析后统一注册到 beanFactory 中
if (StringUtils.hasText(userName)) {
builder.addPropertyValue("userName", userName);
}
if (StringUtils.hasText(email)) {
builder.addPropertyValue("email", email);
}
}
}
- 创建一个 Handler 类,继承自 NamespaceHandlerSupport
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("contact", new ContactBeanDefinitionParser());
}
}
- 编写 .handlers、.schemas
META-INF/spring.schemas
http\://www.mustang.com/schema/user.xsd=META-INF/user.xsd
META-INF/spring.handlers
http\://www.mustang.com/schema/user=com.mustang.custom.UserNamespaceHandler
- xml 配置自定义标签的 bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:user="http://www.mustang.com/schema/user"
xsi:schemaLocation=
http://www.mustang.com/schema/user http://www.mustang.com/schema/user.xsd">
<user:contact id="userId" email="userEmail" userName="userName"/>
</beans>
- 测试
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
Contact bean = (Contact)context.getBean("userId");
System.out.println(bean);
}
3.3 自定义标签解析流程
- 根据当前解析标签的头信息找到对应的 namespaceUri
- 加载 spring 所有 jar 中的 META-INF/spring.handlers 文件,并建立映射关系
- 根据 namespaceUri 从映射关系中找到对应的实现了 NamespaceHandler 接口的类
- 调用类的 init 方法完成标签解析类的注册
- 根据 namespaceUri 找到对应的解析类,然后调用 parser 方法完成标签解析
3.4 自定义标签解析源码
BeanDefinitionParserDelegate # parseCustomElement
public BeanDefinition parseCustomElement(Element ele) {
// containingBd 为父类 Bean,对顶层元素的解析应设置为 null
return parseCustomElement(ele, null);
}
BeanDefinitionParserDelegate # parseCustomElement
/**
* 对非默认命名空间的元素节点的解析,过程为:
* 1. 获取标签的 namespaceUri
* 2. 加载 META-INF/spring.handlers 配置文件,建立映射关系
* 3. 根据 namespaceUri 从映射关系中获取NamespaceHandler 处理类
* 4. 调用 NamespaceHandler 的 init 方法完成标签解析类的注册
* 5. 调用 NamespaceHandler 的 parse 方法开始真正标签解析过程
*/
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 1. 获取对应的命名空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 2. 根据命名空间找到对应的 NamespaceHandler
// 在 readerContext 初始化时其属性 namespaceHandlerResolver 已经被初始化为 DefaultNamespaceHandlerResolver 的实例,所以,
// 这里调用的 resolve 方法其实调用的是 DefaultNamespaceHandlerResolver 类中的方法
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 3. 调用自定义的 NamespaceHandler 进行解析
/**
* public class UserNamespaceHandler extends NamespaceHandlerSupport {
* @Override
* public void init() {
* registerBeanDefinitionParser("contact", new ContactBeanDefinitionParser());
* }
* }
*/
// 以上面为例,此时的 handler 已经被实例化为我们自定义的 UserNamespaceHandler,UserNamespaceHandler 也完成了初始化
// 调用 NamespaceHandlerSupport.parse
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
DefaultNamespaceHandlerResolver # resolve
public NamespaceHandler resolve(String namespaceUri) {
// 读取 spring.handlers 配置文件并将配置文件缓存到 map 中
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 的初始化方法
/**
* public class UserNamespaceHandler extends NamespaceHandlerSupport {
* @Override
* public void init() {
* registerBeanDefinitionParser("contact", new ContactBeanDefinitionParser());
* }
* }
*/
namespaceHandler.init();
// 记录在缓存
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
DefaultNamespaceHandlerResolver # getHandlerMappings
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
// 如果没有被缓存则开始进行缓存
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
if (logger.isTraceEnabled()) {
logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
}
try {
// this.handlerMappingsLocation 在构造函数中已经被初始化为:META-INF/spring.handlers
// DEFAULT_HANDLER_MAPPINGS_LOCATION
/**
* public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
* this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
* }
*/
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {
logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}
handlerMappings = new ConcurrentHashMap<>(mappings.size());
// 将 Properties 格式文件合并到 Map 格式的 handlerMappings 中
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}
NamespaceHandlerSupport # parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 寻找解析器并进行解析操作
// 结合示例,首先获取在 UserNamespaceHandler 类中的 init 方法中注册的对应的 UserBeanDefinitionParser 实例,并调用其 parse 进行进一步解析
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
我们自定义的 UserBeanDefinitionParser 继承 AbstractSingleBeanDefinitionParser,因此调用到 AbstractBeanDefinitionParser # parse
AbstractBeanDefinitionParser # parse
public final BeanDefinition parse(Element element, ParserContext parserContext) {
// 真正做解析的事情委托给 parseInternal,正是这句代码调用了我们自定义的解析函数
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error("Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 将 AbstractBeanDefinition 转化为 BeanDefinitionHolder 并注册
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
// 需要通知监听器进行处理
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}
AbstractSingleBeanDefinitionParser # parseInternal
// 并不是直接调用自定义的 doParse 函数,而是进行了一系列的数据准备,包括对 beanClass、scope、lazyInit 等属性的准备
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// 获取自定义标签中的 class,此时会调用自定义解析器如 ContactBeanDefinitionParser 中的 getBeanClass 方法
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
// 若子类没有重写 getBeanClass 方法,则尝试检查子类是否重写 getBeanClassName 方法
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
// 若存在父类,则使用父类的 scope 属性
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
// 配置延迟加载
builder.setLazyInit(true);
}
// 调用子类重写的 doParse 方法进行解析
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
AbstractSingleBeanDefinitionParser # doParse
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
doParse(element, builder);
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
}
public class ContactBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
/**
* Element 对应的类
*/
@Override
protected Class<?> getBeanClass(Element element) {
return Contact.class;
}
/**
* 从 element 中解析并提取对应的元素
*/
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String userName = element.getAttribute("userName");
String email = element.getAttribute("email");
// 将提取的数据放入到 BeanDefinitionBuilder 中,待到完成所有 bean 的解析后统一注册到 beanFactory 中
if (StringUtils.hasText(userName)) {
builder.addPropertyValue("userName", userName);
}
if (StringUtils.hasText(email)) {
builder.addPropertyValue("email", email);
}
}
}
3.5 context:component-scan自定义标签解析源码
以 <context:component-scan /> 为例
- 解析当前自定义标签的 namespaceUri
String namespaceUri = getNamespaceURI(ele);
- 加载所有 jar 中的 META-INF/spring.handlers
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
- 根据 namespaceUri 从映射关系中找到对应的实现了 NamespaceHandler 接口的类
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
- 调用类的 init 方法
namespaceHandler.init();
- 调用 parser 方法完成标签解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
return (parser != null ? parser.parse(element, parserContext) : null);
继续调用 ComponentScanBeanDefinitionParser # parse
/**
* 完成对 <context:component-scan base-package="com.mustang.service"/> 的解析
* component-scan 中还有其他属性如:scoped-proxy、use-default-filters
* 见下面 ###1 的分析
*/
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
// 扫描指定包中的 bean,见下面 ###2 的分析
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
// 注册 ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor,见 ###3
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
###1
ComponentScanBeanDefinitionParser # configureScanner
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
ComponentScanBeanDefinitionParser # createScanner
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters, readerContext.getEnvironment(), readerContext.getResourceLoader());
###2
ClassPathBeanDefinitionScanner # doScan
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
ClassPathScanningCandidateComponentProvider # findCandidateComponents
return scanCandidateComponents(basePackage);
ClassPathScanningCandidateComponentProvider # scanCandidateComponents
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
ClassPathBeanDefinitionScanner # doScan
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
registerBeanDefinition(definitionHolder, this.registry);
ClassPathBeanDefinitionScanner # registerBeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
BeanDefinitionReaderUtils # registerBeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
registry.registerAlias(beanName, alias);
DefaultListableBeanFactory # registerBeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
SimpleAliasRegistry # registerAlias
this.aliasMap.put(alias, name);
###3
ComponentScanBeanDefinitionParser # registerComponents
Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
AnnotationConfigUtils # registerAnnotationConfigProcessors
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);