Spring 源码解析十一:Spring 的扩大加载机制
Spring 的扩大加载机制次要有 2 个:主动加载第三方包中的类、扩大 xml 配置文件中 bean 的命名空间
1. 主动加载第三方包中的类
spring-core
提供了一个相似 Java SPI 的的扩大机制,在 META-INF/spring.factories
文件中定义须要主动加载的类,就能够主动实例化其余包指定的类,spring-boot, spring-cloud
都依赖这个机制主动加载资源。
比方 spring-boot
的扩大(一部分)
# Logging Systemsorg.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 Loadersorg.springframework.boot.env.PropertySourceLoader=\org.springframework.boot.env.PropertiesPropertySourceLoader,\org.springframework.boot.env.YamlPropertySourceLoader# ConfigData Location Resolversorg.springframework.boot.context.config.ConfigDataLocationResolver=\org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\org.springframework.boot.context.config.StandardConfigDataLocationResolver# ConfigData Loadersorg.springframework.boot.context.config.ConfigDataLoader=\org.springframework.boot.context.config.ConfigTreeConfigDataLoader,\org.springframework.boot.context.config.StandardConfigDataLoader# Run Listenersorg.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 <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } // 加载spring.factories中的bean名字 List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse); // 后果集 List<T> result = new ArrayList<>(factoryImplementationNames.size()); for (String factoryImplementationName : factoryImplementationNames) { // 初始化bean,并退出到后果集 result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse)); } return result; } // 加载spring.factories中的bean名字 public static List<String> 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<String, List<String>> loadSpringFactories(ClassLoader classLoader) { // 如果有缓存,间接返回缓存 Map<String, List<String>> result = cache.get(classLoader); if (result != null) { return result; } // 后果集 result = new HashMap<>(); try { // 加载所有包下的spring.factories,不光是主包,还有各种依赖包 Enumeration<URL> 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> T instantiateFactory(String factoryImplementationName, Class<T> 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<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories( BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());}
2. 扩大 xml 配置文件中 bean 的命名空间
spring-beans
提供了基于 XML 配置的、第三方对 bean 的命令空间扩大机制,次要是在META-INF/spring.handlers, META-INF/spring.schemas
文件中定义须要扩大的命令空间,
如 <dubbo:application name="name"/>, <dubbo:registry address="address"/>
比方 spring-beans
下的扩大
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandlerhttp\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandlerhttp\://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<String, Object> 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<String, Object> getHandlerMappings() { Map<String, Object> 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 许可证)