spring boot 工程有一个依赖工程xxx-common.jar, 这个xxx-common.jar有一个工具类XUtils,这个工具类会读取xxx-common.jar classpath下的一个配置文件。
本来XUtils.class.getResource("/xxxx.json").getPath();获取路径,读取这个配置文件信息。后来发现服务器上跑有问题。(我这边的打包方式是appassembler方式)。
后来记得spring-boot 源码里面有 自动装配下读取有 spring.factory的文件, 后来参考了一下源码。
关键地方 org.springframework.util.ClassUtils getDefaultClassLoader 方法;
//源码如下:
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
后来使用一下的方式读取成功:
ClassUtils.getDefaultClassLoader().getResourceAsStream("xxx.json");
#应该对应的就是下面的代码
Thread.currentThread().getContextClassLoader().getResourceAsStream("xxx.json");
XUtils.class.getResource("/xxxx.json") 或者 XUtils.class.getClassLoader.getResource("/xxxx.json") 都是主工程的classpath 。
并且这配置文件是处于jar里面的, 直接通过path好像还不能访问, 所以使用了 getResourceAsStream。
spring-boot 还有挺多细节可以看看的(关键代码 ConfigurationClassPostProcessor.class、 AutoConfigurationImportSelector.class )
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();//loadFactoryNames方法的 classLoader
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String propertyValue = properties.getProperty(factoryClassName);
for (String factoryName : StringUtils.commaDelimitedListToStringArray(propertyValue)) {
result.add(factoryName.trim());
}
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}