提问者:小点点

如何使用来自main(String[]args)方法的自动添加(@自动添加)引用?


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

无法对非静态字段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);       
    }
}

有人能建议-当涉及主类时,如何或什么是使用自动装配的正确方法。

(因为将Autowed引用作为静态无论如何都不起作用)
AutowireVideMainClassApplication类中,更改为-

@Autowired
static IZipCodeLookup zipCodeLookupService;

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


共2个答案

匿名用户

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

>

  • 在@PostConstruct方法中使用@Autowed对象,该方法在依赖注入完成后执行,如上所述davidxxx

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

    public static void main(String[] args) {
        ...
        ConfigurableApplicationContext appContext = SpringApplication.run(StartApplication.class, args);
        IZipCodeLookup service = appContext.getBean(IZipCodeLookup.class);
        ...
    }
    

    使用Spring的Command dLineRunner组件(在main之后运行),它将负责自动装配您的对象:

    @Component
    public class MyRunner implements CommandLineRunner {
    
        @Autowired
        private IZipCodeLookup service;
    
        @Override
        public void run(String... args) throws Exception {
            ...
            service.doSomething();
            ... 
        }
    }
    

    在你的main中实现Spring的ApplicationRunner的run方法:

    @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();
            ... 
        }
    }
    

  • 匿名用户

    使用@SpringBootApplication注释的类不是经典bean。
    它从静态方法创建Spring上下文。
    但是自动装配的依赖关系不能是静态的。

    这就是为什么这个声明:

    city=zipCodeLookupService.retriveCityForZip(args[0]);
    

    当您将zipCodeLookupService声明为静态字段时,不会抛出Spring异常,而是抛出经典的NullPointerException

    在您的情况下,作为解决方法,您可以将使用Spring bean的处理移动到主类中的用javax. note.PostConstruct方法注释的实例方法中,并将传递给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的第一句总结了一般的预期行为。

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

    但是这句话

    “依赖注入完成后执行”

    确实是指:

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

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

    将其应用于您的案例应该会使事情更加清晰。
    AutowireWellMainClassApplication类被认为是Spring bean,因为@SpringBootApplication@Configuration注释,而它本身也用@Component注释。
    和任何Spring bean一样,它可以声明依赖注入。
    这是一个依赖注入:

    @Autowired
    IZipCodeLookup zipCodeLookupService;
    

    但是您当然可以声明任意数量的依赖注入:

    @Autowired
    IZipCodeLookup zipCodeLookupService;
    
    @Autowired
    OtherClass otherClass;
    
    ...
    

    因此,只有当所有依赖项都被有效注入时,PostConstruct才会被调用一次。