Wiring conditional bean in other bean with contructor injection - java

Please go through complete question before marking duplicate. Can discuss more in comments
I have following code where ServiceA depends on ServiceB. And serviceB implementation bean will be conditionally initialized
class ServiceA{
ServiceB serviceB;
ServiceA(ServiceB serviceB){
this.serviceB = serviceB;
}
}
#Configuration
class AppConfig{
#Conditional("some_condition_based_on_property")
#Bean
ServiceB serviceB1(){
return new ServiceBImpl1();
}
#Conditional("some_condition_based_on_property")
#Bean
ServiceB serviceB2(){
return new ServiceBImpl2();
}
#Bean
ServiceA serviceA(){
//what should go here so that conditional bean is injected in ServiceA
}
}
I cannot auto-detect ServiceA bean, as I need to inject it in a Map with some key.
One option I see is to remove construction injection, and have serviceB bean #autowired in serviceA, which would be last option for me. Any other option?
Edit: I don't want to have if-else during injection, as the beans can be defined at various places. I will be only using #Conditional

Nothing holds you from autowiring the resulting ServiceB right inside the configuration class and reusing the reference it for creating ServiceA:
#Configuration
class AppConfig{
#Conditional(/* some condition */)
#Bean
ServiceB serviceB1(){
return new ServiceBImpl1();
}
#Conditional(/* some condition */)
#Bean
ServiceB serviceB2(){
return new ServiceBImpl2();
}
// store a local reference
#Autowired
private dynamicServiceB;
#Bean
ServiceA serviceA(){
return new ServiceA(dynamicServiceB);
}
}
However, it feels like you're trying to work around some other problem that you didn't describe, especially given you included syntactically incorrect code: #Conditional doesn't accept strings as values. You should not expect that constraining acceptable solutions to those working with a broken bit of code you have will yield much success.
This feels like a scenario for a #Profile.

Related

Spring profile annotation multiple beans

Let's say I have a library (I cannot change it). There is a class Consumer that uses a spring component of class A.
#Component
public class Consumer{
#Autowired
private A a;
}
In my configuration class I want to define two beans of same class A depending on the profile.
#Configuration
public class Config {
#Bean
#Profile("!dev")
A a1(){
return new A();
}
#Bean
#Profile("dev")
A a2(){
return new A();
}
}
But when I start the app, I get next exception
Parameter 1 of constructor in sample.Consumer required a single bean, but 2 were found:
I can't get how to fix that. I've tried to create 2 separate configs for that with profile annotation and single bean there, but it also did not work.
Marking one bean #Primary also does not help.
Do you guys know how to fix that? Thanks!
UPD.
Let me make it more specific. That class is a part of dynamodb spring starter. Consumer - DynamoDBMapperFactory. My bean - DynamoDBMapperConfig. So I want to have 2 versions of DynamoDBMapperConfig in my app.
You need to stop scanning package where Consumer declared.
#Profile behaves differently if it's applied to the #Bean annotated method.
From Profile doc.:
Use distinct Java method names pointing to the same bean name if you'd like to define alternative beans with different profile conditions
This means, you should do:
#Configuration
public class Config {
#Bean("a")
#Profile("!dev")
A a1(){
return new A();
}
#Bean("a")
#Profile("dev")
A a2(){
return new A();
}
}
Note the same bean names.

Spring dependency injection #Autowired VS dependency injection of an object without #Autowired

what is the main difference between injecting objects with #Autowired and injecting without it ?
I know that spring will initialize the bean , but what it is really offering ?
There are several ways to configure Spring beans and inject dependencies using Spring. One way is by using constructor injection, where the constructor of your Spring bean has arguments which are the dependencies that should be injected:
#Component
public class MyBean {
private final SomeDependency something;
#Autowired
public MyBean(SomeDependency something) {
this.something = something;
}
}
However, since Spring 4.3, it is not necessary anymore to use #Autowired on such a constructor (click link for Spring documentation). So you can write it without the #Autowired:
#Component
public class MyBean {
private final SomeDependency something;
public MyBean(SomeDependency something) {
this.something = something;
}
}
This will work exactly the same as the code above - Spring will automatically understand that you want the dependency to be injected via the constructor. The fact that you can leave out #Autowired is just for convenience.
So, to answer your question: there is no difference.
#Autowired (so the injection) in some situation cannot be used, an example is if your autowired bean not ready because of some async stuff but in the target bean you want to use that.
So in this situation do not use inject (#Autowired) it is better to inject the ApplicationContext and in the exact moment get your bean from there by name or by class (there is a lot off possibilities there).
You can consider the #Autowired with the #Lazy annotation too.

Is #Configuration a singleton

I was doing my daily staff and I've realized despite I use #Configuration oftenly I don't know how it works exactly, after reading the spring.io documentations I can't tell for sure if #Configuration is a way of making a class a singleton.
So.... I guess my question is:
What should I use to proper make a singleton #Configuration or #Component? and why's that'?
I've been investigating about this 2 options with 2 examples like this:
1st example
#Configuration
public static class Config {
#Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
#Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
2nd example
#Component
public static class Config {
#Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
#Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
The first piece of code works fine, and as expected, SimpleBeanConsumer will get a link to singleton SimpleBean. But unfortunately, it doesn’t work in a signed enviroment.
The second configuration is totally incorrect because spring will create a singleton bean of SimpleBean, but SimpleBeanConsumer will obtain another instance of SimpleBean which is out of the spring context control.
The reason for this behaviour can be explained as follows:
If you use #Configuration, all methods marked as #Bean will be wrapped into a CGLIB wrapper which works as if it’s the first call of this method, then the original method’s body will be executed and the resulting object will be registered in the spring context. All further calls just return the bean retrieved from the context.
So I guess I've answered my own question but not sure if I'm missing something.

How to get a spring bean in a bean-defining method

I have a java config where ServiceB depends on ServiceA:
#Bean
ServiceA getServiceA() { return new ServiceA(); }
#Bean
ServiceB getServiceB() { return new ServiceB(getServiceA()); }
Then I want to declare ServiceA (but no ServiceB) as a component. I add #ScanPackage to config and annotate ServiceA:
#Component
class ServiceA { .. }
How to declare method getServiceB() now?
Spring auto-injects method parameters by type for Bean defining methods:
#Bean
ServiceB getServiceB(ServiceA serviceA) {
return new ServiceB(serviceA);
}
Now you don't have to worry about how ServiceA is provided.
As Rohan already wrote in his answer, Spring's #Bean annotation can inject dependencies of other Spring beans, in the same manner as constructor-based dependency injection does.
I would just add that there are also other possibilities to do dependency injection, when defining a bean in java config. #Configuration annotated class is a Spring bean as any other Spring bean, so you can auto-wire a dependency, as is usually done in Spring and then use this dependency when defining your #Bean, like:
#Autowired
private ServiceA serviceA;
#Bean
public ServiceB getServiceB() {
return new ServiceB(serviceA);
}
Since Spring Framework 4.3, you are also able to do constructor injection in #Configuration classes - which is yet another way to inject dependencies.
See more details in spring documentation.

#Autowired bean property is null in #Configuration bean

I have a problem with #Autowired property in #Configuration bean.
I have a bean similar to the one below:
#Configuration
public class MyConfig {
#Autowired MongoTemplate mongoTemplate;
#Bean
MongoDbMetadataStore indexMetadataStore() {
return new MongoDbMetadataStore(mongoTemplate, "index");
}
}
and ... mongoTemplate is null while creating indexMetadataStore bean (checked with debugger). Unfortunately I cannot provide entire project structure, it is large (it has ~5 XML config files and around 20-30 #Configuration beans) and my bet is that there could a circular reference or something of sort.
However, this mongoTemplate bean is created earlier and injected to other beans (also checked with debugger), so at this point mongoTemplate is fully created and I cannot understand why it is not injected and left null.
Any ideas where I should look?
Ok, I found out a problem. I will describe it here, so that perhaps someone else may find this answer useful and save precious time resolving it :).
It turned out that there was a circular reference and Spring was doing its best to initialize and use not-fully-initialized config objects. There were config1 and config2 beans (both #Configuration) that used objects from each other.
It is interesting to know that in such a situation Spring tries to initialize #Resource, #Autowired and #Value in the following order:
#Resource is initialized first, in the order that objects were declared in the #Configuration bean
#Value is treated as #Autowired. Hence, #Value and #Autowired are initialized in the order of appearance AFTER all #Resource beans are initialized.
It is important to understand the above order, because your beans and circular reference may rely on #Value settings and such setting may still be null while creating a resource referenced from other config bean.
However, the best strategy is to avoid circular references and finally that is what I did - put offending resources to new, third, config bean.
The order statement seems to be true. I have a number of #Autowired properties in my #Configuration bean. Those at the end of the list appear as null when trying to use them in my #Bean.
#Configuration
public class MyConfig {
#Autowired
private MyClass myClass;
#Autowired
private MyClass2 myClass2;
...
#Autowired
private MyArgument1 myArgument1;
#Autowired
private MyArgument2 myArgument2;
#Bean(name = "myList")
public List<MyInterface> getMyList() { //given MyArgument1 & MyArgument2 implement MyInterface
List<MyInterface> myList= new ArraList<MyInterface>();
myList.add(myArgument1); //resolved as null
myList.add(myArgument2); //resolved as null
return myList;
}
}
If I put them in the top of the list they are resolved properly. So.. how many should I count on being properly resolved? Need a better approach.
This is working
#Configuration
public class MyConfig {
#Autowired
private MyClass myClass;
#Autowired
private MyClass2 myClass2;
...
#Bean(name = "myList")
public List<myInterface> getMyList((#Qualifier("myArgument1") MyInterface myArgument1, (#Qualifier("myArgument2") MyInterface myArgument2) { //given myArgument1 & myArgument 2 are properly labeled as #Component("myArgument1") & #Component("myArgument2")
List<myInterface> myList= new ArraList<myInterface>();
myList.add(myArgument1); //resolved!
myList.add(myArgument2); //resolved!
return myList;
}
}
This seems to implement the right dependency

Categories

Resources