2017-05-11 52 views
3

我有一個正在檢查數據庫條目的Spring服務。爲了最小化我的存儲庫調用,兩個find方法都是「@Cacheable」。但是,當我嘗試初始化我服務的bean,而我的配置類有一個CacheManager的bean定義我獲得以下NoSuchBeanDefinitionException:Config.class中的CacheManager bean定義導致NoSuchBeanDefinitionException

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'foo.mediacode.directory.MediaCodeDirectoryService' available 
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353) 
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340) 
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093) 
at foo.mediacode.directory.MediaCodeDirectoryService.implementation(MediaCodeDirectoryService.java:63) 
at foo.campaigntree.directory.CampaignTreeDirectoryService.<init>(CampaignTreeDirectoryService.java:18) 
... 15 more 

如果我參加了CacheManager的bean定義,我可以初始化我的服務豆,它運行沒有任何問題和緩存

這裏是我的代碼: 配置

... 
    @Configuration 
    @EnableCaching 
    @EnableJpaRepositories(...) 
    @PropertySource({...}) 
    public class MediaCodeDirectoryServiceConfig { 

     private static Logger configLogger = Logger.getLogger(MediaCodeDirectoryServiceConfig.class.getName()); 

     @Value("${jpa.loggingLevel:FINE}") 
     private String   loggingLevel; 

     @Value("${mysql.databaseDriver}") 
     private String   dataBaseDriver; 

     @Value("${mysql.username}") 
     private String   username; 

     @Value("${mysql.password}") 
     private String   password; 

     @Value("${mysql.databaseUrl}") 
     private String   databaseUrl; 

     @Bean 
     public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() { 
      ... 
     } 

     @Bean 
     public MediaCodeDirectoryService mediaCodeDirectoryService() { 
      return new MediaCodeDirectoryService(); 
     } 

     @Bean 
     public CacheManager mediaCodeCacheManager() { 
      SimpleCacheManager cacheManager = new SimpleCacheManager(); 
      cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("mediaCodeMappingRegexCache"), 
        new ConcurrentMapCache("mediaCodeMappingsCache"))); 

      return cacheManager; 
     } 

     @Bean 
     public JpaTransactionManager transactionManager() { 
      ... 
     } 

     @Bean 
     public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
      ... 
     } 

     public DataSource getDataSource() { 
      ... 
     } 

     public JpaDialect getJpaDialect() { 
      ... 
     } 

     public Properties getEclipseLinkProperty() { 
      ... 
     } 

     public JpaVendorAdapter getJpaVendorAdapter() { 
      ... 
     } 
    } 

服務

.... 
    public class MediaCodeDirectoryService implements MediaCodeDirectoryServiceApi { 

     ... 

     @Autowired 
     private MediaCodeDirectoryRepository repo; 

     @SuppressWarnings("resource") 
     public static MediaCodeDirectoryServiceApi implementation() { 
     if (INSTANCE == null) { 
       ApplicationContext ctx = new AnnotationConfigApplicationContext(MediaCodeDirectoryServiceConfig.class); 
       INSTANCE = ctx.getBean(MediaCodeDirectoryService.class); 
      } 

      return INSTANCE; 
     } 
... 

... 
@Repository 
public interface MediaCodeDirectoryRepository extends CrudRepository<MediaCodeDao, Integer> { 

    @Cacheable("mediaCodeMappingRegexes") 
    @Query("SELECT m FROM #{#entityName} m WHERE (m.fooId = :fooId) AND (m.isRegex = :isRegex) ORDER BY (m.orderId DESC, m.id ASC)") 
    List<MediaCodeDao> findByfooIdAndIsRegexOrderByOrderIdDescAndIdAsc(@Param("fooId") int fooId, @Param("isRegex") boolean isRegex); 

    @Cacheable("mediaCodeMappings") 
    List<MediaCodeDao> findByMediaCode(String MediaCode, Pageable pageable); 
} 

當我調試到DefaultListableBeanFactory我可以在我的beanDefinitionMap找到mediaCodeDirectoryService並且也在beanDefinitionNames 中出現mediaCodeDirectoryService。但是DefaultListableBeanFactory.getBean(...)無法解析名稱,並且在行364中名爲Bean的爲空。

當我嘗試通過字符串來獲取上下文喜歡:

INSTANCE = (MediaCodeDirectoryService) ctx.getBean("mediaCodeDirecotryService") 

我避免NoSuchBeanDefinitionException但我碰上另一個。

這裏的任何人都有一個想法,可能是什麼原因呢?我在配置中錯過了什麼嗎?謝謝!

+0

您應該編程來接口非具體類......因此,而不是'MediaCodeDirectoryService'在代碼中使用'MediaCodeDirectoryServiceApi'。 –

+0

在另一個節點上,你的代碼是危險的,你應該永遠不要調用'new * ApplicationContext',因爲你基本上是一遍又一遍地重新創建你的應用程序。如果你在多個地方有這個代碼,你最終會得到內存問題,事務問題,奇怪的併發問題(當然,如果你希望那些可以這樣做,但我強烈建議你不要那麼做!)。 –

回答

4

通過AOP應用緩存。對於AOP,Spring使用基於代理的方法,默認情況下是創建基於接口的代理。

public class MediaCodeDirectoryService implements MediaCodeDirectoryServiceApi {... } 

在運行時使用這個類的定義,你會得到一個動態創建的類(Proxy$51或類似的規定),它實現了所有的接口,但它不是一個MediaCodeDirectoryService。然而它是MediaCodeDirectoryServiceApi

您有兩種方式解決這個,無論是程序接口(你應該做的事情呢,因爲你已經定義的接口),而不是具體的類或使用基於類的代理。

第一個選項涉及您的地方直接@Autowire或得到MediaCodeDirectoryService實例使用MediaCodeDirectoryServiceApi,而不是(這恕我直言,你應該已經做了,爲什麼別的定義一個接口)改變你的代碼。現在你會得到代理注入,一切都會工作。

第二個選項涉及您在@EnableCaching註釋設置proxyTargetClass=true。然後,而不是一個基於接口的代理,你會得到一個基於類的代理。

@EnableCaching(proxyTargetClass=true) 
+0

非常感謝您的明確和詳細的答案。之後,我做了一些研究,並找到了爲什麼自動裝配接口而不是類的一般解釋http://stackoverflow.com/questions/12899372/spring-why-do-we-autowire-the-interface-and-not -THE實現一流 – grimbo

相關問題