在独立Java应用程序中使用Spring3Autowire

在独立Java应用程序中使用Spring3Autowire,java,spring,dependency-injection,main,autowired,Java,Spring,Dependency Injection,Main,Autowired,这是我的密码: 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

这是我的密码:

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



为什么这样不行?我得到
NullPointerException
。可以在独立应用程序中使用自动布线吗?

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

@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没有机会自动连接依赖项(这会导致
NullPointerException


在第二种情况下(本答案中的一种),您从Spring上下文获得bean,因此它是Spring管理的,Spring负责
自动连接

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());
    }
}
这是主
应用程序
类。
@ComponentScan
注释搜索组件。
@Autowired
注释将bean注入
消息
变量。注释ConfigApplicationContext用于创建Spring应用程序上下文


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

对于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
或其子包下。

一个好的解决方案是:

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

我在以下网站上找到了这个非常好的解决方案:

如果您正在运行SpringBoot:

我也遇到了同样的问题,我无法从静态main方法自动连接我的一个服务

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


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

努力使你的问题具有可读性。并向我们展示异常堆栈跟踪。我在这里维护了一个操作示例:@Autowired不是一个综合策略吗?要么spring管理所有的对象创建,要么一个都没有,但是您不能将@Autowired添加到调用堆栈中的某些字段并用new..()实例化它们。@Cojones,您可以自动连接一些bean并用new创建其他bean,否则您将如何调用
新ArrayList()
,例如?如果您有一个带有自动连接参数的类,并且您使用
new
实例化它,那么自动连接将不会发生。您可能也需要在config.xml中使用它:
不要忘记Main上面的@Component注释,否则您将得到类型为[…]的不合格bean定义为异常。我花了一些时间才弄明白。@TinusSky即使这样,我也没有得到类型为..error的合格bean。这个解决方案比xml解决方案简单得多。这对我来说非常有效。我很好奇为什么需要自动连线,然后从上下文中获取bean。。我想我的答案解决了这个问题antipattern@MichailMichailidis您有一个Spring启动应用程序。这里我们讨论一个经典的Spring应用程序。我们需要引导应用程序。谢谢@JanBodnar。我认为现在所有的应用程序默认都是SpringBoot应用程序,要么扩展类似于您描述的CommandLineRunner,要么启动web服务器
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);
@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);
    }

}