Using Spring 3 autowire in a standalone Java application

102,215

Solution 1

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

@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 Autowire the dependencies (which causes the 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.

Solution 2

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.

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 @Component annotation for auto-detection by Spring container.

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 Application class. The @ComponentScan annotation searches for components. The @Autowired annotation injects the bean into the message variable. The AnnotationConfigApplicationContext is used to create the Spring application context.

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

Solution 3

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:

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.yourproject or its subpackages.

Solution 4

I case you are running SpringBoot:

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

See below an approach in case you are relying on 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 ;-)

Share:
102,215
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin over 1 year

    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?

  • Cojones
    Cojones over 12 years
    Isn't @Autowired an all-in strategy? Either spring manages all the object creation none, but you can't add @Autowired to some fields in your callstack and instantiate them with new ..().
  • Cojones
    Cojones over 12 years
    If only one single object in your callstack is instantiated with new ..() it won't work right?
  • Paul
    Paul over 12 years
    @Cojones, you can autowire some beans and create others with new, otherwise how would you ever be able to call new ArrayList(), for example? If you have a class with autowired parameters and you instantiate it with new then the autowiring won't take place.
  • Mikael Vandmo
    Mikael Vandmo over 10 years
    You might need this in your config.xml also:<context:annotation-config /> <context:component-scan base-package="com.yourcompany.mycomponents" />
  • TinusSky
    TinusSky over 9 years
    Don't forget the @Component annotation above Main, otherwise you'll get a No qualifying bean of type [..] is defined exception. Took me some time to figure out.
  • vaske
    vaske over 7 years
    @TinusSky even with that I got No qualifying bean of type..error
  • naXa stands with Ukraine
    naXa stands with Ukraine over 6 years
    I get org.springframework.beans.factory.NoSuchBeanDefinitionExcept‌​ion: No qualifying bean of type [Main] is defined =(
  • Kyle Bridenstine
    Kyle Bridenstine over 5 years
    This solution is much much easier than the xml solutions. Worked for me really well.
  • Michail Michailidis
    Michail Michailidis over 4 years
    I am curious why it is needed to autowire and then get the bean from the context.. I think my answer resolves this antipattern
  • Jan Bodnar
    Jan Bodnar over 4 years
    @MichailMichailidis You have a Spring Boot application. Here we deal with a classic Spring application. We need to bootstrap the application.
  • Michail Michailidis
    Michail Michailidis over 4 years
    Thank you @JanBodnar. I thought all apps now by default are SpringBootApplications either extending CommandLineRunner resembling what you are describing or otherwise starting a web server