【问题标题】:Retrieving beans in Spring Boot?在 Spring Boot 中检索 bean?
【发布时间】:2020-06-04 23:34:57
【问题描述】:

我过去曾使用过传统的 Spring。我们通过 xml 配置定义了我们的 bean 并手动连接它们。我的团队终于齐心协力更新注解并使用 Spring Boot 而不是 Spring MVC 的“传统”方法。

话虽如此,我无法弄清楚我是如何在 Boot 中检索 bean 的。在 legacy 中,Spring 要么使用构造函数/setter 注入(取决于我们的配置),要么我们可以直接调用带有 context.getBean("myBeanID"); 的 bean,但现在似乎不再是这种情况了。

我整理了一个小测试用例,尝试在下面的代码中让它工作:

package com.ots;


import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class GriefUIApplication{

    public static void main(String[] args) {
        SpringApplication.run(GriefUIApplication.class, args);

        SessionFactory factory = new Configuration().configure("hibernate.cfg.xml")
                .addAnnotatedClass(GriefRecord.class).addAnnotatedClass(RecordId.class)
                .addAnnotatedClass(CrossReferenceRecord.class)
                .buildSessionFactory();

        Statics.setSessionFactory(factory);

        TennisCoach tCoach = new TennisCoach();
        tCoach.getCoach();

    }

}



interface Coach{
    public String workout();
}


@Service
class TennisCoach implements Coach{

    private Coach soccerCoach;
    @Autowired
    private ApplicationContext context;


    public TennisCoach() {

    }

    public Coach getCoach() {

        System.out.println(context + " IS THE VALUE OF THE CONTEXT OBJECT");

        soccerCoach = (SoccerCoach)context.getBean("soccerCoach");

        System.out.println(soccerCoach.getClass());

        return soccerCoach;

    }

    @Override
    public String workout() {
        String practice = "practice your backhand!";
        System.out.println(practice);
        return practice;
    }


}

@Service
class SoccerCoach implements Coach{

    public SoccerCoach() {

    }

    @Override
    public String workout() {
        String practice = "practice your footwork!";
        System.out.println(practice);
        return practice;
    }

}

@RestController
class MyController{

    @GetMapping("/")
    public String sayHello() {

        return "Time on server is: " + new java.util.Date();
    }

}

我尝试将 ApplicationContext 对象自动装配到 TennisCoach 类中。当我运行它时,该对象为空。

我们如何在 Boot 中检索 bean?

【问题讨论】:

    标签: java spring-boot javabeans


    【解决方案1】:

    最常用的方法是使用@Autowired 注解。另外,因为Coach 接口有两种不同的实现,所以应该使用@Qualifier 注解来告诉Spring 要注入哪个接口实现。

    一些关于这两个注释的教程,让你开始:

    对于您的示例,要将 bean 注入您的控制器,您应该这样做:

    @RestController
    class MyController {
    
        @Autowired
        @Qualifier("soccerCoach")
        private Coach coach;
    
        @GetMapping("/")
        public String sayHello() {
            // this should invoke the workout() from SoccerCoach implementation
            System.out.println(coach.workout());
    
            return "Time on server is: " + new java.util.Date();
        }
    
    }
    

    或者,按照您的意图将soccerCoach 注入tennisCoach,使用构造函数注入,代码将变为:

    @Service
    class TennisCoach implements Coach {
    
        private Coach soccerCoach;
    
        @Autowired
        public TennisCoach(@Qualifier("soccerCoach") Coach soccerCoach) {
            this.soccerCoach = soccerCoach;
        }
    
        public Coach getCoach() {
            System.out.println(soccerCoach.getClass());
    
            return soccerCoach;
        }
    
    }
    

    如果您确实需要使用ApplicationContext 来检索一些bean,则不建议在具有main 函数的类中这样做。只需创建另一个 bean(您可以使用 @Componenent 注释)。这是一个例子:

    @Component
    public class AnyComponent {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        public void invokeCoach() {
            System.out.println(applicationContext.getBean("tennisCoach"));
            System.out.println(applicationContext.getBean(SoccerCoach.class));
        }
    
    }
    

    并在您的应用程序流中注入此 bean,可以在控制器、服务或存储库中:

    @RestController
    class MyController {
    
        @Autowired
        private AnyComponent anyComponent;
    
        @GetMapping("/")
        public String sayHello() {
            anyComponent.invokeCoach();
    
            return "Time on server is: " + new java.util.Date();
        }
    
    }
    

    注意:通过注解注入 bean 是 Spring 特有的,一般来说,不是 Spring Boot。

    来自https://www.baeldung.com/spring-autowire

    从 Spring 2.5 开始,该框架引入了一种由 @Autowired Annotations 驱动的新风格的依赖注入。此注解允许 Spring 解析协作 bean 并将其注入到您的 bean 中。

    【讨论】:

    • 如果没有现场注入,我该怎么做?根据我的阅读,这通常被认为是不好的做法。我将如何使用构造函数注入来做到这一点?
    • 我已经更新了我的答案以通过构造函数注入来做到这一点。我个人喜欢现场注入,但我认为这只是一个偏好问题。 soccerCoach 也可能是最终的:private final Coach soccerCoach;
    • 我明白,但这里的两个答案都略微偏离了重点。我不明白 如何 检索 bean。如果您查看我的代码,在主要方法中,我正在尝试实例化网球教练查看new Coach() 过程。但是,我得到一个空指针异常。即使将我的代码更改为与您上面的代码一样,我仍然会收到空指针异常。如何从 Spring 容器中检索 bean?
    • 它应该和你尝试过的一样,使用 ApplicationContext。在您的主应用程序中,只需执行context.getBean(TennisCoach.class)。更多详情:stackoverflow.com/questions/34088780/….
    • 我查看了该页面并尝试自动装配应用程序上下文。它只是返回为空,不起作用。
    【解决方案2】:

    直接注入所需的bean。 Spring boot 中不需要ApplicationContext

    @Service
    class TennisCoach {
    
        private SoccerCoach soccerCoach;
    
        @Autowired
        public TennisCoach(SoccerCoach soccerCoach) {
          this.soccerCoach = soccerCoach;
        }
    
    }
    

    【讨论】:

    • 如果你的字段是final的并且只有一个构造函数,那么即使@Autowired注解也不需要。我通常使用 Lombok 的 @RequiredArgsConstructor 来消除样板。
    • 我如何检索这个 bean? TennisCoach tCoach = new Coach();?当我尝试实例化对象时,它说我缺少一个参数。
    • 不需要这样做。 Spring 容器将负责对象实例化。
    • 好的,但是如果我不执行new Coach()如何检索 bean?在我的主要方法中,我试图检索 bean,但我不知道该怎么做。
    猜你喜欢
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    • 2016-08-22
    • 2016-09-10
    • 2016-07-05
    • 2019-11-29
    • 1970-01-01
    相关资源
    最近更新 更多