尽管设置正确,@Autowired @Service Bean 为空

@Autowired @Service Bean is null although set up properly

我在启动基于 Spring Boot 2.1.4 的应用程序时遇到此错误:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [test.services.AlmConnectivity]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1295) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    ... 22 common frames omitted
Caused by: java.lang.NullPointerException: null
    at test.services.AlmConnectivity.initProxyBean(AlmConnectivity.java:43) ~[classes/:na]
    at test.services.AlmConnectivity.<init>(AlmConnectivity.java:30) ~[classes/:na]

提到的行 43 是以 proxy =:

开头的行
@DependsOn({ "config", "cfg" })
private void initProxyBean() {
    System.err.println("Config: " + config);
    proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getProxyHost(), config.getProxyPort()));
}

System.err 也打印 null 。如您所见,我尝试使用 @DependsOn 来表示依赖关系。

这些是(我猜)class 的其他相关部分:

@Service
public class AlmConnectivity {
    Logger log = LoggerFactory.getLogger(AlmConnectivity.class);

    @Autowired
    @Qualifier("config")
    Config config;

    private Proxy proxy;

    private OkHttpClient client;

    public AlmConnectivity() {
        initProxyBean();
        initClientBean(proxy);
    }

因为我更喜欢使用更短的名称 @Qualifier,但即使我跳过此步骤并使用其全名 config 获取 bean,它也不起作用并且配置保持为空。

这是配置 class:

@Component
public class Config {

    @NotNull
    @NotEmpty
    @Value("${proxy.host}")
    private String proxyHost = "i.am.desparate";

    @NotNull
    @NotEmpty
    @Value("${proxy.port}")
    private int proxyPort = 8090;

    public String getProxyHost() {
        return proxyHost;
    }

    public int getProxyPort() {
        return proxyPort;
    }
}

我的主要 class 带有这些注释:

@SpringBootApplication
@EnableScheduling
@Configuration
@ComponentScan
@EnableAutoConfiguration

(后三个是我在尝试获取此 运行 时添加的)

您可能希望将您的行为从在构造函数中调用更改为

javax.annotation.PostConstruct

注释方法:

@Service
public class AlmConnectivity {

    Logger log = LoggerFactory.getLogger(AlmConnectivity.class);

    @Autowired
    @Qualifier("config")
    Config config;

    private Proxy proxy;

    private OkHttpClient client;

    @PostConstruct
    private void initProxyBean() {
        System.err.println("Config: " + config);
        proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getProxyHost(), config.getProxyPort()));
    }
}

只是添加有关 Smutje 上面提供的答案的信息:

Bean 构造器用于创建 bean 的实例。

Spring 首先调用 Bean 构造函数,只有在那之后,当有一个 bean 实例时,才调用自动装配逻辑(你可以在 [=28= 中阅读 bean post 处理器] 了解它们是如何工作的,但它超出了这个问题的范围)。

完成自动装配逻辑并注入所有自动装配字段后,Spring 调用用 @PostConstruct 注释的方法。

这是您可以初始化代码的地方。

所以可能的答案之一确实是使用 bean post 构造函数。

另一种方法是停止使用字段注入,转而使用构造函数注入:

@Service  
public class AlmConnectivity {

  @Autowired // optional annotation in modern spring if you have a single constructor
  public AlmConnectivity(@Qualifier("config") Config  config) {
       // here config is not null, so you can init proxy
  }
}