Java 如何在@Configuration 类中自动装配带有 Spring 注释的服务类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38337012/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:13:12  来源:igfitidea点击:

How to Autowire a Spring-annotated service class in a @Configuration class?

javaspring-boot

提问by Razeen

I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.

我正在尝试将服务注释类注入 Spring Boot 应用程序中的配置类,但它没有被注入(设置为 null),我认为这是由于 Spring 生命周期。

Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.

此外,该服务有一个使用构造函数注入的重载构造函数,我想这也是一个问题,因为自动装配作用于默认构造函数。但是,该服务需要是 Spring 配置的,因此我认为不能在 Bean 注释方法中创建新实例。

How can one solve this?

如何解决这个问题?

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private SessionService sessionService;

    @Bean
    public SessionService sessionService() {
        return sessionService;
    }
}

public interface SessionService extends BaseCacheService<Session> {
    void extendExpiration(String key);

    String getSessionId(String key);
}

@Service
public class SessionServiceImpl implements SessionService {

    private Environment environment;
    private UserService userService;

    @Autowired
    public SessionServiceImpl(Environment environment, UserService userService) {
      this.environment = environment;
      this.userService = userService;
    }
}

If I exclude the @Bean method, then I get a compilation error: Autowire compilation error if no bean found

如果排除@Bean 方法,则会出现编译错误: 如果未找到 bean,则自动装配编译错误

采纳答案by alexbt

Your erroris the following (you are returning a null value):

您的错误如下(您返回的是空值):

@Bean
public SessionService sessionService() {
    return sessionService;
}


Solution

解决方案

  1. Since your SessionServiceImplis annotated with @Service, you can just remove the @Beanmethod and let spring create it. Spring already makes it available for you.

  2. Or, If your SessionServiceImplwasn't annotated with @Service, you would need the following :

  1. 由于您SessionServiceImpl的注释为@Service,您可以删除该@Bean方法并让 spring 创建它。Spring 已经为您提供了它。

  2. 或者,如果您SessionServiceImpl没有用 注释@Service,则需要以下内容:

@Bean
public SessionService sessionService() {
   return new SessionService();
}


If this doesn't work, it may just be that your SessionServiceImplis in a package not being scanned by spring (as suggested by @Milo? Milivojevi?)

如果这不起作用,则可能只是您SessionServiceImpl的包裹中没有被 spring 扫描(如@Milo 所建议的?Milivojevi?)

You may add @ComponentScanto your Configuration class

您可以添加@ComponentScan到您的配置类

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

回答by JudgingNotJudging

Expanding on @Alex's answer, when you annotate a method with @Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.

扩展@Alex 的答案,当您使用@Bean 注释方法时,它会告诉 Spring 该方法将生成该类型。因此,您实际上是告诉 Spring 为您提供所有 SessionService 类型的 Bean 的空引用。

If you are using Annotation-based context configuration, you can Autowireany @ComponentBean (not just @Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as @Alex suggested, or you can use getBeanand pass in the Type and Constructor arguments. The former is generally preferred.

如果您使用基于注解的上下文配置,您可以使用Autowire任何可以在没有运行时参数的情况下构造的@ComponentBean(不仅仅是@Service)(例如,具有默认构造函数或自动装配构造函数)。如果您需要做一些事情来创建 bean(例如需要运行时配置),您可以按照@Alex 的建议创建一个方法,或者您可以使用getBean并传入 Type 和 Constructor 参数。通常首选前者。

回答by Milo? Milivojevi?

If Alex's answer does not work (removing the @Bean method), you're probably not using @EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding @ComponentScan("service.class.package")to your configuration (in addition to removing the sessionService method) and see if it helps.

如果 Alex 的回答不起作用(删除 @Bean 方法),则您可能没有使用 @EnableAutoConfiguration 或者您的应用程序不在根层次结构包中,因此它没有扫描整个类路径。尝试添加@ComponentScan("service.class.package")到您的配置中(除了删除 sessionService 方法),看看它是否有帮助。

回答by Sangan K

I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use @ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.

我在为 Spring Boot 应用程序编写集成测试类时遇到了类似的问题。指标 API 的 RestTemplate 类和 CounterService 在我的服务类中自动装配。我可以使用 @ContextConfiguration(Classes={RestTemplate.class}) 将 RestTemplate 注入我的服务,但是将 CounterService.class 添加到上面的注释中没有帮助,也许是因为 CounterService 是一个接口而不是一个具体的类,因此我得到“不找到 CounterService 类型的 bean”问题。

Thanks to answer by Milos, I included @EnableAutoConfiguration to my integration test class, issue was resolved!

感谢 Milos 的回答,我将 @EnableAutoConfiguration 包含到我的集成测试类中,问题已解决!