Spring bean autowiring based on property - java

I want to specify in property file, which bean will be autowired.
I found the solutions but all of them are using #Profile annotation, which means that they are based on specified profile, not specified property.
I did it in that way:
#Configuration
public class WebServiceFactory {
#Value("${webservice}")
private String webService;
#Lazy
#Autowired
private GraphQLService graphQLService;
#Lazy
#Autowired
private RestService restService;
#Primary
#Bean
WebService getWebService() {
switch (webService) {
case "graphQlService":
return graphQLService;
case "restService":
return restService;
default:
throw new UnsupportedOperationException("Not supported web service.");
}
}
}
Bean type I want to autowire is interface WebService, GraphQLService and RestService are it's implementations.
Is there any better way to do this?

You can do this using the normal configuration of Spring.
class A{
B bBean;
...//setters/getters here.
}
class B{}
You can have a configuration file (It also can be a configuration class)
<bean id = "a" class = "A">
<property name="bBean" ref="b"/>
</bean>
<bean id = "b" class = "B">
</bean>
The bBean configuration can be in a different file, so you can import it from you classpath. Instead of using a property file you use a configuration file in the classpath o systemfile. If B is a different implementation then you modify your config file with the right class.

Related

What is the programatic equivalent of a XML defined spring bean

What is the programatic equivalane to defining a bean like this in xml:
<bean id="foo" class="com.bizz.Foo" />
Ideally I would like to be able to have spring create that bean, without using XML and without calling new and for this to happen within a #Configuration type class. For example:
#Configuration
public ConfigBar {
#Bean
public com.bizz.Foo foo() {
return /* Programmatic equivalent of <bean id="foo" class="com.bizz.Foo" /> here*/;
}
}
I don't think new Foo() is equivalent:
as spring is able to pick which constructor to use which may not be the no args constructor.
and spring is able to inject dependencies, which I don't think will be done here.
I know that spring is doing some reflection to achieve this, however simply stating that is not the answer to this question.
so how can we let spring create the Foo bean programmatically letting spring inject dependencies, pick the constructor and perhaps other tasks that spring would normally do when defined in XML?
The equivalent is #Component or any variant thereof such as #Controller or #Service. So long as your bean is in a package included in the component scan Spring will be able to find your bean at runtime and inject it into other beans.
As an example:
#Component
public class Foo {
//...
}
#Service
public class Bar {
// Spring will find and inject Foo bean creating it if necessary when
// creating the Bar "service" bean
#Autowired
private Foo foo;
//...
}
I have worked it out:
#Bean
#Autowired
public Foo foo(AutowireCapableBeanFactory autowireCapableBeanFactory) {
return autowireCapableBeanFactory.createBean(Foo.class);
}

Autowiring conflict in spring core with the xml configuration

Taking as reference the post Spring #Autowired and #Qualifier
We have this example to fix the autowiring conflict :
public interface Vehicle {
public void start();
public void stop();
}
There are two beans, Car and Bike implements Vehicle interface.
#Component(value="car")
public class Car implements Vehicle {
#Override
public void start() {
System.out.println("Car started");
}
#Override
public void stop() {
System.out.println("Car stopped");
}
}
#Component(value="bike")
public class Bike implements Vehicle {
#Override
public void start() {
System.out.println("Bike started");
}
#Override
public void stop() {
System.out.println("Bike stopped");
}
}
#Component
public class VehicleService {
#Autowired
#Qualifier("bike")
private Vehicle vehicle;
public void service() {
vehicle.start();
vehicle.stop();
}
}
That's a very good example to fix this problem.
But when I have the same problem but without those balises in the application context:
<context:component-scan></context:component-scan>
<context:annotation-config></context:annotation-config>
All the issues are solved by using the #Qualifier annotation, but in my case we don't use the balise that permit to use annotation.
The question is :
How can I fix this issue just using the configuration in application context, that's it, without using annotations?
I searched a lot and I found people talking about autowire attribute in the bean declaration <bean id="dao" class="package.IDao" autowire="byName"></bean> and I need more explanation about it.
How can I fix this issue just using the configuration in application
context?
You could use the qualifier tag like below (see https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers)
<context:annotation-config/>
<beans>
<bean class="your_pkg_route.Vehicle">
<qualifier value="bike"/>
</bean>
</beans>
</context:annotation-config>
I found people talking about autowire attribute in the bean
declaration and I need more explanation about it
Using Annotation
#Autowired used on a bean declaration method injects the defined dependencies by (another) declared beans. Now, if your dependencies are in the same context of your application, you don't need to use the #Autowired annotation at all because Spring is able to figure them out by itself. So, if your dependencies are outside your applicatoin context then you can use it.
For example, take as reference the below code:
#Autowired
#Bean
public MyBean getMybean(Dependency1 depdency1, Dependency2 depdency2) {
return new MyBean(depdency1.getSomeStuff(), depdency2.getSomeOtherStuff());
}
Here, #Autowired will find an instance of Dependency1 and Dependency2 and will provide them for the creation of an instance of MyBean.
Using xml configuration
From Pro Spring 5... Spring supports five modes for autowiring.
byName: When using byName autowiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in ApplicationContext, the foo bean is assigned to the foo property of the target.
byType: When using byType autowiring, Spring attempts to wire each of the
properties on the target bean by automatically using a bean of the same type in
ApplicationContext.
constructor: This functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts String and an Integer, and you have both a String and an Integer bean in your ApplicationContext, Spring uses the two-argument constructor.
default: Spring will choose between the constructor and byType modes
automatically. If your bean has a default (no-arguments) constructor, Spring uses
byType; otherwise, it uses constructor.
no: This is the default
So, in your case you would need to do something like this (BUT, I would NOT recommend it. Why?, you would need to declare Vehicle class as a bean and a component which is not correct, see Spring: #Component versus #Bean. On the other hand I'm not sure if you could use it just declaring it as a bean):
// xml config
<context:annotation-config/>
<beans>
// use the primary tag here too! in order to say this the primary bean
// this only works when there are only two implementations of the same interface
<bean id="bike" primary="true" class="your_pkg_route.Bike"/>
<bean id="car" class="your_pkg_route.Car"/>
<bean autowire="byName" class="your_pkg_route.VehicleService"/>
<beans>
</context:annotation-config>
// VehicleService
#Component
public class VehicleService {
private Vehicle bike; // call attribute 'bike' so it is autowired by its name
public void service() {
//...
}
}
As you can see there is a lot of complications trying to do this using xml config, so I would recommend you to use the annotation option if possible.
Related posts:
Why do I not need #Autowired on #Bean methods in a Spring configuration class?
Difference between #Bean and #Autowired
PS: I have not tested any of the posted codes.
You can use #Primary instead of #Qualifier
#Primary
#Component(value="bike")
public class Bike implements Vehicle {
we use #Primary to give higher preference to a bean when there are multiple beans of the same type.
We can use #Primary directly on the beans
You can also set primary attribute in XML:
property has primary attribute:
<bean primary="true|false"/>
If a #Primary-annotated class is declared via XML, #Primary annotation metadata is ignored, and is respected instead.

Spring Boot #Autowired MessageSource works in one classes and doesn't in another

I'm learning Spring boot framework (version 2.0.7.RELEASE) for developing web application. When I try to autowire MessageSource class it works for one classes, but doesn't for another:
Here is my WebConfig class:
package net.local.mis.phog.config;
#Configuration
public class WebConfig implements WebMvcConfigurer {
[...]
#Bean
public MessageSource messageSource() {
// This is the only place around application where messageSource is created
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
[...]
}
Everything works fine in controller classes, for example:
package net.local.mis.phog.controller;
#Controller
#Transactional
public class AlbumController {
[...]
#Autowired
private MessageSource messageSource; (works fine)
[...]
}
But when I try to inject messagSource in model classes it failes:
package net.local.mis.phog.model;
#Component
public class AlbumModel {
[...]
#Autowired
private MessageSource messageSource; (null)
[...]
}
In spring - component autowired in one class but not in another Balaji Krishnan says: "You are not using spring to obtain Account instance - so spring did not get a chance to autowire it". Perhaps I should do something of the kind, but I cannot understand how.
Can anybody please help me.
Thank you, Mikhail.
For spring to leverage dependency injection, the beans must all be managed by spring. The AlbumModel object creation should be managed by spring, so that the MessageSource can be autowired. If AlbumModel should not be managed by spring and you want to create the object yourself (which I doubt because you annotated it with #Component) then you could also use constructor injection.
Whereas you can have something like this:
package net.local.mis.phog.model;
#Component
public class AlbumModel {
[...]
private MessageSource messageSource;
[...]
#Autowired
public AlbumModel(MessageSource messageSource) {
this.messageSource = messageSource;
}
}
With the solution above, when you manually create an AlbumModel, you could pass in the MessageSource object, which is already autowired by the calling class (for example the controller or any service layer class). But also when AlbumModel creation is manage by spring it is advisable to use constructor injection. Read more about it on an article by a Spring contributor
Thank you guys for your answers.
Amit Bera, I create AlbumModel object just by calling its constructor:
package net.local.mis.phog.controller;
#Controller
#Transactional
public class AlbumController {
[...]
#Autowired
private JenreDao jenreDao;
#Autowired
private MessageSource messageSource;
[...]
#RequestMapping(value={"/album"},method=RequestMethod.GET)
public String albumShowHandler(Model model,
HttpServletRequest request,
#RequestParam(value="jenreIdSelected") Long jenreIdSelected,
#CookieValue(value="thumbnailOrder",defaultValue="ordDefault") String thumbnailOrder,
[...]) {
[...]
ThumbnailOrderAux thumbnailOrderAux = new ThumbnailOrderAux(thumbnailOrder);
JenreAux jenreAux = new JenreAux(jenreDao.getLstJenreModel(null,jenreIdSelected),jenreIdSelected);
AlbumModel albumModel = new AlbumModel(jenreAux,thumbnailOrderAux);
[...]
model.addAttribute("albumModel",albumModel);
return "album";
}
[...]
}
And here is code of AdminModel constructors:
package net.local.mis.phog.model;
#Component
public class AlbumModel {
private JenreAux jenreAux;
private ThumbnailAux thumbnailAux;
[...]
public AlbumModel() {
super();
}
public AlbumModel(JenreAux jenreAux,ThumbnailOrderAux thumbnailOrderAux) {
super();
this.jenreAux = jenreAux;
this.thumbnailOrderAux = thumbnailOrderAux;
}
[...]
}
Nazeem, I added #Component annotation to AlbumModel class in hope that MessageSource bean would be injected. Unfortunately it was not.
I could pass MessageSource as argument and it works even if I don't annotate constructor #Autowired. If I understand it right MessageSource bean is injected to AlbumController because it managed by Spring, and it isn't injected to AlbumModel because it doesn't managed by Spring. Right? If so, is there any way I make Spring manage AlbumModel object?
I had the same problem on a spring 3.1.1-RELEASE old application. In my case during debug I've got two different MessageResource objects as if the wold have been instanziated twice.
I've solved moving the bean definition:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
from dispatcher-servlet.xml xml-based configuration file to the applicationContext.xml ones.
In other words, there exists two contexts: the application context and the dispatcher servlet contexts. The application context is the parent of the dispatcher servlet context (I guess that many servlet contexts may exists under the same application context if your application consists of many servlet).
Thus, beans defined in the application context are visible to the servlet context, but not vice versa. While the servlet context contains those beans that are specifically related to MVC, the application context is used to define broader beans like services.
Since #Controller annotation is a #Component annotated ones:
#Component
public #interface Controller
i guess Spring autowires beans in #Controller and #Component differently, looking for beans in the two different contexts mentioned above.

Spring 3 default beans

I am working on a project with multiple spring configuration java classes. Many of them have beans from other config classes autowired in and then injected in the constructors of other beans.
To make this as flexible as possible, I have been using spring profiles to define which implementation of an interface to use in the case where multiple are available.
This works fine, but I was wondering if there was any way with Spring that you could define a default bean?
For example: If no bean of type Foo found on classpath, inject implementation Bar. Else, ignore Bar.
I have looked at this question: Spring 3: Inject Default Bean Unless Another Bean Present, and the solution shown with Java config would work fine if you knew the name of all of the beans, but in my case I will not know what the beans are called.
Does anybody know of a way this can be achieved?
Define the default as, well the default, just make sure that the name of the bean is the same, the one inside the profile will override the default one.
<beans>
<!-- The default datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
</bean>
<beans profile="jndi">
<jndi:lookup id="dataSource" jndi-name="jdbc/db" />
</beans>
</beans>
This construct would also work with Java based config.
#Configuration
public DefaultConfig {
#Bean
public DataSource dataSource() { ... }
#Configuration
#Profile("jndi")
public static class JndiConfig {
#Bean
public DataSource dataSource() { ... // JNDI lookup }
}
}
When using java based configuration you can also specify a default and in another configuration add another bean of that type and annotate it with #Primary. When multiple instances are found the one with #Primary should be used.
#Configuration
public DefaultConfig {
#Bean
public DataSource dataSource() { ... }
}
#Configuration
#Profile("jndi")
public class JndiConfig {
#Bean
#Primary
public DataSource jndiDataSource() { ... // JNDI lookup }
}

#Autowired Foo foo, if Foo is not a #Component

I would like to auto-wire foo:
#Autowired
Foo foo
but I cannot modify class Foo and mark it as #Component. What is the cleanest way to autowire foo?
BTW, I would prefer to use Java Spring configuration instead of XML config if you need to use config to address this problem.
Related:
Understanding Spring #Autowired usage
The #Bean annotation seems to be what you're after...
In your Javaconfig class you would create an #Bean annotated method returning Foo:
#Bean
public Foo foo() {
return new Foo();
}
See: http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html
You can use an xml configuration file to create a bean of the class Foo. Then #Autowired works the same as annotating the beans directions.
Sample xml file:
<beans>
<bean id="foo" class="Foo"/>
</beans>
If you now include this into your file with the autoscan then this bean is used as if it were annotated with #Component.

Categories