如何使用 main(String[] args) 方法中的自动装配(@Autowired)引用?
How to use autowired (@Autowired) references from main(String[] args) method?
我正在尝试使用来自 main class 的自动装配引用,并且我正面临:
Cannot make a static reference to the non-static field
zipCodeLookupService.
这是显而易见的。但我想知道如何处理这种情况。涉及 main class 时自动装配的正确方法是什么。我的代码如下 -
界面class
package com.example.services;
public interface IZipCodeLookup {
String retriveCityForZip(String zipCode);
}
服务Class
package com.example.services;
import org.springframework.stereotype.Service;
@Service
public class ZipCodeLookupService implements IZipCodeLookup {
@Override
public String retriveCityForZip(String zipCode) {
//below is mock code. actual code does a db lookup using a DAO.
if(zipCode=="94123") return "San Francisco";
return "not found in DB";
}
}
这里是主要的 class 需要服务 class
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.example.services.IZipCodeLookup;
@SpringBootApplication
public class AutowireWithMainClassApplication {
@Autowired
IZipCodeLookup zipCodeLookupService;
public static void main(String[] args) {
SpringApplication.run(AutowireWithMainClassApplication.class, args);
String city;
//this will not work, compilation error
//Cannot make a static reference to the non-static field zipCodeLookupService
city=zipCodeLookupService.retriveCityForZip(args[0]);
System.out.println("city for zipcode " + args[0] + " is " +city);
}
}
有人可以建议 - 当涉及 main class 时,如何使用自动装配的正确方法或什么是正确的方法。
(因为将 Autowired 引用设为静态无论如何都不起作用)
在 AutowireWithMainClassApplication
class 中,更改为 -
@Autowired
static IZipCodeLookup zipCodeLookupService;
投掷
Exception in thread "main"
java.lang.NullPointerException
用 @SpringBootApplication
注释注释的 class 不是 classic bean。
它从 [=55] 创建 Spring 上下文=]静态方法。
但是自动装配的依赖项不能是 static.
这就是为什么这个声明:
city=zipCodeLookupService.retriveCityForZip(args[0]);
当您将 zipCodeLookupService
声明为 static
字段时, 不会抛出 Spring 异常,而是 classic NullPointerException
。
在您的情况下,作为解决方法,您可以在 instance 方法中移动使用 Spring bean 的处理,该方法在您的内部用 javax.annotation.PostConstruct
方法注释main class 并将传递给 main()
方法的参数存储在一个字段中,以便以后能够使用它:
private static String[] args;
@Autowired
IZipCodeLookup zipCodeLookupService;
public static void main(String[] args) {
AutowireWithMainClassApplication.args = args;
SpringApplication.run(AutowireWithMainClassApplication.class, args);
}
@PostConstruct
public void init() {
String city=zipCodeLookupService.retriveCityForZip(args[0]);
System.out.println("city for zipcode " + args[0] + " is " +city);
}
要回答您的评论,您应该注意有关 @PostConstruct
的几件事
1) 它不是特定于 Spring 的注释。因此,官方文档可能会讨论比 Spring 更笼统的事情,或者讨论具体但不同的事情,例如 EJB(它最初是为他们引入的)。
2) javadoc 的第一句总结了一般的预期行为。
The PostConstruct annotation is used on a method that needs to be
executed after dependency injection is done to perform any
initialization.
但是这句话
"executed after dependency injection is done"
确实意味着:
"executed after all dependency injections are done"
我们笼统地谈论依赖注入,而不是每个依赖注入。
所以,是的,坚持下去。
将它应用到你的案例中应该会让事情变得更清楚。
AutowireWithMainClassApplication
class 被认为是一个 Spring bean,因为 @SpringBootApplication
用 @Configuration
注释,@Configuration
本身用 @Component
.[=59= 注释]
和任何 Spring bean 一样,它可以声明依赖注入。
那是一个依赖注入:
@Autowired
IZipCodeLookup zipCodeLookupService;
但是您当然可以声明任意数量的依赖注入:
@Autowired
IZipCodeLookup zipCodeLookupService;
@Autowired
OtherClass otherClass;
...
因此,仅当 所有 依赖项都被有效注入时,PostConstruct
才会被一次又一次地调用。
您可以执行以下操作之一:
在@PostConstruct方法中使用@Autowired对象,依赖注入完成后执行,如上所述 davidxxx
在您的 main() 中使用 Spring 的 getBean() 明确要求 Spring 框架 return 注入完成后的对象:
public static void main(String[] args) {
...
ConfigurableApplicationContext appContext = SpringApplication.run(StartApplication.class, args);
IZipCodeLookup service = appContext.getBean(IZipCodeLookup.class);
...
}
使用Spring的CommandLineRunner组件(运行紧跟在main之后),它将负责自动装配你的对象:
@Component
public class MyRunner implements CommandLineRunner {
@Autowired
private IZipCodeLookup service;
@Override
public void run(String... args) throws Exception {
...
service.doSomething();
...
}
}
在您的 main 中实现 Spring 的 ApplicationRunner 的 运行 方法:
@SpringBootApplication
public class StartApplication implements ApplicationRunner {
@Autowired
private IZipCodeLookup service;
public static void main(String[] args) {
ConfigurableApplicationContext appContext = SpringApplication.run(StartApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
...
service.doSomething();
...
}
}
我正在尝试使用来自 main class 的自动装配引用,并且我正面临:
Cannot make a static reference to the non-static field zipCodeLookupService.
这是显而易见的。但我想知道如何处理这种情况。涉及 main class 时自动装配的正确方法是什么。我的代码如下 -
界面class
package com.example.services;
public interface IZipCodeLookup {
String retriveCityForZip(String zipCode);
}
服务Class
package com.example.services;
import org.springframework.stereotype.Service;
@Service
public class ZipCodeLookupService implements IZipCodeLookup {
@Override
public String retriveCityForZip(String zipCode) {
//below is mock code. actual code does a db lookup using a DAO.
if(zipCode=="94123") return "San Francisco";
return "not found in DB";
}
}
这里是主要的 class 需要服务 class
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.example.services.IZipCodeLookup;
@SpringBootApplication
public class AutowireWithMainClassApplication {
@Autowired
IZipCodeLookup zipCodeLookupService;
public static void main(String[] args) {
SpringApplication.run(AutowireWithMainClassApplication.class, args);
String city;
//this will not work, compilation error
//Cannot make a static reference to the non-static field zipCodeLookupService
city=zipCodeLookupService.retriveCityForZip(args[0]);
System.out.println("city for zipcode " + args[0] + " is " +city);
}
}
有人可以建议 - 当涉及 main class 时,如何使用自动装配的正确方法或什么是正确的方法。
(因为将 Autowired 引用设为静态无论如何都不起作用)
在 AutowireWithMainClassApplication
class 中,更改为 -
@Autowired
static IZipCodeLookup zipCodeLookupService;
投掷
Exception in thread "main" java.lang.NullPointerException
用 @SpringBootApplication
注释注释的 class 不是 classic bean。
它从 [=55] 创建 Spring 上下文=]静态方法。
但是自动装配的依赖项不能是 static.
这就是为什么这个声明:
city=zipCodeLookupService.retriveCityForZip(args[0]);
当您将 zipCodeLookupService
声明为 static
字段时, 不会抛出 Spring 异常,而是 classic NullPointerException
。
在您的情况下,作为解决方法,您可以在 instance 方法中移动使用 Spring bean 的处理,该方法在您的内部用 javax.annotation.PostConstruct
方法注释main class 并将传递给 main()
方法的参数存储在一个字段中,以便以后能够使用它:
private static String[] args;
@Autowired
IZipCodeLookup zipCodeLookupService;
public static void main(String[] args) {
AutowireWithMainClassApplication.args = args;
SpringApplication.run(AutowireWithMainClassApplication.class, args);
}
@PostConstruct
public void init() {
String city=zipCodeLookupService.retriveCityForZip(args[0]);
System.out.println("city for zipcode " + args[0] + " is " +city);
}
要回答您的评论,您应该注意有关 @PostConstruct
1) 它不是特定于 Spring 的注释。因此,官方文档可能会讨论比 Spring 更笼统的事情,或者讨论具体但不同的事情,例如 EJB(它最初是为他们引入的)。
2) javadoc 的第一句总结了一般的预期行为。
The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization.
但是这句话
"executed after dependency injection is done"
确实意味着:
"executed after all dependency injections are done"
我们笼统地谈论依赖注入,而不是每个依赖注入。
所以,是的,坚持下去。
将它应用到你的案例中应该会让事情变得更清楚。
AutowireWithMainClassApplication
class 被认为是一个 Spring bean,因为 @SpringBootApplication
用 @Configuration
注释,@Configuration
本身用 @Component
.[=59= 注释]
和任何 Spring bean 一样,它可以声明依赖注入。
那是一个依赖注入:
@Autowired
IZipCodeLookup zipCodeLookupService;
但是您当然可以声明任意数量的依赖注入:
@Autowired
IZipCodeLookup zipCodeLookupService;
@Autowired
OtherClass otherClass;
...
因此,仅当 所有 依赖项都被有效注入时,PostConstruct
才会被一次又一次地调用。
您可以执行以下操作之一:
在@PostConstruct方法中使用@Autowired对象,依赖注入完成后执行,如上所述 davidxxx
在您的 main() 中使用 Spring 的 getBean() 明确要求 Spring 框架 return 注入完成后的对象:
public static void main(String[] args) { ... ConfigurableApplicationContext appContext = SpringApplication.run(StartApplication.class, args); IZipCodeLookup service = appContext.getBean(IZipCodeLookup.class); ... }
使用Spring的CommandLineRunner组件(运行紧跟在main之后),它将负责自动装配你的对象:
@Component public class MyRunner implements CommandLineRunner { @Autowired private IZipCodeLookup service; @Override public void run(String... args) throws Exception { ... service.doSomething(); ... } }
在您的 main 中实现 Spring 的 ApplicationRunner 的 运行 方法:
@SpringBootApplication public class StartApplication implements ApplicationRunner { @Autowired private IZipCodeLookup service; public static void main(String[] args) { ConfigurableApplicationContext appContext = SpringApplication.run(StartApplication.class, args); } @Override public void run(ApplicationArguments args) throws Exception { ... service.doSomething(); ... } }