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"}