如何使用main(String [] args)方法中的自动装配(@Autowired)引用?

时间:2017-10-07 05:40:13

标签: spring spring-boot dependency-injection inversion-of-control autowired

我正在尝试使用主类的自动装配引用并面临:

  

无法对非静态字段进行静态引用   zipCodeLookupService。

这很明显。但我想知道如何处理这种情况。涉及主类时,自动装配的正确方法是什么。我的代码如下 -

接口类

package com.example.services;
public interface IZipCodeLookup {
    String retriveCityForZip(String zipCode);
}

服务类

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";
    }
}

这是需要服务类的主类

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);       
    }
}

有人可以建议 - 在涉及主类时使用自动装配的正确方法是什么或者是什么。

(因为将Autowired引用设为静态无论如何都不起作用)
AutowireWithMainClassApplication课程中,更改为 -

@Autowired
static IZipCodeLookup zipCodeLookupService;

引发

  

线程“main”中的异常   显示java.lang.NullPointerException

2 个答案:

答案 0 :(得分:3)

使用city=zipCodeLookupService.retriveCityForZip(args[0]); 注释注释的类不是经典bean。
它使用静态方法创建Spring上下文。
但自动连接的依赖项不能静态

这就是为什么这句话:

NullPointerException
在您将zipCodeLookupService声明为static字段时,

不会抛出Spring异常而是经典javax.annotation.PostConstruct

在您的情况下,作为解决方法,您可以在主类中使用main()方法注释的实例方法中移动使用Spring bean的处理,并存储传递给它的参数。字段中的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

要回答您的评论,您应该注意一些关于AutowireWithMainClassApplication

的内容

1)它不是Spring特有的注释。因此,官方文档可能会讨论比Spring更通用的东西或特定但不同的东西,例如EJB(它最初是为它们引入的)。

2)javadoc的第一句话总结了一般预期的行为。

  

PostConstruct注释用于需要的方法   在完成依赖注入以执行任何操作之后执行   初始化。

但这句话

  

“在完成依赖注入后执行”

确实意味着:

  

“完成所有依赖注入后执行”

我们一般谈论依赖注入,而不是每次依赖注入 所以,是的,坚持你。

将它应用到你的案件中应该让事情更清楚 @SpringBootApplication类被视为Spring bean,@Configuration使用@Component进行注释,@Autowired IZipCodeLookup zipCodeLookupService; 注释@Autowired IZipCodeLookup zipCodeLookupService; @Autowired OtherClass otherClass; ... 。 和任何Spring bean一样,它可以声明依赖注入 这是依赖注入:

PostConstruct

但是你当然可以声明你想要的依赖注入次数:

{{1}}

因此,只有当所有依赖关系被有效注入时,{{1}}才会被调用一次。

答案 1 :(得分:1)

您可以执行以下任一操作:

  1. @PostConstruct 方法中使用 @Autowired 对象,该方法在完成依赖项注入后执行,如上文davidxxx所述

  2. 在main()中使用Spring的 getBean()明确要求Spring框架在注入完成后返回对象:

    public static void main(String[] args) {
        ...
        ConfigurableApplicationContext appContext = SpringApplication.run(StartApplication.class, args);
        IZipCodeLookup service = appContext.getBean(IZipCodeLookup.class);
        ...
    }
    
  3. 使用Spring的 CommandLineRunner 组件(在main之后运行),它将负责自动装配对象:

    @Component
    public class MyRunner implements CommandLineRunner {
    
        @Autowired
        private IZipCodeLookup service;
    
        @Override
        public void run(String... args) throws Exception {
            ...
            service.doSomething();
            ... 
        }
    }
    
  4. 在您的主目录中实施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();
            ... 
        }
    }