Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Autowired and @Value on property not working

I would like to use @Value on a property but I always get 0(on int).
But on a constructor parameter it works.

Example:

@Component
public class FtpServer {

    @Value("${ftp.port}")
    private int port;

    public FtpServer(@Value("${ftp.port}") int port) {
        System.out.println(port); // 21, loaded from the application.properties.
        System.out.println(this.port); // 0???
    }
}

The object is spring managed, else the constructor parameter wouldn't work.

Does anyone know what causes this weird behaviour?

like image 906
Jan Wytze Avatar asked Sep 04 '17 11:09

Jan Wytze


People also ask

What is @AutoWired annotation in spring spring?

Spring @Autowired Annotation. The @Autowired annotation provides more fine-grained control over where and how autowiring should be accomplished. The @Autowired annotation can be used to autowire bean on the setter method just like @Required annotation, constructor, a property or methods with arbitrary names and/or multiple arguments.

What are @AutoWired instance variables in spring?

They are known in the Spring context and can be used for injection. When a constructor of a class is called, the @Autowired instance variables do not contain their values yet. If you are dependent on them for the execution of specific logic, I suggest you use the @PostConstruct annotation.

Why is @AutoWired not working in Spring Boot?

When @Autowired doesn’t work There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.

Can a field with @AutoWired have @component at its class definition?

Suppose, we have applied @Autowired annotation at field which is a user defined class reference. Now, if we also apply @Component to that class then it will always be initialized with null. So, a field with @Autowired should not have @Component at its class definition. By default @Autowired is byType. Address bean is autowired at Student class.


2 Answers

Field injection is done after objects are constructed since obviously the container cannot set a property of something which doesn't exist. The field will be always unset in the constructor.

If you want to print the injected value (or do some real initialization :)), you can use a method annotated with @PostConstruct, which will be executed after the injection process.

@Component
public class FtpServer {

    @Value("${ftp.port}")
    private int port;

    @PostConstruct
    public void init() {
        System.out.println(this.port);
    }

}
like image 174
Daniel Olszewski Avatar answered Sep 18 '22 12:09

Daniel Olszewski


I think the problem is caused because Spring's order of execution:

  • Firstly, Spring calls the constructor to create an instance, something like:

    FtpServer ftpServer=new FtpServer(<value>);

  • after that, by reflection, the attribute is filled:

    code equivalent to ftpServer.setPort(<value>)

So during the constructor execution the attribute is still 0 because that's the default value of an int.

like image 44
Pablo Lozano Avatar answered Sep 20 '22 12:09

Pablo Lozano