Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Injection - access to the injected object within a constructor

I have a resource (Spring bean) which has some of its fields injected by Spring, for example:

@Repository(value="appDao")
public class AppDaoImpl implements AppDao {
   @PersistenceContext
   EntityManager entityManager;

   public Resource() {
      ... use entityManager ... // doesn't work
   }
}

I know that I can't access the injected entityManager in the constructor and should use a @PostConstruct annotation on a different method. But what are the reasons for this?

like image 737
John Manak Avatar asked Nov 09 '10 14:11

John Manak


People also ask

What is the limitation of constructor injection in Spring?

Constructor injection (from the definition) does not allow you to create circular dependencies between beans. This limitation is actually an advantage of constructor injection - Spring can resolve circular dependencies when setter injection is used without you even noticing.

Can we use both constructor and setter injection?

If we use both constructor and setter injection, IOC container will use the setter injection. Changes: We can easily change the value by setter injection. It doesn't create a new bean instance always like constructor. So setter injection is flexible than constructor injection.

What does @inject do with constructor?

Injectable constructors are annotated with @Inject and accept zero or more dependencies as arguments. @Inject can apply to at most one constructor per class. @Inject is optional for public, no-argument constructors when no other constructors are present. This enables injectors to invoke default constructors.

How constructor injection works in Spring?

Constructor Based Dependency Injection. It is a type of Spring Dependency Injection, where object's constructor is used to inject dependencies. This type of injection is safer as the objects won't get created if the dependencies aren't available or dependencies cannot be resolved.


2 Answers

Because Spring can't access any fields or methods before the object is created (which is done through the constructor). So Spring instantiates the object using the constructor and then injects the properties.

The only way around this is to use Constructor Injection (which can be cumbersome if you have multiple dependencies). I think what you should do is move your code out of the constructor and into an initialization method using the @PostConstruct annotation:

@PostConstruct
public void init(){
    // do stuff with entitymanager here
}
like image 149
Sean Patrick Floyd Avatar answered Oct 21 '22 10:10

Sean Patrick Floyd


The reason is in the lifecycle of the bean:

  • The container (spring application context) instantiates the object
  • then it sets all the dependencies (incl. the entityManager in your example)
  • after all dependencies have been set, it invokes the @PostConstruct method, if any.

Spring (and no one) can set fields to an object before actually constructing that object.

You can use constructor-injection - passing the dependencies to a non-default constructor, but it is not possible with @PersistenceContext

like image 20
Bozho Avatar answered Oct 21 '22 10:10

Bozho