当前位置: 首页 > 知识库问答 >
问题:

Gemfire NoSuchBeanDefinitionException自动连线缓存(Spring 5.0.2/Gemfirev9.2.7)

罗绪
2023-03-14

我们正在从gefire 8.2.7迁移到9.2.1

作为Gemfire启动的一部分,我们利用SpringContextBootstrappingInitializer来初始化SpringBean,它@自动连接缓存。

迁移到Gemfire 9.2.1(以及其他堆栈)的同一代码在服务器启动时失败,出现以下错误。

Gemfire 8.2.7 --> Gemfire 9.2.1
Spring-data-Gemfire 1.8.4 --> 2.0.2
Spring-Boot 1.4.7 --> 2.0.0.M7
Spring --> 5.0.2

原因:org.springframework.beans.factory.NoSuchBean定义异常:没有可用类型为“org.apache.geode.cache.缓存”的合格bean:需要至少1个符合自动连接候选条件的bean。依赖注释:{@org.springframework.beans.factory.annotation.自动连接(必需=true)}

GemfireConfig需要任何指针/更改吗?下面是我们的JavaConfig。

@Bean
public CacheFactoryBean gemfireCache() {

    return new CacheFactoryBean();
}

看起来ComponentScan是在配置处理器之前启动的。对控制这种行为有什么想法吗?这在Spring Boot 1.4.6(Spring-4.3.8)中进行了测试,并通过@Depends选项得到解决,但只是想了解在较新的Spring版本中bean初始化的顺序是否有任何根本性的变化。

@Configuration
@EnableAutoConfiguration(exclude = { HibernateJpaAutoConfiguration.class, BatchAutoConfiguration.class })
@Import(value = { GemfireServerConfig.class, JpaConfiguration.class, JpaConfigurableProperties.class })
@ComponentScan(basePackages = "com.test.gemfire", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) )

共有1个答案

沈健
2023-03-14

首先,让我给你一些提示,因为你上面的问题陈述有3个问题。。。

1)首先,您没有明确说明为什么或如何在此处使用SpringContextBootstrappingLaunalizerDocso.s.d.g.support.

我只能假设这是因为您正在使用以下命令使用Gfsh启动您的GemFire服务器...

gfsh> start server --name=MyServer --cache-xml-file=/path/to/cache.xml ...

您的缓存。xml的定义与此类似。毕竟,这是使用SpringContextBootstrappingInitializer的初衷。

如果是这种情况,为什么不使用Gfsh、启动服务器命令、--spring xml位置选项。例如:

gfsh> start server --name=MyServer --spring-xml-location=/by/default/a/classpath/to/applicationContext.xml --classpath=/path/to/spring-data-gemfire-2.0.2.RELEASE.jar:...

通过这样做,您不再需要提供缓存。xml仅声明SpringContextBootstrappingInitializer,以便在GemFire JVM进程内引导Spring容器。启动服务器时,您只需使用-spring-xml-location选项并将SDG放在服务器的类路径上。

2) 其次,不清楚您将GemFire缓存引用注入到哪种类型的应用程序组件/bean中(例如,一个区域或另一个应用程序组件类,如DAO等)。提供一段代码,显示如何注入缓存引用,即使用自动连线注释的注入点,会很有帮助。例如:

@Service
class MyService {

  @Autowired
  private Cache gemfireCache;

  ...
}

3) 如果包含完整的堆栈跟踪,而不仅仅是NoSuchBeanDefinitionException消息,那么#2会更加明显。

尽管你的问题陈述存在问题,但我可以推断出以下几点:

>

  • 很明显,您正在使用“类路径组件扫描”(带有注释)并“按类型”自动连接;这可能是关键;我将在下文稍后再谈到这一点。

    您正在bean类字段(字段注入)或属性(setter注入)上使用Spring的Autowired注释,甚至可能是构造函数。

    此字段/属性(或构造函数参数)的类型肯定是org。阿帕奇。晶洞。隐藏物缓存

    继续。。。

    一般来说,Spring将首先遵循依赖顺序。也就是说,如果A依赖于B,那么B必须在A之前创建,并在A之后销毁。通常,Spring会并且可以毫无意外地实现这一点。

    除了“依赖顺序”bean创建和满足bean之间的依赖关系(包括使用@DependsOn注释)之外,bean创建的顺序定义得相当松散。

    有几个因素可以影响它,例如“注册顺序”(即声明bean定义的顺序,对于XML中定义的bean尤其如此)、“导入顺序”(当在配置类上使用导入注释时)、Java反射(包括在配置类中声明的bean定义),配置组织绝对重要,不应掉以轻心。

    这就是为什么我不是“类路径组件扫描”的主要支持者的一个原因。虽然这可能很方便,但在我看来,在您的配置和配置的组织中更加“明确”总是更好的,因为除了其他不明显的限制外,这里概述了一些原因。最坏的情况下,您肯定应该限制扫描的范围。

    具有讽刺意味的是,您排除/过滤了实际上可以帮助您解决组织问题的1件事。。。配置类型的组件:

    ... excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
    

    注意:考虑到排除,您确定没有排除包含您的CacheFactoryBean定义的1配置类吗?我想不会,因为你说这在包含了DependsOn注释之后起作用了。

    显然,您的某些应用程序组件(?)之间定义了依赖关系和一个类型为o.a.g.cache的bean。缓存(使用Autowired),但Spring无法解决它。

    我的想法是,Spring无法解析缓存依赖关系,因为1)GemFire缓存bean尚未创建,2)Spring无法在您的配置中找到所需类型(即o.a.g.Cache.Cache)的适当bean定义,该定义将解析依赖关系并强制首先创建GemFire缓存,或者3)首先创建了GemFire缓存bean,但Spring无法将类型解析为o.a.g.Cache。缓存

    我以前遇到过这两种情况,但我并不完全清楚每种情况发生的时间,因为我只是还没有完全了解这一点。我只是纠正了它,然后继续前进。我注意到它与版本有关。

    有几种方法可以解决这个问题。

    如果问题是后者,3),那么只需将依赖项声明为类型o.a.g.cache。GemFireCache应该可以解决这个问题。例如:

    @Repository
    class MyDataAccessObject {
    
      @Autowired
      private GemFireCache gemfireCache;
    
      ...
    }
    

    这是因为o.s.d.g.CacheFactoryBean类的getObjectType()方法返回一个泛化扩展的类类型。GemFireCache。这是设计的,因为o.s.d.g.client。ClientCacheFactoryBean扩展了o.s.d.g.CacheFactoryBean,尽管如果我创建了这些类,我可能不会这样做。然而,这与GemFire中的实际缓存类型是o.a.g.internal这一事实是一致的。隐藏物GemFireCacheImpl间接实现了o.a.g.cache。缓存接口以及o.a.g.Cache。客户ClientCache接口。

    如果你的问题是前(1)2),这有点棘手),那么我建议你采用一个更智能的配置组织,用关注点分隔。例如,您可以使用以下内容封装GemFire配置:

    @Configuration
    class GemFireConfiguration {
      // define GemFire components (e.g. CacheFactoryBean) here
    }
    

    然后,您的应用程序组件(其中一些依赖于GemFire组件)可以定义为:

    @Configuration
    @Import(GemFireConfiguration.class)
    class ApplicationConfiguration {
      // define application beans, including beans dependent on GemFire components
    }
    

    通过导入GemFireConfiguration,您可以确保首先创建(实例化、配置和初始化)GemFire组件/bean。

    在您拥有大量应用程序组件(服务、DAO等)的情况下,您甚至可以在Application ationConfiguration类级别使用更有针对性的、有限的“类路径组件扫描”。

    然后,您可以让您的主Spring Boot应用程序类驱动所有这些:

    @Configuration
    @Import(ApplicationConfiguration.class)
    class MySpringBootApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
      }
    }
    

    关键是,您可以选择粒度。我喜欢按关注点封装配置,并清楚地组织配置(使用导入)以反映我希望创建组件(构建、配置和初始化)的顺序。

    老实说,我基本上是按照依赖关系的顺序组织配置的。如果我的应用程序最终依赖于数据存储,没有该数据存储就无法运行,那么它需要确保首先初始化,否则,启动应用程序的意义是什么。

    最后,正如您所做的那样,您可以始终依赖于DependsOn注释,以确保Spring将在预期组件之前创建组件。

    基于@DependsOn注释解决了您的问题这一事实,那么我会说这是一个组织问题,属于我上面概述的1)/2)类别。

    我将对此进行更深入的探讨,并用我的发现在评论中回应我的答案。

    希望这有帮助!

    -约翰

  •  类似资料:
    • 我正在努力学习一本书名为《SpringMVC初学者指南》的书,我一直在努力创建存储库对象。我不断地得到一个BeanCreationException。不知道我还错过了什么。我想知道是否有人能帮我解决这个问题。 请在下面找到我的代码。谢谢 BeanCreationException XML文件: ProductCrontroller: 产品存储库: InMemoryProductRepository

    • 我正在试验Spring和MongoDB。在我的项目中,我有一个存储库和一个有调度方法的服务。问题是,存储库没有自动运行,它总是为空。 Autowire在主应用程序类中正常工作(通过实现CommandLineRunner进行测试) 我错过什么了吗? 目录 机器应用。JAVA 工人JAVA LineDataRepository

    • 我与SpringBoot和JPA合作。我收到一个无法完成的错误。 这是我的主要课程: 这是我的班级失败的原因: 这是类: 这是错误消息: 错误创建bean的名称'请求LoggerImpl':注入自动生成的依赖失败; 无法自动关联字段:专用com。存储库。请求logdao.com。记录器。impl。RequestLoggerImpl。请求logdao;嵌套的异常是org。springframewor

    • 问题内容: 能否请您告诉我,我如何才能很好地为Hibernate实体启用Spring自动装配? 假设我有一个实体,并希望在那里有邮件发送者: 有没有比做的更好的方法 在我的DAO中? 谢谢! 问题答案: 有可能的!(这是Spring Roo中的默认样式!) 您所需要做的就是将@Configurable批注添加到您的实体。在配置中并使用AspectJ编织激活注释。 Spring参考中有一章:7.8.

    • 我有个小问题。如果类是用@component、@service、@controller或@repository注释的,并且我想注入它的依赖项,我需要@autowired吗? 这段代码对我来说非常适用,因为它是UserDeviceService中指定的@Service注释。是因为那个吗?

    • 我有一个带有自动扫描和@Component注释的Spring项目。一些组件需要使用@Autow的注入到不同的bean中。默认情况下,它是否将是作为单例创建的相同组件bean?如果是,如何将同一组件的不同实例注入不同的bean中? 附言:我知道它接近基础,听起来很一般。只是想自己说清楚。 提前致谢