分析原因:原因1@Configuration默认使用application.yml中读配置属性,而本项目的属性是来自于taskconfig.yml自定义文件,所以注入失败。原因2就是使用的这个类是一个Component,但是加载顺醋可能晚于InitConfig这个bean(而initconfig加载以后才能设置从taskconfig.yml加载属性配置,可使用@DependsOn({"propertySourcesPlaceholderConfigurer"})设置在其之后加载。)
解决方案是:一个是在@Configuration的这配置中加入注解,切换属性加载位置,@PropertySource(value = "classpath:taskconfig.yml", ignoreResourceNotFound = true , factory = MixPropertySourceFactory.class),因为PropertySource注解默认不支持yml,因此使用了自定义的MixPropertySourceFactory。或者使用@DependsOn({"propertySourcesPlaceholderConfigurer"})设置在其之后加载。再就是推荐使用 @Value("#{taskRunServerConfig.enable}")这种方式,通过bean统一来注入。
2:在标注@Configuration的主配置类中,使用@Value("${task.runServer.enable:false}")这种方式是好用的,而使用@Value("#{taskRunServerConfig.enable}")则是不好用的。分析原因,发现。这个类中taskRunServerConfig依赖于此Configuration配置的一个bean,因此taskRunServerConfig这个bean晚于本配置类创建,因此taskRunServerConfig的bean属性注入失败(值不是yml中的)。而为啥@Value("${task.runServer.enable:false}")这种方式好用呢?因为之前写了个InitConfig,其中使用YamlPropertiesFactoryBean的方式加载了taskconfig.yml配置文件,并且有@Import({InitConfig.class, TaskCommonRedisConfig.class})引入了这个配置,因此是好用的。为了统一使用bean方式引入配置,作出了如下修改:
2.1TaskRunServerConfig配置类使用@Bean的方式在主配置类中配置
@Bean
@ConfigurationProperties(prefix="task.runServer")
TaskRunServerConfig taskRunServerConfig()
{
TaskRunServerConfig config = new TaskRunServerConfig()
return config
}
2.2
主配置类中引入@PropertySource(value = "classpath:taskconfig.yml", ignoreResourceNotFound = true , factory = MixPropertySourceFactory.class),那么配置会从自定义的taskconfig.yml文件中加载配置属性。
2.3
TaskRunServerConfig 中原来Autowried了一个主配置类中创建的bean,此时不采用绑定方式,而是在创建另一个bean的时候,调用TaskRunServerConfig的set方法去设置自己进去。不然会出现循环依赖。
2.4
主配置类型使用@Bean创建bean的时候,使用参数绑定的方式传入TaskRunServerConfig ,例如@Bean(name={"taskInstanceRunManager"}, initMethod="start", destroyMethod="stop")
public TaskInstanceRunManager taskInstanceRunManager( TaskRunServerConfig taskRunServerConfig )
#
@Configuration
public class InitConfig
{
// @Bean
// public static PropertySourcesPlaceholderConfigurer properties()
// {
// PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer()
// YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean()
// yaml.setResources(new ClassPathResource("taskconfig.yml"))
// propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject())
// return propertySourcesPlaceholderConfigurer
// }
}
#
public class MixPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?>createPropertySource(String name, EncodedResource resource) throws IOException {
String sourceName = name != null ? name : resource.getResource().getFilename()
if (!resource.getResource().exists()) {
return new PropertiesPropertySource(sourceName, new Properties())
} else if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
Properties propertiesFromYaml = loadYml(resource)
return new PropertiesPropertySource(sourceName, propertiesFromYaml)
} else {
return super.createPropertySource(name, resource)
}
}
private Properties loadYml(EncodedResource resource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean()
factory.setResources(resource.getResource())
factory.afterPropertiesSet()
return factory.getObject()
}
}
基于setter的DI是在调用无参数构造函数或无参数静态工厂方法来实例化bean之后,通过容器调用bean上的setter方法来完成的。
基于构造函数的DI是通过容器调用带有许多参数的构造函数来完成的,每个参数代表一个依赖项
1、对于强制依赖的使用构造方法注入
2、对于可选的使用属性注入
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependencyhowever, constructor injection with programmatic validation of arguments is preferable.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)