1. 波及 SPI 机制中央
- 自定义标签:例如:context aop 等等都是自定义标签,须要利用 SPI 机制
- 默认标签中的自定义元素加载也波及到 SPI 机制
2. SPI 机制:
SPI 就是一个服务的扩大机制,能够把接口的实现类配置到 META-INF 元数据区,框架启动时加载到缓存,最后的版本是 jdk 中实现的,起初在 spring、springboot、dubbo 中都有相应的应用。
3. JDK 的 SPI 机制:
META-INF 下创立 services 目录,而后以接口全限定名为文件名,将实现类的全限定名放进去,这样运行程序时,会加载实现类的名称进 jvm,调用的时候会调用 newInstance()办法实例化对象。
示例:
- 创立一个 IAnimal 接口:
package com.hello.spi;
public interface IAnimal {void sing();
}
- 创立两个实现类:
package com.hello.spi;
public class Cat implements IAnimal {
@Override
public void sing() {System.out.println("cat sing......");
}
}
package com.hello.spi;
public class Dog implements IAnimal {
@Override
public void sing() {System.out.println("dog sing......");
}
}
// 全门路需和类门路保持一致
resource\META-INF.services\com.hello.spi.IAnimal
// 此门路文件下有
com.hello.spi.Cat
com.hello.spi.Dog
- 测试代码:
public class TestSPI {public static void main(String[] args) {ServiceLoader<IAnimal> animals = ServiceLoader.load(IAnimal.class);
for (Iterator<IAnimal> iter = animals.iterator();iter.hasNext();) {IAnimal animal = iter.next();
animal.sing();}
}
}
5. spring 的 spi 机制:
- 获取 spring 中所有 jar 包外面的 ”META-INF/spring.handlers” 文件,并且建设映射关系
- spring 的类 DefaultNamespaceHandlerResolver 这个类,会懒加载 spring.handler 文件内配置的实现类进内存
- 读取 META-INF/spring.handlers 目录下的实现类进 jvm
- 而后缓存到 handlerMappings,期待前面应用
- 这个是 spring-context 工程下 spring.handlers 文件 内容:key 为命名空间 url、value 为类的全限定名,加载实现后会缓存到 handlerMappings 中
// 此办法上一篇中有提到
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 {
// 加载 "META-INF/spring.handlers" 文件过程
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {logger.trace("Loaded NamespaceHandler mappings:" + mappings);
}
// 所有 "META-INF/spring.handlers" 文件外面的内容建设映射关系
handlerMappings = new ConcurrentHashMap<>(mappings.size());
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;
}
6. 自定义标签的解析
6.1 解析自定义元素
public BeanDefinition parseCustomElement(Element ele) {return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 解析到自定义元素的命名空间,例如:context 元素命名空间 http://www.springframework.org/schema/context
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {return null;}
// 依据 url 找命名空间 handler
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));
}
6.2 寻找命名空间对象(此办法上一章有用到)
public NamespaceHandler resolve(String namespaceUri) {
// 获取 spring 中所有 jar 包外面的 "META-INF/spring.handlers" 文件,并且建设映射关系
Map<String, Object> handlerMappings = getHandlerMappings();
// 依据 namespaceUri:http://www.springframework.org/schema/p,获取到这个命名空间的解决类
// 依据 url 找到对应的全限定类名
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {return null;}
// 如果时对象间接返回,阐明不是第一次应用
else if (handlerOrClassName instanceof NamespaceHandler) {return (NamespaceHandler) handlerOrClassName;
}
// 首次调用,会走下述逻辑
// 1. 依据类名加载此类,创立 class 对象
// 2. 依据 class 反射创建对象
// 3. 初始化 init
// 4. 放入缓存
// 5. 返回这个对象
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);
// 调用解决类的 init 办法,在 init 办法中实现标签元素解析类的注册 *** 重要
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
// catch 略......
}
}
6.3 初始化,把属性和解析器缓存映射,次要的解决缓存逻辑都在父类 NamespaceHandlerSupport 中,这样初始化之后,这个 NamespaceHandler 就蕴含了泛滥解析器。
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());
}
}
//NamespaceHandlerSupport 类中
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {this.parsers.put(elementName, parser);
}
6.4 跳回到 6.1 拿到 NamespaceHandler,开始解析
public BeanDefinition parse(Element element, ParserContext parserContext) {BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {String localName = parserContext.getDelegate().getLocalName(element);
// 从缓存中拿到 component-scan 的解析器
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
6.5 拿到解析器,跳转至 ComponentScanBeanDefinitionParser,开始解析
public BeanDefinition parse(Element element, ParserContext parserContext) {String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
6.6 创立一个扫描器
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
// 应用默认过滤器
boolean useDefaultFilters = true;
if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
}
// Delegate bean definition registration to scanner class.
// 创立扫描器
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
}
try {parseBeanNameGenerator(element, scanner);
}
catch (Exception ex) {parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
}
try {parseScope(element, scanner);
}
catch (Exception ex) {parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
}
parseTypeFilters(element, scanner, parserContext);
return scanner;
}
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
readerContext.getEnvironment(), readerContext.getResourceLoader());
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
// 应用默认过滤器,注册默认过滤器
registerDefaultFilters();}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
6.7 注册过滤器,反对注解扫描
protected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250'javax.annotation.ManagedBean'found and supported for component scanning");
}
catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330'javax.inject.Named'annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}
}
6.8 跳回到 6.5,创立扫描器实现后,就能够扫描 basePackages 包了
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 寻找符合条件的类,有 Component 注解的
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 把 BeanDefinition 注册到 spring 的缓存中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
6.9 寻找符合条件的类
public Set<BeanDefinition> findCandidateComponents(String basePackage) {if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
// 看此办法
return scanCandidateComponents(basePackage);
}
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 这里递归寻找文件 ***** 重要
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning" + resource);
}
if (resource.isReadable()) {
try {
// 拿到扫描门路下的资源,而后获取元数据信息,依据元素据信息判断是否满足条件
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class:" + resource);
}
candidates.add(sbd);
}
else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class:" + resource);
}
}
}
else {if (traceEnabled) {logger.trace("Ignored because not matching any filter:" + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to read candidate component class:" + resource, ex);
}
}
else {if (traceEnabled) {logger.trace("Ignored because not readable:" + resource);
}
}
}
}
catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 排除掉的组件
for (TypeFilter tf : this.excludeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return false;}
}
// 蕴含的组件
for (TypeFilter tf : this.includeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return isConditionMatch(metadataReader);
}
}
return false;
}
6.10 跳回 6.7 查看注册器过滤器类型 AnnotationTypeFilter,其父类 AbstractTypeHierarchyTraversingFilter
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// This method optimizes avoiding unnecessary creation of ClassReaders
// as well as visiting over those readers.
if (matchSelf(metadataReader)) {return true;}
ClassMetadata metadata = metadataReader.getClassMetadata();
if (matchClassName(metadata.getClassName())) {return true;}
if (this.considerInherited) {String superClassName = metadata.getSuperClassName();
if (superClassName != null) {
// Optimization to avoid creating ClassReader for super class.
Boolean superClassMatch = matchSuperClass(superClassName);
if (superClassMatch != null) {if (superClassMatch.booleanValue()) {return true;}
}
else {
// Need to read super class to determine a match...
try {if (match(metadata.getSuperClassName(), metadataReaderFactory)) {return true;}
}
catch (IOException ex) {logger.debug("Could not read super class [" + metadata.getSuperClassName() +
"] of type-filtered class [" + metadata.getClassName() + "]");
}
}
}
}
if (this.considerInterfaces) {for (String ifc : metadata.getInterfaceNames()) {
// Optimization to avoid creating ClassReader for super class
Boolean interfaceMatch = matchInterface(ifc);
if (interfaceMatch != null) {if (interfaceMatch.booleanValue()) {return true;}
}
else {
// Need to read interface to determine a match...
try {if (match(ifc, metadataReaderFactory)) {return true;}
}
catch (IOException ex) {logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
metadata.getClassName() + "]");
}
}
}
}
return false;
}
6.11 跳转回子类进行判断
protected boolean matchSelf(MetadataReader metadataReader) {AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
6.12 跳转回 6.9,如果发现这个类下面有 Component 注解信息,那么就符合条件。对于符合条件的,就会创立一个 beanDefinition 对象,而后将元数据信息封装进去,并放入容器中,最初返回
6.13 跳回 6.8,拿到 candidates 后,就会遍历解决,返回 beanDefinition 汇合,联合 6.5,而后将 beanDefinition 汇合注册到 spring 容器中,这样这个 context 的自定义标签解析结束。
<!-- 配置扫描门路样例 -->
<context:component-scan base-package="com.hello" />
总结
- 下面是以 context:component-scan 这个自定义标签为例,剖析了解析的流程,大略流程如下:
- 获取元素命名空间 url,nameSpaceUrl
- 依据 namespaceUrl 找到 nameSpaceHandler,这个应用到了 spi 懒加载机制(首次获取会反射创立 handler 对象,而后缓存)
- 创立 handler 后,会 init 初始化,初始化的过程中会缓存各种解析器
- 依据元素的 localname,查问到解析器,而后调用解析器的 parse 办法开始解析
- 无论是默认标签还是自定义标签,它们最终都是生成 beanDefinition 对象,而后注册到 beanDefinitionMaps 中缓存。