问题
For spring boot + integration application, I'm attempting to load configuration from database, allow it to be accessible to Spring's Environment
& inject-able via @Value
annotation and be override-able by externalized configurations as described in the spring boot reference documentation under the Externalized Configuration Section.
The problem I'm having is that my spring Integration XML contains ${input}
property placeholders that can not be resolved, because I can't get the database backed configuration to be loaded before Spring attempts to load the XML configurations.
The entry point to the application:
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
How database configuration would be loaded:
@Configuration
public class DbPropertiesConfig {
@Autowired
private org.springframework.core.env.Environment env;
@PostConstruct
public void initializeDatabasePropertySourceUsage() {
MutablePropertySources propertySources = ((ConfigurableEnvironment) env).getPropertySources();
try {
// The below code will be replace w/ code to load config from DB
Map<String,Object> map = new HashMap<>();
map.put("input-dir","target/input");
map.put("output-dir","target/output");
DbPropertySource dbPropertySource = new DbPropertySource("si",map);
propertySources.addLast(dbPropertySource);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
How Spring Integration config is loaded:
@Profile("IN")
@Configuration
@ImportResource({"si-common-context.xml","si-input-context.xml"})
public class SiInputAppConfig {
}
The Spring Integration XML configurationsi-input-context.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd" default-lazy-init="true">
<int-file:inbound-channel-adapter channel="input2" directory="${input-dir}" filename-pattern="*">
<int:poller fixed-rate="500"/>
</int-file:inbound-channel-adapter>
<int:service-activator input-channel="input2" ref="sampleEndpoint" method="hello" output-channel="output2"/>
<int:channel id="output2"/>
<int-file:outbound-channel-adapter channel="output2" directory="${output-dir}"/>
</beans:beans>
The error I get:
2015-10-28 17:22:18.283 INFO 3816 --- [ main] o.s.b.f.xml.XmlBeanDefinitionReader : Loading XML bean definitions from class path resource [si-common-context.xml]
2015-10-28 17:22:18.383 INFO 3816 --- [ main] o.s.b.f.xml.XmlBeanDefinitionReader : Loading XML bean definitions from class path resource [si-mail-in-context.xml]
2015-10-28 17:22:18.466 INFO 3816 --- [ main] o.s.b.f.config.PropertiesFactoryBean : Loading properties file from URL [jar:file:/C:/Users/xxx/.m2/repository/org/springframework/integration/spring-integration-core/4.1.6.RELEASE/spring-integration-core-4.1.6.RELEASE.jar!/META-INF/spring.integration.default.properties]
2015-10-28 17:22:18.471 INFO 3816 --- [ main] o.s.i.config.IntegrationRegistrar : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2015-10-28 17:22:18.604 INFO 3816 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; ...
2015-10-28 17:22:18.930 WARN 3816 --- [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0.source' defined in null: Could not resolve placeholder 'si.in-input' in string value "${si.in-input}"; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'input-dir' in string value "${input-dir}" ...
Spring loads DbPropertiesConfig
after XML configuration is attempted to be loaded.
How can I resolve this issue?
Thanks in advance
AP
回答1:
Yes, I can confirm by my home tests that XML definitions are loaded before the annotation stuff. It's enough complicated to determine why it is, but I'm sure that @Import*
resources are more important by premise than an internal @Configuration
logic.
Therefore your @PostConstruct
isn't good for mix with XML.
One solution is to move all Spring Integration configuration to the Annotation style and even consider to use Spring Integration Java DSL.
Another solution is to follow with Spring Boot's Externalized Configuration recommendation:
- Default properties (specified using
SpringApplication.setDefaultProperties
).
That means you have to read properties from your DB before the starting Spring Application. Yes, if you were going to use DataSource
on the matter from the same application, it won't be possible. From other side let's take a look to your goal one more time! You are going to load properties for the application from DB as an external configuration, so, what is the point to do that from the application itself? Of course, it would be more safe to load and feed properties before application start.
Hope I am clear.
来源:https://stackoverflow.com/questions/33403056/using-spring-boot-spring-integration-with-database-backed-configuration