在独立的 Java 应用程序中使用 Spring 3 自动装配

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3659720/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 03:15:59  来源:igfitidea点击:

Using Spring 3 autowire in a standalone Java application

javaspringdependency-injectionmainautowired

提问by mike27

Here is my code:

这是我的代码:

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>

Why doesn't this work? I get NullPointerException. Is it possible to use autowiring in a standalone application?

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

采纳答案by Abhinav Sarkar

Spring works in standalone application. You are using the wrong way to create a spring bean. The correct way to do it like this:

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

In the first case (the one in the question), you are creating the object by yourself, rather than getting it from the Spring context. So Spring does not get a chance to Autowirethe dependencies (which causes the NullPointerException).

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

In the second case (the one in this answer), you get the bean from the Spring context and hence it is Spring managed and Spring takes care of autowiring.

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

回答by Jan Bodnar

Spring is moving away from XML files and uses annotations heavily. The following example is a simple standalone Spring application which uses annotation instead of XML files.

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

This is a simple bean. It is decorated with the @Componentannotation for auto-detection by Spring container.

这是一个简单的豆子。它@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());
    }
}

This is the main Applicationclass. The @ComponentScanannotation searches for components. The @Autowiredannotation injects the bean into the messagevariable. The AnnotationConfigApplicationContextis used to create the Spring application context.

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

My Standalone Spring tutorialshows how to create a standalone Spring application with both XML and annotations.

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

回答by Michail Michailidis

For Spring 4, using Spring Boot we can have the following example without using the anti-pattern of getting the Bean from the ApplicationContext directly:

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

Make sure that all your injected services are under com.yourprojector its subpackages.

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

回答by Frix G

A nice solution would be to do following,

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

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

Then you can use it like:

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

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

I found this very nice solution in the following website: https://confluence.jaytaala.com/pages/viewpage.action?pageId=18579463

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

回答by gerstams

I case you are running SpringBoot:

如果您正在运行 SpringBoot:

I just had the same problem, that I could not Autowire one of my services from the static main method.

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

See below an approach in case you are relying on SpringApplication.run:

如果您依赖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);
    }

}

I noticed that SpringApplication.run returns a context which can be used similar to the above described approaches. From there, it is exactly the same as above ;-)

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