Best practice to use #Configuration Bean in another #Configuration class - java

I have to work with existing library of my company which has bunch of #Bean packaged in #Configuration in Spring project but would be added as dependency for my project. The situation would be similar to
#Configuration
Class A{
#Bean
B b(){
return new B()
}
}
#Configuration
Class C{
#Bean
D d(){
D d = new D();
//TODO: How do I use instance of B here
d.someConfiguration(B b);
return d;
}
}
Should I initialized A using new operator in C and call method b or should I #Autowire B in C directly.

There are multiple ways you can do this
By field Autowiring
#Configuration
Class C{
#Autowire
private B b;
#Bean
D d(){
D d = new D();
//TODO: How do I use instance of B here
d.someConfiguration(B b);
return d;
}
}
By constructor Autowiring (Personally i prefer using constructor Autowiring which will be help during test cases)
#Configuration
Class C{
private B b;
#Autowire
public C(B b){
this.b=b;
}
#Bean
D d(){
D d = new D();
//TODO: How do I use instance of B here
d.someConfiguration(B b);
return d;
}
}
Or you can just add it as method arguments spring will resolve it
#Configuration
Class C{
#Bean
D d(B b){
D d = new D();
//TODO: How do I use instance of B here
d.someConfiguration(B b);
return d;
}
}

When you include the library sa a dependency, then when springboot initializes it scans the #Configuration files in those libraries as well. So the beans declared in those are already available in spring context.
So what you can do is just include it as a method parameter
#Configuration
Class C{
#Bean
D d(B b){
D d = new D();
d.someConfiguration(b);
return d;
}
}
As soon as spring see that you want a bean if type B it will search and give u an instance.
I would say its evil to use new in spring :)

Related

Spring inject interface implementation

I'd like to use lombok to inject a class implemented from a interface like below:
#RequiredArgsConstructor(onConstructor = #_(#Inject))
public class className {
#NonNull
private final ClassA1 a1 implements ClassA;
...
}
But obviously this is not working, so what's the correct way to do this?
=================
edit:
Or should I do this way?
public class className {
private ClassA a1;
public className(A1 a1) {
this.a1 = a1; }
}
===================
Here's the code after taking advice from Mykhailo Moskura:
#Component
#RequiredArgsConstructor(onConstructor = #_(#Inject))
public class C {
#NonNull
private A b;
public someFunction() {
b.method();
}
}
Here A is the interface, while b is Class implementing A with camelcase name. And using lombok I injected b, and now call some method of b in some function. However I realized b.method still points to the interface A, but not B.
#NonNull is not required
Lombok will generate a constructor with fields that are marked as final or #NonNull
You can autowire just declaring the interface type
and giving the implementation class name in camel case starting from lower case.
Also you need to declare your implementation as bran and the class in which you are injecting it too.
#Inject is java ee CDI dependency.
#Autowired is spring specific.
Spring supports both but it says to use #Autowired
Here is an example:
public interface A{
}
#Component
public class B implements A{
}
#Component
public class C {
private A a;
#Autowired
public C(A a){
this.a = a;
}
}
Lombok sample:
#RequiredArgsConstructor
#Component
public class C {
//Here it will inject the implementation of A interface with name of implementation (As we have name of impl B we declare field as b , if HelloBeanImpl then helloBeanImpl
private A b;
}
But if you have many implementations of one interface you can use #Qualifier with name of bean or the above sample with lombok where A b where b is the name of implementation

Injection of beans in Spring

I am a newbie in Spring Framework and I came across the below POJO beans:
#Component
Class A{
#Autowired
B b;
}
#Component
Class B{
// primitive variables
}
My doubt is what will be the order of initialisation and injection of beans?
Will it be:
Instance of A is created(Constructor is called of A)
Instance of B is created(Constructor is called of B)
B is injected into A
OR
Instance of B is created(Constructor is called of B)
Instance of A is created(Constructor is called of A)
B is injected into A

Usage of #Bean annotation

Suppose I have the following Spring context configuration:
#Configuration
public class Configuration {
#Bean
public A a() {
return new A(b());
}
public B b() {
return new B();
}
}
Should one annotate b() with #Bean if the only place where B instance needed is within a() for A instance construction?
If B is a plan Java class (no Spring annotations) then no, You can use current configuration. As this is a private member of A class.
But if you have methods that need to be managed by spring (inside B class), like #PostConstruct or #PreDestroy, than you should make a Bean out of B class:
#Bean
public A a(B b) {
return new A(b);
}
#Bean
public B b() {
return new B();
}
Such cases are:
resource to be closed on shutdown/close
executors to be closed on shutdown
jdbc connections
etc

Can instantiate object of class in which a bean is autowired

There are two classes class A and class B. class B is spring bean and autowired in class A. Class A is not spring bean.
public class A {
int a,c;
public A(int a, int c ){
this.a = a;
this.c = c;
}
#Autowired
B b
// some logic
}
class C {
// Can object will be created
A obj = new A(10,12);
}
if code will compile what will happen I mean object of B will be created.
Object of class B will be created at application start-up, but will not be injected into instance of A, since it's not a spring managed bean.

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

Categories