Spring Boot - 如何使用非默认构造函数@Autowired Bean?

Mis*_*bon 4 spring spring-boot

我在这里找到了很多关于使用@Autowired和非空构造函数的信息.但我甚至无法解决我目前的问题.

我有一个日志记录界面.我正在记录数据库中的每个条目.出于这个原因,我必须知道类名,哪个类使用记录器.

我的第一个想法:创建一个Logger的新实现,它有一个非空的构造函数.因此,在创建此记录器的新实例时,您必须设置名称.

我的界面看起来像这样:

public interface Logger{
  public void log(String name, String msg);
}
Run Code Online (Sandbox Code Playgroud)

其实现如下:

@Service
public class LoggerImpl implements Logger{
 private String className;

 LoggerImpl(String className){ this.className = className }

 @Override
 public void log(String name, String msg) { // print and save in the database }
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序的任何地方我都想使用这个记录器 - 接口.例如,在某些业务类中,我以这种方式使用Logger:

@Service
public class ServiceName {
 private Logger logger;

 @Autowired
 public ServiceName(){
   logger = new LoggerImpl("ServiceName");
 }

 public void someMethod(){
    logger.log("name", "this is a log!");
 }
}
Run Code Online (Sandbox Code Playgroud)

但我的应用程序告诉我,他没有数据库通信并抛出一个NullPointerException,同时保存数据库中的日志.在创建非空构造函数之前,此通信有效.所以我的猜测是,当我手动创建此LoggerImpl时,此对象不再位于spring应用程序上下文中.有什么想法要解决?谢谢.编辑:我正在使用Spring Boot,我没有任何XML文件.

Bar*_*cki 5

我认为在这种情况下用 @Service 注释是不够的。Spring 将无法创建 LoggerImpl 的实例。

您必须告诉 Spring 如何创建实例。当使用 XML 配置时,你应该这样做

<bean id="loggerForX" class="LoggerImpl ">
  <constructor-arg index="0" value="X" />
</bean>
Run Code Online (Sandbox Code Playgroud)

使用javaconfig时

@Configuration
public class LoggerConfiguration {

  @Bean
  public Logger loggerForX() {
    return new LoggerImpl("X");
  }

}
Run Code Online (Sandbox Code Playgroud)

然后您将能够@Autowire Logger 作为

@Autowire  Logger loggerForX;
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,请尝试自动装配loggerForX变量 ab

@Autowire @Qualifier("loggerForX") Logger loggerForX;

使用这种方法,您必须为每个需要记录器的类创建单独的 bean。创建LoggerFactory为 bean 并注入它可能会更好LoggerFactory。LoggerFactory必须有方法来创建Logger。

@Service
class LoggerFactory  {

  public Logger loggerFor(String name) {
    return new LoggerImpl(name);
    }

}
Run Code Online (Sandbox Code Playgroud)

LoggerFactory有默认构造函数,可以轻松地出现在@Autowired您想要的任何地方。


Rub*_*ben 5

您可能想看一下新的InjectionPoint

@Configuration
public class LoggerConfig {

  @Bean
  @Scope("prototype")
  public Logger logger(InjectionPoint injectionPoint) {
    //this is the class where the logger will be used     
    Class<?> theClassYouAreLookingFor = injectionPoint.getMember().getDeclaringClass();
    return findOrCreateYourLogger(theClassYouAreLookingFor);
  }
}
Run Code Online (Sandbox Code Playgroud)

要Logger像正常使用任何其他Bean一样使用它.