2017-05-11 50 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

相关问题