spring @Autowired Bean with @Async got null field

w51jfk4q  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(43)

Springboot版本是2.6.13。
我有一个类数据,它看起来像这样:

package com.example.asynctest;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
@lombok.Data
@Async
public class Data {
    public class MyData{
        int age;
        String name = "";
    }

    private MyData myData = new MyData();
}

字符串
当我尝试让它自动连接时,myData字段为空。

package com.example.asynctest;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@Async
class CmmandLine implements CommandLineRunner{
    @Autowired
    private Data data;
    @Override
    public void run(String... args) throws Exception {
        log.info(data.toString());
    }
}


在IDEA中,data字段如下所示:debug picture
当我删除@Async注解时,自动连接的data.myData是正确的。我自己跟踪了这一点,bean被AsyncAnnotationBeanPostProcessorpostProcessAfterInitialization修改。我在entrypoint类上添加了@EnableAsync
那么,为什么会发生这种情况呢?我应该如何同时使用@Async和@Autowired呢?

nue99wik

nue99wik1#

你的代码的问题不是data对象没有被注入。事实上,它确实被注入了。为了绝对确定,你可以修改你的代码以通过构造函数注入:

@Component
@Slf4j
@Async
@RequiredArgsConstructor
class CmmandLine implements CommandLineRunner{

    private final Data data;

    @Override
    public void run(String... args) throws Exception {
        log.info(data.toString());
    }
}

字符串
如果data对象没有被正确注入,你会得到一个异常Parameter 0 of constructor in industries.atende. Tester required a bean of type 'com.example.asynctest.Data' that could not be found.。此外,即使(理论上)你没有得到这个异常,data.toString()也会产生一个NullPointerException。注意,这两个异常都没有发生。所以代码(几乎)正确工作。你在错误的地方寻找错误。
真实的问题是Data类中的toString()方法返回null。对象本身是notnull,但在IDEA调试中它似乎是null,因为Intellij Idea也使用方法toString()来为您描绘对象。而IDEA从toString()方法中获得null
那么为什么toString()返回null呢?因为你把它变成了@Async。每个@Async方法都应该返回由一个能够处理异步响应的类 Package 的值。例如,如果方法是@Async,你应该总是返回CompletableFuture<String>,而不仅仅是String。为什么?因为方法是在另一个线程上运行的,如果没有这个 Package 器,你就没有办法阻止它来获得结果(换句话说:你没有办法“等待”结果)。
所以我的建议是从顶层(类型)中删除@Async注解,只在你真正需要的方法上使用它。因为否则你没有办法解决这个问题。toString()是从Object类继承的,所以它不能返回CompletableFuture<String>-它必须返回String。所以让方法为String,你总是会得到null而不是真实的值。

相关问题