Spring 源码解析十一(Spring 的扩展加载机制)

Spring 源码解析十一:Spring 的扩展加载机制 Spring 的扩展加载机制主要有 2 个:自动加载第三方包中的类、扩展 xml 配置文件中 bean 的命名空间
1. 自动加载第三方包中的类 【Spring 源码解析十一(Spring 的扩展加载机制)】spring-core 提供了一个类似 Java SPI 的的扩展机制,在 META-INF/spring.factories 文件中定义需要自动加载的类,就可以自动实例化其他包指定的类,spring-boot, spring-cloud 都依赖这个机制自动加载资源。
比如 spring-boot 的扩展(一部分)

# Logging Systems org.springframework.boot.logging.LoggingSystemFactory=\ org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\ org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\ org.springframework.boot.logging.java.JavaLoggingSystem.Factory# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader# ConfigData Location Resolvers org.springframework.boot.context.config.ConfigDataLocationResolver=\ org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\ org.springframework.boot.context.config.StandardConfigDataLocationResolver# ConfigData Loaders org.springframework.boot.context.config.ConfigDataLoader=\ org.springframework.boot.context.config.ConfigTreeConfigDataLoader,\ org.springframework.boot.context.config.StandardConfigDataLoader# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener

实现这个功能的类是 SpringFactoriesLoader
public final class SpringFactoriesLoader { // 自动加载文件地址 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; // 加载spring.factories public static List loadFactories(Class factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } // 加载spring.factories中的bean名字 List factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse); // 结果集 List result = new ArrayList<>(factoryImplementationNames.size()); for (String factoryImplementationName : factoryImplementationNames) { // 初始化bean,并加入到结果集 result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse)); }return result; }// 加载spring.factories中的bean名字 public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); // 加载spring.factories中的bean定义,并提取出名字 return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }// 加载spring.factories中的bean定义 private static Map> loadSpringFactories(ClassLoader classLoader) { // 如果有缓存,直接返回缓存 Map> result = cache.get(classLoader); if (result != null) { return result; }// 结果集 result = new HashMap<>(); try { // 加载所有包下的spring.factories,不光是主包,还有各种依赖包 Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); // 遍历读取 while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); // 把属性加载出来,以properties文件对待 Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry entry : properties.entrySet()) { // bean名字 String factoryTypeName = ((String) entry.getKey()).trim(); // bean类型,可以用逗号分隔多个 String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); // 遍历bean类型 for (String factoryImplementationName : factoryImplementationNames) { // 加入到结果集 result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()) .add(factoryImplementationName.trim()); } } }// 去重 result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))); // 加入缓存 cache.put(classLoader, result); } catch (IOException ex) { // ... 代码省略 } return result; }// 初始化bean private static T instantiateFactory(String factoryImplementationName, Class factoryType, ClassLoader classLoader) { try { // 取出class Class factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader); // factoryImplementationClass不是factoryType的子类 if (!factoryType.isAssignableFrom(factoryImplementationClass)) { // 报错 } // 调用newInstance实例化 return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance(); } catch (Throwable ex) { // ... 代码省略 } }}

然后在 CachedIntrospectionResults
静态加载
public final class CachedIntrospectionResults { private static final List beanInfoFactories = SpringFactoriesLoader.loadFactories( BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader()); }

2. 扩展 xml 配置文件中 bean 的命名空间 spring-beans 提供了基于 XML 配置的、第三方对 bean 的命令空间扩展机制,主要是在
META-INF/spring.handlers, META-INF/spring.schemas 文件中定义需要扩展的命令空间,
,
比如 spring-beans 下的扩展
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler

实现这个功能的类是 DefaultNamespaceHandlerResolver
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver { // 自动加载文件地址 public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers"; // 默认加载DEFAULT_HANDLER_MAPPINGS_LOCATION public DefaultNamespaceHandlerResolver() { this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION); }// 默认加载DEFAULT_HANDLER_MAPPINGS_LOCATION public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) { this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION); }public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader, String handlerMappingsLocation) { this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); this.handlerMappingsLocation = handlerMappingsLocation; }// 解析命名空间 @Override public NamespaceHandler resolve(String namespaceUri) { // 获取命令空间映射 Map handlerMappings = getHandlerMappings(); // 获取处理器 Object handlerOrClassName = handlerMappings.get(namespaceUri); // 没有,返回null if (handlerOrClassName == null) { return null; } // NamespaceHandler,返回NamespaceHandler else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { // 当做类加载 Class handlerClass = ClassUtils.forName(className, this.classLoader); // 初始化类,并调用init方法 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); namespaceHandler.init(); // 载入缓存 handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { // ... 代码省略 } // ... 代码省略 } }// 获取命令空间映射 private Map getHandlerMappings() { Map handlerMappings = this.handlerMappings; // 如果已经加载过了,就不加载了 if (handlerMappings == null) { synchronized (this) { handlerMappings = this.handlerMappings; if (handlerMappings == null) { try { // 加载所有包下的spring.handlers,不光是主包,还有各种依赖包 // 把属性加载出来,以properties文件对待 Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); handlerMappings = new ConcurrentHashMap<>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); // 赋值给handlerMappings this.handlerMappings = handlerMappings; } catch (IOException ex) { // ... 代码省略 } } } } return handlerMappings; } }

因为 DefaultNamespaceHandlerResolver 是默认的命名空间解析器,所以从一开始就会被初始化,所以也就会自动加载 spring.handlers
后续 更多博客,查看 https://github.com/senntyou/blogs
作者:深予之 (@senntyou)
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)

    推荐阅读