如何在抽象类中获取applicationContext引用?

How to get an applicationContext reference in abstract class?

提问人:boardtc 提问时间:8/2/2023 最后编辑:boardtc 更新时间:8/2/2023 访问量:71

问:

我正在重构现有代码,需要在抽象类中获取applicationContext引用。

简化起见,这里有两个类来说明这个问题:

public abstract class BaseCheck {

  private ApplicationContext applicationContext;

  protected AbstractConfig configClass;


  @Autowired
  // not called before setConfigClass called so null
  public final void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
  }

  public AbstractConfig getConfigClass() {
    return configClass;
  }

  public void setConfigClass(String configClass) {
    // fails due to null applicationContext
    this.configClass = (AbstractConfig) applicationContext.getBean(configClass);
  }

}


@Component
@DependsOn({"myConfig"})
public class FirstCheck extends BaseCheck {

  public FirstCheck() {
      setConfigClass("myConfig");
  }
}

我无法注入applicationContext。此代码对 setter 进行注释,如 https://www.baeldung.com/spring-autowired-abstract-class

我还尝试实现ApplicationContextAware,但这也不适用于抽象类。

有谁知道我怎样才能让它工作?

Java spring-boot 自动连线

评论

0赞 BadZen 8/2/2023
abstract不对类进行组件扫描。您必须自动连接扩展子类的构造函数。
0赞 boardtc 8/2/2023
我希望有另一种方法,因为我有 7 个扩展类,并且不想将 applicationContext 添加到他们所有的构造函数中,但它确实解决了问题!添加您的评论作为答案。还有其他解决方案吗?
0赞 Jim Garrison 8/2/2023
抽象类除了作为具体子类的一部分之外,没有独立的存在。Spring 就是将具体的类实例实例化和连接在一起。
0赞 boardtc 8/2/2023
然而,@JimGarrison能够在抽象类中自动连接 setter 方法(如链接所示)
0赞 Jim Garrison 8/2/2023
因为 setter 可以继承,而构造函数不能。也许@PostConstruct?

答:

1赞 DingHao 8/2/2023 #1

您可以 impl InitializingBean 。

@Component
@DependsOn({"myConfig"})
public class FirstCheck extends BaseCheck implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        setConfigClass("myConfig");
    }
    
}

评论

0赞 boardtc 8/2/2023
不幸的是,我尝试了这个,但没有效果。
1赞 M. Deinum 8/2/2023 #2

问题是您正在尝试访问构造函数中的。此时,该方法尚未被调用,因为 Spring 只能在对象构造后调用它。您在施工期间访问它,因此 .ApplicationContextsetApplicationContextNullPointerException

您可以做的是将 注入到构造函数中,以便您可以访问它。不要使用 来查找 bean,而是使用 并将正确的配置注入到构造函数中,而不是使用ApplicationContextApplicationContext@QualifiersetConfigClass

public abstract class BaseCheck {

  protected AbstractConfig configClass;

  protected BaseCheck(AbstractConfig configClass) {
    this.configClass=configClass;
  }

  public AbstractConfig getConfigClass() {
    return configClass;
  }
}


@Component
public class FirstCheck extends BaseCheck {

  public FirstCheck(@Qualifier("myConfig") AbstractConfig configClass) {
      super(configClass);
  }
}

这样,您就不需要访问 .无论如何,您已经在构造函数中拥有该名称(现在可以将其删除),因此将其移动到 an 以获得正确的实例应该可以这样做。ApplicationContext@DependsOn@Qualifier

评论

0赞 boardtc 8/2/2023
一个令人兴奋的想法!我删除了所有applicationContext引用,并在所有配置上添加了@Qualifier,如图所示。我遇到的一个问题是 FirstCheck,其他问题是侦听器,另一个启动侦听器的类失败,因为配置类为 null。我尝试将@ DependsOn用于侦听器入门类中的所有配置。该代码之前在侦听器启动器构造函数中传递配置的地方工作,但我正在远离它,因为 SonarQube 在构造函数 (9) 中突出显示了太多参数。P.S. 你不能对抽象类进行构造函数注入
0赞 M. Deinum 8/2/2023
只要将引用传递给抽象类(这就是我在这里所做的),就可以毫无问题地进行构造函数注入。使用构造函数注入时,除非您不是通过 Spring 而是在其他地方实例化它们,否则事情就不可能了!null
0赞 boardtc 8/2/2023
我不会挂断电话,baeldung 帖子中有详细介绍。 @EventListener(ApplicationReadyEvent.class) 位于启动侦听器的方法上。配置仍然是空的:-(
1赞 M. Deinum 8/2/2023
现在你把所有这些注释都拉走了......您没有在问题中提及这些内容,因此您的问题包含愚蠢的代码,请提供具有代表性的代码。基本上,依赖项不能为空,应用程序甚至不会以该依赖项启动,并在启动期间因依赖项不满意而爆炸。创建代理,如果事情是私有的,最终的等,这些将对代理隐藏(所以请添加一些实际代码而不是愚蠢的代码)。@EventListener
0赞 boardtc 8/2/2023
谢谢,你已经回答了我提出的问题,对愚蠢的版本是公平的。我使用 Project Lombok 完全删除了构造函数,从而完全消除了这个问题!