spring bean dependency injection - java

I have this class (that looks like this, pseudo-code wise):
#Component
public class classA() {
private variable a;
public A() {
}
#Autowired
public classA(variable a) {
this.a = a;
}
}
Basically, the variable "a" that I want to inject is a spring bean from a configuration file defined elsewhere (at run-time)
Is this the correct way to go about defining the class so that "a" gets injected from the configuration file at run-time? I was wondering how this would work if we also have a no-args constructor?
IE: If I create an instance of classA using the no-args constructor, will "a" still be properly injected?

Related

Spring: Choosing constructor while Autowiring a Component

I've a Component as follows:
#Component
class A(){
private s;
public A(){}
public A(String s){this.s=s;}
}
Here is the other class Where I'm auto wiring the above class:
#Component
class B(){
#Autowire
private A a;
}
In the above autowiring, I need to use the parameterized constructor. How can I pass the constructor args?
You can't, at least not via #Autowired in B but there are other ways to do it:
Wire the parameter into A's constructor:
One constructor is annotated with #Autowired because:
As of Spring Framework 4.3, the #Autowired constructor is no longer
necessary if the target bean only defines one constructor. If several
constructors are available, at least one must be annotated to teach
the container which one it has to use.
#Component
class A(){
private s;
public A(){}
#Autowired
public A(#Value("${myval}") String s){this.s=s;}
}
Expose A as a #Bean
Straight from the docs:
#Configuration
public class AppConfig {
#Bean
public A a(#Value("${myval}") String s) {
return new A(s);
}
}
Construct A in B using an initialization callback
Docs
#Component
class B(){
private A a;
#Value("${myval}")
private String myval;
#PostConstruct
private void init()
{
a = new A(myval);
}
}
There is a concept of prototype bean which I think you require in your case. #Component will create a singleton bean and changing it in one place will change in all parent classes where this was injected.
You need to understand how to inject a prototype bean in singleton bean.
Follow this example
https://stackoverflow.com/a/25165971/949912
Just use setters instead of constructor.
If you want to create object by yourself with new keyword then this object will not be managed by container.

Autowire Bean with constructor parameters

I've got a bean with constructor parameters which I want to autowire into another bean using annotations. If I define the bean in the main config and pass in the constructor parameters there then it works fine. However, I have no main config but use #Component along with #ComponentScan to register the beans. I've tried using #Value property to define the parameters but then I get the exception No default constructor found;
#Component
public class Bean {
private String a;
private String b;
public Bean(#Value("a") String a, #Value("b") String b)
{
this.a = a;
this.b = b;
}
public void print()
{
System.out.println("printing");
}
}
#Component
public class SecondBean {
private Bean bean;
#Autowired
public SecondBean(Bean bean)
{
this.bean = bean;
}
public void callPrint()
{
bean.print();
}
}
The constructor for Bean needs to be annotated with #Autowired or #Inject, otherwise Spring will try to construct it using the default constructor and you don't have one of those.
The documentation for #Autowired says that it is used to mark a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities. In this case you need to tell Spring that the appropriate constructor to use for autowiring the dependency is not the default constructor. In this case you're asking Spring to create SecondBean instance, and to do that it needs to create a Bean instance. In the absence of an annotated constructor, Spring will attempt to use a default constructor.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html

Is there any way to inject a dependency so that it can be used in the constructor?

I have object A
#Component("a")
Class A{
public SomeObject getC(){
return anObject;
}
}
that I want to use in the construction of another object B like so
#Service("b")
Class B{
#Autowired
#Qualifier("a")
A a;
SomeObject c;
public B(){
c = a.getC();
}
Where a is a connector to a database. Basically I want to load object c from the database upon initialization and still be able to get updates to the database afterwards. The problem is I tried doing this and I get the following initialization error.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name defined in file
Instantiation of bean failed;
Could not instantiate bean class
Constructor threw exception; nested exception is java.lang.NullPointerException
Is this even possible since the dependency must be injected before the object B has been constructed, or how would I do this?
There are two solutions to your problem. You can in fact use constructor injection with Spring, but you might instead want to use a method annotated #PostConstruct. It'll get executed after all of the necessary injections have happened but before the bean is put into service (e.g., by being made available to another bean or to a servlet), and you can execute any code you like there with the knowledge that the bean is in a valid constructed state.
#Service("b")
class B {
#Autowired
#Qualifier("a")
A a;
SomeObject c;
public B(){}
#PostConstruct
private void initializeSomeObject() {
c = a.getSomeObject();
}
}
Beans are created first and then its dependencies are injected, that's why you're getting the NullPointerException. Try this:
#Service("b")
Class B{
A a;
SomeObject c;
#Autowired
#Qualifier("a")
public B(A a){
this.a = a;
c = a.getC();
}
}

Spring autowire / Java

If I have two classes like:
Class A {
public String importantValue = "stringvalue";
#Autowire
public B b;
}
#Component
#Scope("prototype");
Class B {
// This should be set automatically
// from IOC Container upon injection.
public String importantValueFromA;
}
Is this even possible? As soon as B class has been injected to A it should automatically set the value in B.
Do you want class A to do some setup on injected class B? That's simple:
#Service
class A {
private String importantValue = "stringvalue";
#Autowire
private B b;
#PostConstruct
public void initB() {
b.importantValueFromA = this.importantValue;
}
}
Obviously you cannot access b.importantValueFromA in A.A constructor because injection didn't yet happen. But #PostConstruct callback is guaranteed to be called after injection.
Another approach is to use setter injection, but it feels kind of hacky:
private B b;
#Autowire
public void setB(B b) {
this.b = b;
b.importantValueFromA = this.importantValue;
}
Two suggestions:
keep your fields private and use setters/methods to access them.
injecting prototype scoped bean to singleton bean might have some unexpected results. Enough to say only one instance of B will be created.
No. B is created before A (since A depends on B) so it will not update the value itself. You have to use a contructor injection:
Class A {
public String importantValue = "stringvalue";
#Autowire
public A(B b) {
b.importantValueFromA = this.importantValue;
}
}
How about doing something like this:
Declare your class B as a scoped proxy, which underlying will expose a proxy to A instead of the real B and will respect the prototype scope.
#Component
#Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
class B {
Then you can inject in an attribute of A in B this way:
#Value("#{a.importantValue}")
private String importantValueFromA;
Here is a full working example in a gist:
https://gist.github.com/3395329

Circular dependency in Spring

How does Spring resolve this: bean A is dependent on bean B, and bean B on bean A.
The Spring reference manual explains how circular dependencies are resolved. The beans are instantiated first, then injected into each other.
Consider this class:
package mypackage;
public class A {
public A() {
System.out.println("Creating instance of A");
}
private B b;
public void setB(B b) {
System.out.println("Setting property b of A instance");
this.b = b;
}
}
And a similar class B:
package mypackage;
public class B {
public B() {
System.out.println("Creating instance of B");
}
private A a;
public void setA(A a) {
System.out.println("Setting property a of B instance");
this.a = a;
}
}
If you then had this configuration file:
<bean id="a" class="mypackage.A">
<property name="b" ref="b" />
</bean>
<bean id="b" class="mypackage.B">
<property name="a" ref="a" />
</bean>
You would see the following output when creating a context using this configuration:
Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance
Note that when a is injected into b, a is not yet fully initialised.
As the other answers have said, Spring just takes care of it, creating the beans and injecting them as required.
One of the consequences is that bean injection / property setting might occur in a different order to what your XML wiring files would seem to imply. So you need to be careful that your property setters don't do initialization that relies on other setters already having been called. The way to deal with this is to declare beans as implementing the InitializingBean interface. This requires you to implement the afterPropertiesSet() method, and this is where you do the critical initialization. (I would also include code to check that important properties have actually been set.)
In the codebase I'm working with (1 million + lines of code) we had a problem with long startup times, around 60 seconds. We were getting 12000+ FactoryBeanNotInitializedException.
What I did was set a conditional breakpoint in AbstractBeanFactory#doGetBean
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
where it does destroySingleton(beanName) I printed the exception with conditional breakpoint code:
System.out.println(ex);
return false;
Apparently this happens when FactoryBeans are involved in a cyclic dependency graph. We solved it by implementing ApplicationContextAware and InitializingBean and manually injecting the beans.
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class A implements ApplicationContextAware, InitializingBean{
private B cyclicDepenency;
private ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
ctx = applicationContext;
}
#Override
public void afterPropertiesSet() throws Exception {
cyclicDepenency = ctx.getBean(B.class);
}
public void useCyclicDependency()
{
cyclicDepenency.doSomething();
}
}
This cut down the startup time to around 15 secs.
So don't always assume that spring can be good at solving these references for you.
For this reason I'd recommend disabling cyclic dependency resolution with AbstractRefreshableApplicationContext#setAllowCircularReferences(false) to prevent many future problems.
Problem ->
Class A {
private final B b; // must initialize in ctor/instance block
public A(B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
// Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'A': Requested bean is currently in creation: Is there an unresolvable circular reference?
Solution 1 ->
Class A {
private B b;
public A( ) { };
//getter-setter for B b
}
Class B {
private A a;
public B( ) { };
//getter-setter for A a
}
Solution 2 ->
Class A {
private final B b; // must initialize in ctor/instance block
public A(#Lazy B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
It just does it. It instantiates a and b, and injects each one into the other (using their setter methods).
What's the problem?
Say A depends on B, then Spring will first instantiate A, then B, then set properties for B, then set B into A.
But what if B also depends on A?
My understanding is: Spring just found that A has been constructed (constructor executed), but not fully initialized (not all injections done), well, it thought, it's OK, it's tolerable that A is not fully initialized, just set this not-fully-initialized A instances into B for now. After B is fully initialized, it was set into A, and finally, A was fully initiated now.
In other words, it just expose A to B in advance.
For dependencies via constructor, Sprint just throw BeanCurrentlyInCreationException, to resolve this exception, set lazy-init to true for the bean which depends on others via constructor-arg way.
Circular dependency in Spring : Dependency of one Bean to other. Bean A → Bean B → Bean A
Solutions:
Use #Lazy Annotation
Redesign you class dependency
Use Setter/Field Injection
Use #PostConstruct Annotation
From the Spring Reference:
You can generally trust Spring to do
the right thing. It detects
configuration problems, such as
references to non-existent beans and
circular dependencies, at container
load-time. Spring sets properties and
resolves dependencies as late as
possible, when the bean is actually
created.
The Spring container is able to resolve Setter-based circular dependencies but gives a runtime exception BeanCurrentlyInCreationException in case of Constructor-based circular dependencies.
In case of Setter-based circular dependency, the IOC container handles it differently from a typical scenario wherein it would fully configure the collaborating bean before injecting it.
For eg., if Bean A has a dependency on Bean B and Bean B on Bean C, the container fully initializes C before injecting it to B and once B is fully initialized it is injected to A. But in case of circular dependency, one of the beans is injected to the other before it is fully initialized.
Its clearly explained here. Thanks to Eugen Paraschiv.
Circular dependency is a design smell, either fix it or use #Lazy for the dependency which causes problem to workaround it.
If you generally use constructor-injection and don't want to switch to property-injection then Spring's lookup-method-injection will let one bean lazily lookup the other and hence workaround the cyclic dependency. See here: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
Constructor Injection fails when there is Circular Dependency between spring beans. So in this case we Setter injection helps to resolve the issue.
Basically, Constructor Injection is useful for Mandatory dependencies, for optional dependencies better to use Setter injection because we can do re-injection.
If two beans are dependent on each other then we should not use Constructor injection in both the bean definitions. Instead we have to use setter injection in any one of the beans. (of course we can use setter injection n both the bean definitions, but constructor injections in both throw 'BeanCurrentlyInCreationException'
Refer Spring doc at "https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource"
Also we use #Lazy Annotation
#Component
public class ClassA {
private ClassB classB;
public ClassB getClassB() {
return classB;
}
#Lazy
#Autowired
public void setClassB(ClassB classB) {
this.classB = classB;
}
}
#Component
public class ClassB {
private ClassA classA;
#Autowired
public ClassB(ClassA classA) {
super();
this.classA = classA;
}
public ClassA getClassA() {
return classA;
}
public void setClassA(ClassA classA) {
this.classA = classA;
}
}

Categories