【问题标题】:Using Spring 3 autowire in a standalone Java application在独立的 Java 应用程序中使用 Spring 3 自动装配
【发布时间】:2026-02-10 16:30:01
【问题描述】:

这是我的代码:

public class Main {

    public static void main(String[] args) {
        Main p = new Main();
        p.start(args);
    }

    @Autowired
    private MyBean myBean;
    private void start(String[] args) {
        ApplicationContext context = 
            new ClassPathXmlApplicationContext("META-INF/config.xml");
        System.out.println("my beans method: " + myBean.getStr());
    }
}

@Service 
public class MyBean {
    public String getStr() {
        return "string";
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 
    <context:annotation-config /> 
    <context:component-scan base-package="mypackage"/>
</beans>

为什么这不起作用?我得到NullPointerException。是否可以在独立应用程序中使用自动装配?

【问题讨论】:

标签: java spring dependency-injection main autowired


【解决方案1】:

如果你正在运行 SpringBoot:

我也遇到了同样的问题,我无法从静态 main 方法自动装配我的一项服务。

如果您依赖 SpringApplication.run,请参阅下面的方法:

@SpringBootApplication
public class PricingOnlineApplication {

    @Autowired
    OrchestratorService orchestratorService;

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(PricingOnlineApplication.class, args);
        PricingOnlineApplication application = context.getBean(PricingOnlineApplication.class);

        application.start();
    }

    private void start() {
        orchestratorService.performPricingRequest(null);
    }

}

我注意到 SpringApplication.run 返回一个上下文,可以使用类似于上述方法。从那里开始,它与上面完全相同;-)

【讨论】:

    【解决方案2】:

    一个不错的解决方案是进行以下操作,

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SpringContext implements ApplicationContextAware {
    
    private static ApplicationContext context;
    
    /**
     * Returns the Spring managed bean instance of the given class type if it exists.
     * Returns null otherwise.
     * @param beanClass
     * @return
     */
    public static <T extends Object> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
    
        // store ApplicationContext reference to access required beans later on
        SpringContext.context = context;
    }
    }
    

    然后你可以像这样使用它:

    YourClass yourClass = SpringContext.getBean(YourClass.class);
    

    我在以下网站找到了这个非常好的解决方案:https://confluence.jaytaala.com/pages/viewpage.action?pageId=18579463

    【讨论】:

      【解决方案3】:

      对于 Spring 4,使用 Spring Boot 我们可以有以下示例,而无需使用直接从 ApplicationContext 获取 Bean 的反模式:

      package com.yourproject;
      
      @SpringBootApplication
      public class TestBed implements CommandLineRunner {
      
          private MyService myService;
      
          @Autowired
          public TestBed(MyService myService){
              this.myService = myService;
          }
      
          public static void main(String... args) {
              SpringApplication.run(TestBed.class, args);
          }
      
          @Override
          public void run(String... strings) throws Exception {
              System.out.println("myService: " + MyService );
          }
      
      }
      
      @Service 
      public class MyService{
          public String getSomething() {
              return "something";
          }
      }
      

      确保所有注入的服务都在com.yourproject 或其子包下。

      【讨论】:

        【解决方案4】:

        Spring 正在远离 XML 文件并大量使用注释。以下示例是一个简单的独立 Spring 应用程序,它使用注释而不是 XML 文件。

        package com.zetcode.bean;
        
        import org.springframework.stereotype.Component;
        
        @Component
        public class Message {
        
           private String message = "Hello there!";
        
           public void setMessage(String message){
        
              this.message  = message;
           }
        
           public String getMessage(){
        
              return message;
           }
        }
        

        这是一个简单的 bean。它用@Component注解装饰,以便Spring容器自动检测。

        package com.zetcode.main;
        
        import com.zetcode.bean.Message;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.annotation.AnnotationConfigApplicationContext;
        import org.springframework.context.annotation.ComponentScan;
        
        @ComponentScan(basePackages = "com.zetcode")
        public class Application {
        
            public static void main(String[] args) {
        
                ApplicationContext context
                        = new AnnotationConfigApplicationContext(Application.class);
        
                Application p = context.getBean(Application.class);
                p.start();
            }
        
            @Autowired
            private Message message;
            private void start() {
                System.out.println("Message: " + message.getMessage());
            }
        }
        

        这是主要的Application 类。 @ComponentScan 注释搜索组件。 @Autowired 注释将 bean 注入到 message 变量中。 AnnotationConfigApplicationContext 用于创建 Spring 应用程序上下文。

        我的Standalone Spring tutorial 展示了如何使用 XML 和注释创建独立的 Spring 应用程序。

        【讨论】:

        • 此解决方案比 xml 解决方案要容易得多。非常适合我。
        • 我很好奇为什么需要自动装配然后从上下文中获取 bean。我认为我的回答解决了这个反模式
        • @MichailMichailidis 你有一个 Spring Boot 应用程序。这里我们处理一个经典的 Spring 应用程序。我们需要引导应用程序。
        • 谢谢@JanBodnar。我认为现在默认情况下所有应用程序都是 SpringBootApplications 或者扩展 CommandLineRunner 类似于您所描述的内容,或者以其他方式启动 Web 服务器
        【解决方案5】:

        Spring 在独立应用程序中工作。您使用错误的方法来创建弹簧豆。这样做的正确方法是:

        @Component
        public class Main {
        
            public static void main(String[] args) {
                ApplicationContext context = 
                    new ClassPathXmlApplicationContext("META-INF/config.xml");
        
                Main p = context.getBean(Main.class);
                p.start(args);
            }
        
            @Autowired
            private MyBean myBean;
            private void start(String[] args) {
                System.out.println("my beans method: " + myBean.getStr());
            }
        }
        
        @Service 
        public class MyBean {
            public String getStr() {
                return "string";
            }
        }
        

        在第一种情况下(问题中的那个),您是自己创建对象,而不是从 Spring 上下文中获取它。所以 Spring 没有机会获得 Autowire 依赖项(这会导致 NullPointerException)。

        在第二种情况下(此答案中的那个),您从 Spring 上下文中获取 bean,因此它由 Spring 管理,Spring 负责 autowiring

        【讨论】:

        • @Autowired 不是全押策略吗? spring 管理 all 对象创建无,但您不能将 @Autowired 添加到调用堆栈中的某些字段并使用 new ..() 实例化它们。
        • @Cojones,您可以自动装配一些 bean 并使用 new 创建其他 bean,否则您将如何调用 new ArrayList()?如果你有一个带有自动装配参数的类并且你用new 实例化它,那么自动装配将不会发生。
        • 您的 config.xml 中可能还需要这个:&lt;context:annotation-config /&gt; &lt;context:component-scan base-package="com.yourcompany.mycomponents" /&gt;
        • 不要忘记 Main 上面的 @Component 注解,否则你会得到一个 No qualifying bean of type [..] is defined 异常。我花了一些时间才弄清楚。
        • @TinusSky 即使我得到了 No qualifying bean of type..error
        最近更新 更多