-1

I've seen all the questions about spring autowired configurations being null and I can't seem to figure it out. So I condensed it into a small problem in the hopes someone can help.

Spring application Hello.java

package hello;

@SpringBootApplication
public class Hello {
  private static final Logger log = LoggerFactory.getLogger(Hello.class);

  @Autowired
  private AppConfig appConfig;

  public void start() {
    log.info("Start");
    log.info("AppConfig: {}", appConfig);
  }

  public static void main(String args[]) {
    SpringApplication.run(Hello.class, args).close();
  }

  @Bean
  public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
    return args -> {
      Hello hello = new Hello();
      hello.start();
    };
  }
}

AppConfig.java

package hello;

@Configuration
public class AppConfig {

  @Value("${string.test:bob}")
  private String commandLineArg;

  public String getCommandLineArg() {
    return commandLineArg;
  }
}

Running this works! However it logs null for the appConfig variable. From my perspective, it should have been automatically instantiated and filled in. What's going on?

brent
  • 1,709
  • 2
  • 13
  • 15

3 Answers3

3

In your CommandLineRunner bean you are creating a new instance of Hello and call start on it. Your hello instance is not a Spring bean, so naturally no dependencies would be injected. To get it working simply invoke start() in your CommandLineRunner bean, CommandLineRunners are run after application context is populated and ready:

@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
    return args -> start();
}

Alternatively, you could add @PostConstruct on your start() method to be run after your bean is populated in Spring application context:

    @PostConstruct
    public void start() {
        log.info("Start");
        log.info("AppConfig: {}", appConfig);
    }
Nima Ajdari
  • 2,754
  • 2
  • 14
  • 18
1

In your commandLineRunner you instantiate "Hello" yourself (new Hello()), so your "hello" Object is not a managed Bean by Spring, so it will have no Dependency Injection at all.

Is there any special reason why you do this? Spring will via @SpringBootApplication-Annotation instantiate Hello already for you. In your CommandLineRunner just call "start()" and you will have your Dependencies autowired:

@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
    return args -> {
        start();
    };
}

If your CommandLineRunner is beeing run from another Class, you can get your Spring-managed "Hello"-Instance via:

@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
    return args -> {
        Hello foo = ctx.getBean(Hello.class);
        foo.start();
    };
}
andreas
  • 955
  • 7
  • 15
1
Hello hello = new Hello(); // Creates new Hello instance, not managed by Spring container

Use instead :

package com.example.demo;

import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

}

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {

    @Autowired
    AppConfig appConfig;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);

    }

    public void start() {
        System.out.println("Start");
        System.out.println("AppConfig: {}" + appConfig);
    }

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {
            this.start();
        };
    }
}

Output :


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2019-04-14 12:22:49.515  INFO 7892 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on sparrow with PID 7892 (/home/anant/Downloads/demo/target/classes started by anant in /home/anant/Downloads/demo)
2019-04-14 12:22:49.519  INFO 7892 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2019-04-14 12:22:50.446  INFO 7892 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.383 seconds (JVM running for 1.875)
Start
AppConfig: {}com.example.demo.AppConfig$$EnhancerBySpringCGLIB$$9ca35f67@68f1b17f

Anant Goswami
  • 318
  • 3
  • 14