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
How to Autowire a Spring-annotated service class in a @Configuration class?
提问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:
采纳答案by alexbt
Your erroris the following (you are returning a null value):
您的错误如下(您返回的是空值):
@Bean
public SessionService sessionService() {
return sessionService;
}
Solution
解决方案
Since your
SessionServiceImpl
is annotated with@Service
, you can just remove the@Bean
method and let spring create it. Spring already makes it available for you.Or, If your
SessionServiceImpl
wasn't annotated with@Service
, you would need the following :
由于您
SessionServiceImpl
的注释为@Service
,您可以删除该@Bean
方法并让 spring 创建它。Spring 已经为您提供了它。或者,如果您
SessionServiceImpl
没有用 注释@Service
,则需要以下内容:
@Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl
is in a package not being scanned by spring (as suggested by @Milo? Milivojevi?)
如果这不起作用,则可能只是您SessionServiceImpl
的包裹中没有被 spring 扫描(如@Milo 所建议的?Milivojevi?)
You may add @ComponentScan
to 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 Autowire
any @Component
Bean (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
任何可以在没有运行时参数的情况下构造的@Component
Bean(不仅仅是@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 包含到我的集成测试类中,问题已解决!