springboot 启动报错:required a bean of type 'xxxRepository' that could not be found
springboot启动的时候报错,错误如下:
Field demoRepository in com.ge.serviceImpl.DemoServiceImpl required a bean of type 'com.ge.dao.DemoRepository' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'com.ge.dao.DemoRepository' in your configuration.
原因分析:
由于搭建的springboot项目是分模块搭建的,使用的是spring-data-jpa
com.ge.dao.DemoRepository是在ge-springboot-dao模块下。代码如下
public interface DemoRepository extends JpaRepository<Demo, Integer> {}
但是SpringBootApplication是在ge-springboot-web这个module下。
com.ge.MainApplication
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
看错误信息的意思是spring找不到这个bean,也就是扫描不到。
尝试的方法:
1. 在 DemoRepository 加注解@Repository,然而好像并没有什么卵用,还是同样的错误。
2. 手动添加一个jpa相关的configuration类,同样没什么卵用。。
1 @Configuration 2 @ComponentScan(basePackages = "com.ge") 3 @EnableJpaRepositories( 4 basePackages = "com.ge", 5 entityManagerFactoryRef = "entityManagerFactory", 6 transactionManagerRef = "transactionManager") 7 @EnableTransactionManagement 8 public class DaoConfiguration { 9 10 @Autowired private Environment environment; 11 12 @Value("${datasource.sampleapp.maxPoolSize:10}") 13 private int maxPoolSize; 14 15 /* 16 * Populate SpringBoot DataSourceProperties object directly from 17 application.yml 18 * based on prefix.Thanks to .yml, Hierachical data is mapped out of 19 the box with matching-name 20 * properties of DataSourceProperties object]. 21 */ 22 @Bean 23 @Primary 24 @ConfigurationProperties(prefix = "spring.datasource") 25 public DataSourceProperties dataSourceProperties() { 26 return new DataSourceProperties(); 27 } 28 29 /* 30 * Configure HikariCP pooled DataSource. 31 */ 32 @Bean 33 public DataSource dataSource() { 34 DataSourceProperties dataSourceProperties = dataSourceProperties(); 35 HikariDataSource dataSource = 36 (HikariDataSource) 37 org.springframework.boot.jdbc.DataSourceBuilder.create( 38 dataSourceProperties.getClassLoader()) 39 .driverClassName(dataSourceProperties.getDriverClassName()) 40 .url(dataSourceProperties.getUrl()) 41 .username(dataSourceProperties.getUsername()) 42 .password(dataSourceProperties.getPassword()) 43 .type(HikariDataSource.class) 44 .build(); 45 dataSource.setMaximumPoolSize(maxPoolSize); 46 return dataSource; 47 } 48 49 /* 50 * Entity Manager Factory setup. 51 */ 52 @Bean 53 public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException { 54 LocalContainerEntityManagerFactoryBean factoryBean = 55 new LocalContainerEntityManagerFactoryBean(); 56 factoryBean.setDataSource(dataSource()); 57 factoryBean.setPackagesToScan(new String[] {"webroot.websrv"}); 58 factoryBean.setJpaVendorAdapter(jpaVendorAdapter()); 59 factoryBean.setJpaProperties(jpaProperties()); 60 return factoryBean; 61 } 62 63 /* 64 * Provider specific adapter. 65 */ 66 @Bean 67 public JpaVendorAdapter jpaVendorAdapter() { 68 HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter(); 69 return hibernateJpaVendorAdapter; 70 } 71 72 /* 73 * Here you can specify any provider specific properties. 74 */ 75 private Properties jpaProperties() { 76 Properties properties = new Properties(); 77 properties.put( 78 "hibernate.dialect", 79 environment.getRequiredProperty("spring.jpa.properties.hibernate.dialect")); 80 return properties; 81 } 82 83 @Bean 84 @Autowired 85 public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { 86 JpaTransactionManager txManager = new JpaTransactionManager(); 87 txManager.setEntityManagerFactory(emf); 88 return txManager; 89 } 90 }
3. 把主启动类MainRepository上的exclude= {DataSourceAutoConfiguration.class} 去掉,然后就可以了。
原来为什么加这个参数?因为没有在application.yml或者application.properties中配置spring.datasource.url这个属性,所以启动会报错。
但是后来我配置了数据源相关的属性,应该把exclude= {DataSourceAutoConfiguration.class}去掉,而且spring-data-jpa是操作数据库相关的框架,可能exculde数据源配置导致spring不会自动扫描repository。
总结:
这是我出现@autowired失败的原因。可能对别人并不适用。
但是对于springboot多模块project来说,能够@autowired自动注入的前提的,我举个例子来说明
我这里有3个模块:
ge-springboot-dao 模块中有 DemoRepositry
package com.ge.repository;
public interface DemoRepository extends JpaRepository<Demo, Integer> {}
ge-springboot-service 模块中有 DemoServiceImpl
package com.ge.service.impl;
@Service public class DemoServiceImpl implements DemoService { @Autowired private DemoRepository demoRepository; @Override public Demo save(Demo demo) { return demoRepository.save(demo); } @Override public Demo get(Integer id) { return demoRepository.getOne(id); } }
ge-springboot-web 模块中有DemoController 和SpringBootApplication
package com.ge.controller;
@Controller @RequestMapping("/demo") public class DemoController { @Autowired private DemoService demoService; @ResponseBody @GetMapping("/save") public Demo save() { Demo demo = new Demo(); demo.setName("gejunling"); return demoService.save(demo); } }
web模块能自动注入service模块的bean,service模块能自动注入dao模块的bean,前提就是所有的这些bean所在的java类都要在同一个package下。
可以发现,我这3个bean虽然在不同的module下,但是所在的packge都是在 com.ge.xxx.xxx
然后在@SpringBootApplication添加scanBasePackge="com.ge"即可。如下
@SpringBootApplication(scanBasePackages = {"com.ge"}) public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
当然,如果不使用scanBasePackge="com.ge"来指指定扫描的packge也可以,但是要保证springboot主启动类要在所有bean的同级或者上级packge。
比如我的MainApplication就是com.ge这个包下。
如果有不同的package需要spring自动扫描,同样可以使用scanBasePackge={"com.ge1","com.ge2","com.ge3"}