自定义加载Spring配置文件

本文介绍了一种通过重写Spring监听器实现自定义Spring配置文件加载的方法,该方法允许在同一平台的不同项目中灵活加载特定的插件配置。

        为了适应目前框架的插件启动机制(同一平台不同项目加载不同插件和配置文件),不得不想办法让插件来选择性的加载spring配置文件,我是通过重写spring监听器来实现加载自定义配置文件。

一、首先,重写类的主要代码(主要在中文注释处):

public class ShineContextLoaderListener extends ContextLoaderListener{
	private ContextLoader contextLoader;

	@Override
	protected WebApplicationContext createWebApplicationContext(ServletContext sc, ApplicationContext parent) {
//		return super.createWebApplicationContext(sc, parent);
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		// Assign the best possible id value.
		if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
			// Servlet <= 2.4: resort to name specified in web.xml, if any.
			String servletContextName = sc.getServletContextName();
			wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
					ObjectUtils.getDisplayString(servletContextName));
		}
		else {
			// Servlet 2.5's getContextPath available!
			try {
				String contextPath = (String) ServletContext.class.getMethod("getContextPath").invoke(sc);
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(contextPath));
			}
			catch (Exception ex) {
				throw new IllegalStateException("Failed to invoke Servlet 2.5 getContextPath method", ex);
			}
		}

		//将默认的spring配置文件与插件注入的配置文件融合
		String configLocation = sc.getInitParameter(CONFIG_LOCATION_PARAM);	//这里获取到web.xml中通过param配置的spring配置文件路径
		String fusionConfigLocation = ConfigFactory.getFactory().fusionSpringXml(configLocation, "Spring");	//将动态加载的spring配置文件和默认的配置文件拼接在一起
                /* 这里拼出结果类似:classpath:com/shine/docs/config/dbSpring.xml,classpath:com/shine/jbpm/config/jbpmSpring.xml */
		
		wac.setParent(parent);
		wac.setServletContext(sc);
		wac.setConfigLocation(fusionConfigLocation);	//设置配置文件路径为拼接后的值
		customizeContext(sc, wac);
		wac.refresh();
		return wac;
	}

	/**
	 * Initialize the root web application context.
	 */
	public void contextInitialized(ServletContextEvent event) {
		//初始化系统配置,将启动时需要的配置文件加载到系统全局变量中
		ConfigFactory.getFactory().init(event.getServletContext());
		
		this.contextLoader = createContextLoader();
		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}
}
二、将web.xml中的配置的spring监听器改成重写后的类

<!-- 
	Spring监听器,原class:org.springframework.web.context.ContextLoaderListener 
	contextConfigLocation值已改成通过插件加载,在此处保留的话不要与插件中加载的冲突
	如果同时使用SpringMvc则注意不要重复加载 
-->
<listener>
	<listener-class>com.shine.spring.ShineContextLoaderListener</listener-class>
</listener>
<!-- 
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:applicationContext.xml</param-value>
</context-param>
 -->

OK,主要就是这样。

<think>好的,我现在需要帮用户解决如何在Spring Boot中自定义PropertySource加载YML配置文件的问题。首先,我得回忆一下用户提供的引用内容,特别是引用1、2、3、4中的信息。用户提到了几种加载配置文件的方式,比如PropertiesFactoryBean、YamlMapFactoryBean,还有@PropertySource注解只能加载properties文件。用户的需求是自定义PropertySource来加载YML,这可能涉及到如何解析YAML文件并将其转换为PropertySource对象。 首先,根据引用1中的内容,YamlPropertySourceLoader可以将YAML文件加载成PropertySource。而引用4提到Spring Boot加载配置文件的顺序,其中application.yml是默认加载的,但用户可能想加载额外的YML文件,比如自定义的custom.yml,这时候就需要手动添加PropertySource。 接下来,我需要考虑如何在代码中实现这一点。可能的步骤包括:创建一个YamlPropertySourceLoader实例,使用它加载指定的YML文件,然后将得到的PropertySource添加到Spring环境中。另外,引用2中的例子展示了通过@ConfigurationProperties来绑定配置到类,但这可能不适用于用户的需求,因为他们想直接加载到PropertySource。 需要注意的是,@PropertySource注解不支持YAML文件,所以必须通过编程方式添加。根据引用1中的YamlPropertySourceLoader,应该使用这个类来处理YML文件。可能的实现方式是在Spring Boot的启动过程中,比如通过实现EnvironmentPostProcessor接口,在配置环境后处理阶段添加自定义的PropertySource。 此外,还需要处理资源的位置,确保文件在类路径下或指定路径下存在。可能需要处理异常情况,比如文件不存在时的处理。另外,可能要考虑配置的优先级,根据Spring Boot的加载顺序,自定义的PropertySource可能需要调整顺序以确保覆盖或不被默认配置覆盖。 最后,需要提供一个代码示例,展示如何实现这一过程。可能需要创建一个实现EnvironmentPostProcessor的类,并在META-INF/spring.factories中注册该类,以便Spring Boot能够识别并执行它。同时,在代码中使用YamlPropertySourceLoader加载YML文件,并将得到的PropertySource添加到环境中。 总结步骤:1. 创建自定义的EnvironmentPostProcessor实现类;2. 使用YamlPropertySourceLoader加载YML文件;3. 将加载的PropertySource添加到Spring环境中;4. 注册EnvironmentPostProcessor;5. 测试配置是否正确加载。</think>### 自定义PropertySource加载YML配置的Spring Boot示例 #### 实现原理 Spring Boot通过`YamlPropertySourceLoader`类支持YAML文件的加载[^1][^3]。自定义`PropertySource`的核心步骤是: 1. 定义`EnvironmentPostProcessor`接口实现类 2. 使用YAML加载器解析配置文件 3. 将生成的属性源添加到环境配置中 #### 完整代码实现 ```java // 1. 实现环境后处理器 public class CustomYmlPropertySourceLoader implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { try { // 2. 加载自定义YML文件 Resource resource = new ClassPathResource("custom.yml"); List<PropertySource<?>> sources = loader.load("customYml", resource); // 3. 添加到环境配置(设置最高优先级) sources.forEach(ps -> environment.getPropertySources().addFirst(ps)); } catch (IOException e) { throw new IllegalStateException("加载custom.yml失败", e); } } } // 4. 注册处理器(在src/main/resources/META-INF/spring.factories) org.springframework.boot.env.EnvironmentPostProcessor=com.example.CustomYmlPropertySourceLoader ``` #### 配置示例(custom.yml) ```yaml app: custom: api-endpoint: https://api.example.com max-retries: 5 timeout: 3000ms ``` #### 验证配置注入 ```java @Value("${app.custom.api-endpoint}") private String apiEndpoint; @Value("${app.custom.max-retries}") private int maxRetries; ``` #### 关键点说明 1. **加载顺序控制**:使用`addFirst()`确保自定义配置具有最高优先级[^4] 2. **异常处理**:捕捉IO异常避免启动失败 3. **文件定位**:ClassPathResource默认从`src/main/resources`加载 4. **命名规范**:建议使用`application-{profile}.yml`格式保持配置一致性[^3]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值