@boot中的springboot自动装配@Repository无法正常工作

时间:2016-08-03 11:48:06

标签: java spring spring-boot spring-data-jpa

我有一个简单的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视图:

enter image description here

3 个答案:

答案 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;
    }
}

如果此解决方案有效,请还原。