Spring フレームワークが XML モード設定の Bean 解析をどのように解析するかを以前に追跡しました (「SF Framework Together シリーズ 5.7 を学ぶ - モジュール Beans-BeanDefinition 解析」を参照)。この記事では主にアノテーション Bean を分析します (「SF Framework Together シリーズ 5.2 を学ぶ - 」を参照)。 Module Beans- 詳細については、「Bean メタデータ構成」) が Spring フレームワークによって解析される方法を参照してください。
アノテーションの設定
アノテーション Bean の構成は次のとおりです。
<!-- 配置注解模式 -->
<context:annotation-config/>
<!-- 注解模式:配置bean扫描路径 -->
<context:component-scan base-package="com.learnsf.main,com.learnsf.service,com.learnsf.demo"/>
エントリを解析中
アノテーション解析の開始点は、以下に示すように DefaultBeanDefinitionDocumentReader.parseBeanDefinitions です。
ここで、XML 解析はメソッド parseDefaultElement(ele, delegate) です。
これまでのエントリーの流れは「SF Framework Series 5.7 - モジュールBeans - BeanDefinition解析をまとめて学ぶ」を参照してください。
解析プロセス
注: NamespaceHandlerSupport は、異なる名前空間に従って異なるパーサーを選択します。SF には次の NamespaceHandler があります。
アノテーション Bean によって使用される名前空間は「context」であり、対応する NamespaceHandler は ContextNamespaceHandler です。
コード追跡
BeanDefinitionParserDelegate.parseCustomElement(要素要素)
デフォルト以外の名前空間で定義された要素を解決します。
//过渡类
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
// 解析一个非默认命名空间定义的元素
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取命名空间资源符
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间资源符获得对应的解析器 注1
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));
}
注 1: 使用される NamespaceHandler は、namespaceUri に従って解析され、異なる名前空間は異なる NamespaceHandler に対応します。正しい NamespaceHandler を見つける方法は、NamespaceHandlerResolver (DefaultNamespaceHandlerResolver) を通じて行われます。
DefaultNamespaceHandlerResolver.resolve(String namespaceUri)
namespaceUri に基づいて使用される NamespaceHandler を解析します。
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 根据namespaceUri从缓存获取handler
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
// 没有对应的handler
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler namespaceHandler) {
// 如果handler是NamespaceHandler,直接返回
return namespaceHandler;
}
else {
/* 如果handler不是NamespaceHandler(则是NamespaceHandler的className),则生成 */
String className = (String) handlerOrClassName;
try {
// 加载NamespaceHandler Class
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初始化 注1
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);
}
}
}
注 1: ここでの NamespaceHandler は ContextNamespaceHandler であり、コードは次のとおりです。
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
コードからわかるように、ContextNamespaceHandler は NamespaceHandlerSupport を継承し、ネームスペースでサポートされるさまざまな要素 BeanDefinition パーサーを登録するための init() メソッドのみを提供します。
NamespaceHandlerSupport.parse(Element 要素、ParserContext parserContext)
解析する要素に対応する BeanDefinitionParser パーサーを見つけます。
前の ContextNamespaceHandler.init() からわかるように、
要素 annotation-config は AnnotationConfigBeanDefinitionParser に対応し
、要素 common-scan は ComponentScanBeanDefinitionParser に対応します。
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 找元素对应的解析器:BeanDefinitionParser
BeanDefinitionParser parser = findParserForElement(element, parserContext);
// 根据元素解析bean 注1
return (parser != null ? parser.parse(element, parserContext) : null);
}
@Nullable
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;
}
注 1: 異なる要素は異なるパーサーに対応する場合があります。たとえば、
要素 context:annotation-config は AnnotationConfigBeanDefinitionParser に対応します。解析方法の詳細については、「SF フレームワーク シリーズを一緒に学ぶ 5.8 - モジュール Bean - アノテーション Bean の解析 2 - 解析」を参照してください。 annotation-config ";
要素 context:component-scan は、ComponentScanBeanDefinitionParser に対応します。解析方法の詳細については、「SF フレームワークシリーズを学ぶ 5.8 - モジュール Beans - Bean アノテーションの解析 3 - コンポーネントの解析」を参照してください。