我有一个简单的spring boot应用程序,其中我有一个jpa存储库对象,我想在@Configuration
类内部自动装配,如下所示。
@Configuration
public class Appconfig {
@Bean
@Autowired
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(OctopusPropertiesRepository repo) {
PropertySourcesPlaceholderConfigurer property = new PropertySourcesPlaceholderConfigurer();
Map<String,Object> props = new ConcurrentHashMap<>();
List<OctopusProperties> loadedSettings = repo.findAll();
loadedSettings.forEach(entry -> props.put(entry.getKey(), entry.getValue()));
MutablePropertySources mutablePropertySources = new MutablePropertySources();
mutablePropertySources.addFirst(new MapPropertySource("custom", props));
property.setPropertySources(mutablePropertySources);
return property;
}
}
这是@Repository
类
@Repository
public interface OctopusPropertiesRepository extends JpaRepository<OctopusProperties, Long> {
}
我得到以下异常。
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.app.OctopusPropertiesRepository]
如果我没有成功配置并启动应用程序,我会从执行器上看到bean可用。这里有什么问题?为什么我无法在@Repository
内发送@Configuration
。
P.S。这两个java文件位于同一文件夹下:com.example.app
P.P.S。我项目的Eclipse视图:
答案 0 :(得分:1)
根据@Bean javadoc:
BeanFactoryPostProcessor-returning @Bean methods
Special consideration must be taken for @Bean methods that return Spring
BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be
instantiated very early in the container lifecycle, they can interfere with
processing of annotations such as @Autowired, @Value, and @PostConstruct
within @Configuration classes. To avoid these lifecycle issues, mark BFPP
returning @Bean methods as static. For example:
@Bean
public static PropertyPlaceholderConfigurer ppc() {
// instantiate, configure and return ppc ...
}
By marking this method as static, it can be invoked without causing
instantiation of its declaring @Configuration class, thus avoiding the above-
mentioned lifecycle conflicts. Note however that static @Bean methods will not
be enhanced for scoping and AOP semantics as mentioned above. This works out
in BFPP cases, as they are not typically referenced by other @Bean methods. As
a reminder, a WARN-level log message will be issued for any non-static @Bean
methods having a return type assignable to BeanFactoryPostProcessor.
因此,根据这一点,您的propertySourcesPlaceholderConfigurer()
应该是静态的。
修改强>
对不起晚编辑。
我不认为你可以在这里使用Hibernate存储库,因为BeanFactoryPostProcessor
在hibernate和jpa需要任何依赖之前得到实例化。
也许你可以在这里使用JdbcTemplate,至少对我有用:
@Configuration
public class Appconfig {
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer property = new PropertySourcesPlaceholderConfigurer();
Map<String, Object> props = new ConcurrentHashMap<>();
List<OctopusProperties> loadedSettings = getAll();
loadedSettings.forEach(entry -> props.put(entry.getKey(), entry.getValue()));
MutablePropertySources mutablePropertySources = new MutablePropertySources();
mutablePropertySources.addFirst(new MapPropertySource("custom", props));
property.setPropertySources(mutablePropertySources);
return property;
}
@Bean
public static DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
private List<OctopusProperties> getAll() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
List<OctopusProperties> all = jdbcTemplate.query("select id,key_column,value_column from octopus_properties",
new RowMapper<OctopusProperties>() {
@Override
public OctopusProperties mapRow(final ResultSet rs, final int rowNum) throws SQLException {
OctopusProperties op = new OctopusProperties();
op.setId(rs.getLong("id"));
op.setKey(rs.getString("key_column"));
op.setValue(rs.getString("value_column"));
return op;
}
});
return all;
}
}
请注意,我在这里使用了MySQL,因此相应地配置了数据源。
答案 1 :(得分:1)
使用@PostConstruct。
@Autowired PropertySourcesPlaceholderConfigurer property;
@Autowired OctopusPropertiesRepository repo;
@PostConstruct
public void onInit() {
Map<String,Object> props = new ConcurrentHashMap<>();
List<OctopusProperties> loadedSettings = repo.findAll();
loadedSettings.forEach(entry -> props.put(entry.getKey(), entry.getValue()));
MutablePropertySources mutablePropertySources = new MutablePropertySources();
mutablePropertySources.addFirst(new MapPropertySource("custom", props));
property.setPropertySources(mutablePropertySources);
}
答案 2 :(得分:0)
在this问题
中解决了类似的问题是否可以像这样更改AppConfig
课程?
@Configuration
public class Appconfig {
@Autowired
private OctopusPropertiesRepository repo;
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer property = new PropertySourcesPlaceholderConfigurer();
Map<String,Object> props = new ConcurrentHashMap<>();
List<OctopusProperties> loadedSettings = repo.findAll();
loadedSettings.forEach(entry -> props.put(entry.getKey(), entry.getValue()));
MutablePropertySources mutablePropertySources = new MutablePropertySources();
mutablePropertySources.addFirst(new MapPropertySource("custom", props));
property.setPropertySources(mutablePropertySources);
return property;
}
}
如果此解决方案有效,请还原。