简体   繁体   English

由于 spring 上下文的双重加载,SpringBoot 无法将 bean 注入 kafkaConumser 即在 spring 托管类之外的类中

[英]SpringBoot not able to inject bean into kafkaConumser i.e. in class outside spring managed class due to double loading of spring context

I am using spring boot starter 2.2.0.RELEASE for my application.我正在为我的应用程序使用 spring boot starter 2.2.0.RELEASE。 I have one kafka consumer.我有一个 kafka 消费者。 Now I want to inject my spring entities into my kafka consumer (kafka consumer is not managed by spring container).现在我想将我的 spring 实体注入我的 kafka 消费者(kafka 消费者不受 spring 容器管理)。

I tried ApplicationContextAware but it didn't helped me.我尝试了 ApplicationContextAware 但它没有帮助我。 I am getting applicationContext as null in my kafka consumer and hence I am not able to get bean from spring container.我在我的 kafka 消费者中将 applicationContext 设为 null,因此我无法从 spring 容器中获取 bean。 First time applicationContext is getting set properly but when context loads second time it set to null.第一次 applicationContext 设置正确,但是当第二次加载上下文时,它设置为 null。 Below are the details of my application in short以下是我的申请详情

@SpringBootApplication
@ComponentScan({"com.xyz.config_assign.service"})
public class ConfigAssignServer {

    private static Logger log = LoggerFactory.getLogger(ConfigAssignServer.class);

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigAssignServer.class, args);

        log.info("Started ConfigAssign Server!!! AppName= {} ", applicationContext.getApplicationName());

       QkafkaClient.loadConfiguration();


    }

}

All my application classes are present in com.xyz.config_assign.service so no issue of bean scanning problem.我所有的应用程序类都存在于 com.xyz.config_assign.service 中,因此没有 bean 扫描问题。 It worked well before I add Kafka consumer在我添加 Kafka 消费者之前它运行良好

My ApplicationContextProvider which is using famous ApplicationContextAware我的 ApplicationContextProvider 正在使用著名的 ApplicationContextAware

@Component
public class ApplicationContextProvider implements ApplicationContextAware{

    public static ApplicationContext applicationContext;


    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextProvider.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

And now my kafkaconsumer现在我的 kafkaconsumer

    public class ConfigAssignmentAssetTagChangeKafkaTopicProcessor implements BatchTopicProcessor<String, String> {

    private Logger log = LoggerFactory.getLogger(ConfigAssignmentAssetTagChangeKafkaTopicProcessor.class);


    private AssignConfigServiceImpl assignConfigServiceImpl;

    public  ConfigAssignmentAssetTagChangeKafkaTopicProcessor(){
        ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
        assignConfigServiceImpl = applicationContext.getBean(AssignConfigServiceImpl.class);
    }

    @Override
    public void handleError(ConsumerRecords<String, String> arg0, Exception arg1) {
        // TODO Auto-generated method stub

    }

    @Override
    public void process(ConsumerRecords<String, String> records, long arg1) {}
}

And the service I want to inject into kafka consumer is我想注入 kafka 消费者的服务是

   @Service
public class AssignConfigServiceImpl implements AssignConfigService {

    private Logger log = LoggerFactory.getLogger(AssignConfigServiceImpl.class);

    @Autowired
    private ConfigProfileDBService dbService;



    public boolean assignConfigToAgents(List<UUID> agentList, long customerId) {
        List<AgentConfigurationProfile> configProfiles = 
        dbService.getConfigurationProfilesForCustomer(customerId);
        boolean isAssignSuccessful = assignConfigToAgents(agentList, customerId, configProfiles);
        log.info("Config Assignment status ={}", isAssignSuccessful);

        return isAssignSuccessful;

    }

The other service I used is我使用的其他服务是

@Service
public class ConfigProfileDBService implements DBService {

    private static Logger log = LoggerFactory.getLogger(ConfigProfileDBService.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;


    public List<AgentConfigurationProfile> getConfigurationProfilesForCustomer(Long customerId) {
        List<AgentConfigurationProfile> agentConfigList;
}

} }

Can someone please let me know what went wrong, I tried multiple online solution but didn't worked for me.有人可以让我知道出了什么问题,我尝试了多种在线解决方案,但对我不起作用。 Thanks in advance.提前致谢。 Note : I haven't initialized any class using new operator.注意:我没有使用 new 运算符初始化任何类。

Based on clarifications in question and comments, and assuming its impossible to move KafkaConsumer to be spring managed (which is I believe the best solution):基于问题和评论的澄清,并假设不可能将 KafkaConsumer 移动到春季管理(我认为这是最好的解决方案):

@Autowired won't work in KafkaConsumer, so no need to put that annotation. @Autowired在 KafkaConsumer 中不起作用,因此无需放置该注释。

I assume that you're getting null for Application context in this line:我假设您在这一行中的 Application 上下文为 null:

 ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();

This means that ApplicationContextProvider#setApplicationContext has not been called by the time you create Kafka Consumer.这意味着在您创建 Kafka Consumer 时尚未调用ApplicationContextProvider#setApplicationContext Spring in addition to injection also manages lifecyle of the managed objects.除了注入之外,Spring 还管理托管对象的生命周期。 Since you're not in spring, you're "on-your-own" and you have to make sure that Application Context gets created first and only after that create other objects (like Kafka Consumer for example).由于您不在春天,因此您是“自己的”,您必须确保首先创建应用程序上下文,并且只有在创建其他对象(例如 Kafka Consumer)之后。

When application context starts it adds beans one by one at some point, among other beans it also gets to the ApplicationContextProvider and calls its setter.当应用程序上下文启动时,它会在某个时刻一个一个地添加 bean,在其他 bean 中,它还到达ApplicationContextProvider并调用它的 setter。

My main problem was my spring context was being loaded twice.我的主要问题是我的 spring 上下文被加载了两次。 As I printed every class's class loader I found that my Application was running twice.当我打印每个类的类加载器时,我发现我的应用程序运行了两次。 (ie when I debug in intellij after pressing F9 I was again landing up on same line ie (即当我在按 F9 后在 intellij 中调试时,我再次登陆同一行,即

ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigAssignServer.class, args);

My problem was in pom.xml.我的问题是在 pom.xml 中。 I removed below dependency from my pom and it worked.我从我的 pom 中删除了以下依赖项并且它起作用了。

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>

Please check for your dependencies.请检查您的依赖项。 Hope it will help someone.希望它会帮助某人。 Enjoy coding :)享受编码:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM