在独立的Java应用程序中使用Spring 3 autowire


72

这是我的代码:

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。在独立的应用程序中可以使用自动装配吗?


1
尽力使您的问题可读。并向我们​​显示异常堆栈跟踪。
skaffman 2010年

我在这里保持的操作实例:tshikatshikaaa.blogspot.com/2012/08/...
杰罗姆Verstrynge

Answers:


132

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

@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都不管理所有对象的创建,但是您不能将@Autowired添加到调用堆栈中的某些字段,并使用new ..()实例化它们。
Cojones 2011年

3
@Cojones,您可以自动连接某些bean,并使用new创建其他bean new ArrayList(),例如,如何调用?如果您有一个带有自动装配参数的类,并使用它实例化了该装配,new则自动装配将不会发生。
保罗

5
您可能还需要在config.xml中使用它:<context:annotation-config /> <context:component-scan base-package="com.yourcompany.mycomponents" />
Mikael Vandmo

2
不要忘记Main上方的@Component批注,否则您将获得[..]类型的未限定Bean定义为异常。花了我一些时间弄清楚。
TinusSky 2014年

1
@TinusSky即使我没有类型合格的bean..error
vaske

28

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注释注入豆成message变量。将AnnotationConfigApplicationContext用于创建Spring应用程序上下文。

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


该解决方案比xml解决方案容易得多。为我工作得很好。
凯尔·布​​莱恩斯汀

我很好奇为什么需要自动装配然后从上下文中获取bean。.我认为我的回答解决了这种反模式
Michail Michailidis

1
@MichailMichailidis您有一个Spring Boot应用程序。在这里,我们处理一个经典的Spring应用程序。我们需要引导应用程序。
Jan Bodnar

谢谢@JanBodnar。我认为现在默认情况下,所有应用程序都是SpringBootApplications,要么扩展类似于您所描述的CommandLineRunner,要么启动Web服务器
Michail Michailidis

11

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


2

如果您正在运行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返回一个上下文,可以使用与上述方法类似的上下文。从那里,它与上面的完全相同;-)


0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.