set map as a Spring bean - java

I need to set a map as a spring bean. I have a map which is intialized in init() method with #PostConstruct keyword.
public class CustomerService
{
#Autowired
TestService testService;
static Map<String, String> someMap;
#PostConstruct
public void initIt() throws Exception {
someMap = new HashMap<String, String>();
someMap = // some code by calling testService
}
#PreDestroy
public void cleanUp() throws Exception {}
}
I call this from applicationContext.xml as a bean.
<bean id="customerService" class="test.com.customer.CustomerService"/>
Initializing the map is working properly, i need to assign the value of this map into bean in order to access the value of the bean in somewhere else in the application.
I found examples of setting up map as a bean, but all were done in XML configurations.
How to inject a Map in java springs
How can i achieve this task. Any knowledge is highly appreciated.

You should just create a getter for that map. And you can #autowire your bean somewhere else and call yourbean.getMap()
and you will have it.
In your other class you can:
#Autowired
CustomerService customerService;
And of course greate a getter method in your Customer service for the map.
Then in your controller or other service you should autowire your bean with the annotation above. And then use it in your method like that:
Map m = customerService.getMap();
You can create a Flyweight Design Pattern later in your app with that approach(as you are creating a bean to hold a map). Read a tutorial about Flyweight Design Pattern here

Related

How to initialize a variable in a Service class

I have a Spring Service class and I want to put a static variable in it that will be initialized with values once when the Service is created by Spring by Autowired.
I want to achieve something like this:
#Service
public class MyServiceImpl implements IService {
public static HashMap<String,String> settings = new HashMap<String,String>();
public MyServiceImpl() {
settings.put("key1","value1");
settings.put("key2","value2");
}
And then when I Autowired that Service the variable will be initialized just once.
Is there any solution how to achieve that?
You can use #PostConstruct:
#PostConstruct
private void init() {
//fill values into map here
}
Spring Beans' default scope is singleton, so you can use constructor and #PostConstruct as well as InitializingBean interfaces or static initializer.
Some suggestion: dont use static variable if not necessary, it is not a good practice, easy to create memory leak etc. If you try to get the map before spring container initialize the bean, it will be empty and other problems can occure.

spring - ApplicationContext registerBean autowiring fails but getBean works in Spring 5

I'm using a configuration class that uses dynamic bean registration:
#Configuration
public class ConfigClass {
#Autowired
private GenericApplicationContext applicationContext;
#PostConstruct
private void init() {
System.out.println("init");
applicationContext.registerBean("exService", ExecutorService.class, () -> Executors.newFixedThreadPool(10), bd -> bd.setAutowireCandidate(true));
System.out.println("init done");
}
}
If I try to autowire the bean, application startup fails with error Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.
From the logs I can see that the init method on config class wasn't called before the error as the two system out statements were not printed out.
However, when I use applicationContext.getBean(ExecutorService.class) it does work without any issues.
Anyway I can get the bean to Autowire?
I'm deliberately not using the #Bean annotation because I need to register the beans dynamically based on certain conditions.
It could be because you are registering your bean in the middle of the context initialization phase. If your target bean initializes and auto-wires ExecutorService before ConfigClass #PostConstruct is invoked there simply is no bean available.
You can try forcing the initialization order:
#Component
#DependsOn("configClass")
public class MyComponent
#Autowired
private ExecutorService executorService;
However it would be cleaner to register a bean definition using BeanFactoryPostProcessor with BeanDefinitionBuilder:
#Component
public class MyBeanRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) bf;
reg.registerBeanDefinition("exService",
BeanDefinitionBuilder
.rootBeanDefinition(ExecutorService.class)
.setFactoryMethod("newWorkStealingPool")
.getBeanDefinition());
}
}
You can do like this:
#Resource
#Lazy
private ExecutorService executorService;
It works.
Actually, I wrote the small infrastructure that deals with such issues. Here is the idea how to do this:
Create a class (lets call it MyClass) that incapsulates ExecutorService.class as a property and declare it as Bean (#Component). Even before that create an Interface (Lets call it MyInterface) that your new class would implement
Create a factory class (Lets call it MyFactory) with method MyInterface getInstance(String) that returnce an instance of your interface. In that factory crate a static property Map[String, MyInterface] and public static method that allows you to add instances of the interface to this map
In MyClass create a constructor that at the end will place newly created instance of itself into that map in the factory with the key of your class name ("MyClass")
Now The trick is that when Spring starts and initializes it creates all its beans. As your MyClass will be created its constructor will place its instance into a factory. So now anywhere in your code you can call:
MyInterface myInterface = MyFactory.getInstance("MyClass");
And you get your bean without worrying about instantiating it. Spring already did it for you. Big extra bonus is non-intrucivness - you don't have to explicitely work with Spring classes

Spring declare multiple beans

I have an HashMap of myobjects which I want to loop through and declare each one of them as bean. At the end I want to choose one particular key as #primary.
Is there anyway to do this in Spring Java Config?
I can't really do this in listeners as these beans are required when context loads up. I was looking at factory beans but could not figure it out.
Any help is appreciated.
Thanks
Abhi
You can create a set of beans by getting a reference to ApplicationContext in one of your Java configuration classes. For example,
#Configuration
public class ServicesConfig {
#PostConstruct
public void onPostConstruct() {
Map<String, MyClass> mapOfClasses = HashMap<>(); // your HashMap of objects
AutowireCapableBeanFactory autowireCapableBeanFactory = context.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) autowireCapableBeanFactory;
for (Map.Entry<String, MyClass> myClassEntry : mapOfClasses.entrySet()) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(myClassEntry.getValue().getClass());
beanDefinition.setAutowireCandidate(true);
registry.registerBeanDefinition(myClassEntry.getKey(), beanDefinition);
autowireCapableBeanFactory.autowireBeanProperties(myClassEntry,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
}
}
}
Here MyClass is the type of your myobject and each MyClass can also have #Autowired annotations. At this point, I assume that each of these objects will be given their bean name the key of the HashMap. This objects then can be used as dependencies for other beans if you want.
Same thing can be achieved by implementing BeanDefinitionRegistryPostProcessor and overriding postProcessBeanDefinitionRegistry to register your HashMap of objects. In this method you will be able to create BeanDefinitions with BeanDefinitionBuilder.
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MyClass.class).getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition("key_of_this_object", beanDefinition);
I'm not sure if you can mark one of these beans as #Primary. But based on this post you can define your own bean resolver by extending DefaultListableBeanFactory which I haven't tested myself. As an alternative you may use #Qualifier as you already know which object is going to be the primary bean.
Hope this will help.
P.S If objects are already available to be added in to the ApplicationContext, following approach would add these custom objects to ApplicationContext
ConfigurableListableBeanFactory configurableListableBeanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
configurableListableBeanFactory.registerSingleton("key_of_this_object", myClassObject);

spring #Autowire property vs setter

What is the difference between anotate #Autowired to a property or do it in the setter?
As far as I know they both have the same result, but is there any reason to use one over the other?
UPDATE (to be more concise)
Is there a difference between this
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
private SpellChecker spellChecker;
#Autowired
public void setSpellChecker( SpellChecker spellChecker ){
this.spellChecker = spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
and this
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
#Autowired
private SpellChecker spellChecker;
public TextEditor() {
System.out.println("Inside TextEditor constructor." );
}
public void spellCheck(){
spellChecker.checkSpelling();
}
}
Sometimes you need an instance of class A, but you do not store A in the fields of the class.
You just need A instance to perform a one-shot operation. Or, you use A instance to obtain an instance of B, and you are storing B in the field.
In those cases, a setter (or constructor) autowire will suit you better.
You will not have unused class-level fields.
Concrete example:
You need to construct RabbitTemplate (an object that sends messages to RabbitMQ)
To construct it, you need ConnectionFactory
http://docs.spring.io/spring-amqp/docs/latest_ga/api/org/springframework/amqp/rabbit/core/RabbitTemplate.html#RabbitTemplate-org.springframework.amqp.rabbit.connection.ConnectionFactory-
You do not need to store that ConnectionFactory. In that case, code that looks like this:
Class MyClass {
private RabbitTemplate template;
#Autowired
void setConnectionFactory(ConnectionFactory c) {
template=new RabbitTemplate(c);
}
}
...will serve you better than directly autowiring the ConnectionFactory field.
In this example, autowiring at the constructor level would be even better, because your object will always be completely constructed. It will be clear that ConnectionFactory is a mandatory dependency, not an optional one.
With #Autowired annotation, you don't need a setter method. Once your bean's constructor is done with allocating/creating the object, Spring will scan for this annotation and would inject the object instances that you annotated.
While if you have setter and if you are still using xml config, you would explicitly set properties.
Having said that, You could annotate your constructor and setter method with autowired annotation which i would prefer as this would give me flexibility later on to move away from Spring (although i wont do it).
If you use #Autowired annotation on a property, spring will initiate the property using spring.xml. You don't need setter in this case.
If you use #Autowired annotation on a setter, you are specifying to spring that it should initiate this property using this setter method where you can add your custom code, like initializing some other property with this property.
Usage with Example:
In the case of using DAO operations using JdbcTemplate, you need DataSource as an input to JdbcTemplate, but DataSource is not required as a property in itself. So you can use DataSource Setter to initialize JdbcTempate by auto-wiring DataSource Setter. Please see the below code:
class DaoDemo{
//#Autowired
//private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource){
//this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int getTableRowCount(){
String sql = "SELECT COUNT(*) FROM DEMOTABLE";
//jdbcTemplate.setDataSource(dataSource); //No need to do this as its done in DataSource Setter now.
return jdbcTemplate.queryForObject(sql,Integer.class);
}
In the above code, the only use of dataSource was to get passed in JdbcTemplate. So, creating a property of dataSource doesn't make sense here. So, just use the #Autowired on setter method of DataSource bean to get its entry from spring.xml and make use of it at that particular time itself.
There are 3 types of autowiring:
Property based
#Autowired
private MyService service;
Constructor based. Note in Spring Boot you don't even need #Autowired annotation in this case:
class MyController {
private final MyService service;
public MyController(MyService service) {
this.service = service;
}
}
Setter based:
private MyService service;
#Autowired
public void setService(MyService service) {
this.service = service;
}
It is recommended to use Constructor based, then if not possible, Setter based and lastly Property based.
Why?
First, because in Constructor based you don't even use any Spring annotations. This helps you transition to different frameworks.
Second, Constructor or Setter based, make unit testing much easier. You don't need to use any Spring specific testing tools and you can only use Junit and Mockito.
Third, Constructor based is good because you can declare the property as final and not expose setters which helps with immutability and thread safety of the class.
Autowiring works best when it is used consistently across a project. If autowiring is not used in general, it might be confusing to developers to use it to wire only one or two bean definitions. With #Autowired on a field you don't need a setter method, which, on one hand makes the class smaller and easier to read, but on the other hand makes mocking the class a bit uglier.
Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire so-called simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.
Autowiring is less exact than explicit wiring. Spring is careful to avoid guessing in case of ambiguity that might have unexpected results, the relationships between your Spring-managed objects are no longer documented explicitly.
Wiring information may not be available to tools that may generate documentation from a Spring container.
Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Maps, this is not necessarily a problem. However for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
If you can, you should avoid the setter. If you don't need it, it's better when it doesn't exists, right?
I personally prefer Guice allowing me to write
public class TextEditor {
private final SpellChecker spellChecker;
#Inject public TextEditor(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
public void spellCheck(){
spellChecker.checkSpelling();
}
}
This goes a step further: With a final field, I know it won't ever change and I get the multithreading visibility guarantee.
There is one case where using #Autowired on an OPTIONAL property would not work.
If you want to do some initialization using that property, it might not be set before the constructor is called, and since it is optional, you cannot put it as an argument in the constructor.
In that case it is better to use an #Autowired setter method, so you can perform the initialization once the property is autowired.

How to inject spring injection manually if not done automatically

My spring dependencies are working fine but there one class
CustomUserDetaisls where i need the Autowired dependency called
#Autowired Private UserDAO userDAO
to match with username and password
But my spring injection is not working here as this class implements the userDetailsSerivce . However injection works if i remove the implements.
I have submitted the question to ask why in this question, but no one gave me answer so i decided to use the DAO with new operator
private UserDAO userDAO = new UserDAO();
But that userDAO in turn depends on session Factory which is a spring bean.
Then i again decided to get sessionfactory from java code rather than spring using following code
SessionFactory sessionFactory = new AnnotationConfiguration()
.configure("com/vaannila/service/hibernate.cfg.xml")
.buildSessionFactory();
But again i have several bean in hibernate-context like datasource , properties file and i am finding it very hard to re-write all the things.
Is there any way that I can manually inject userDAO so that all the related spring injection like sessionFactories works
If you have access to the spring context, you can retrieve an AutowireCapableBeanFactory which you can then use on any bean like this:
ApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());
AutowireCapableBeanFactory factory = springContext.get(AutowireCapableBeanFactory.class);
// this would instantiate and autowire a bean:
UserDAO userDAO = factory.createBean(UserDAO.class);
// this will autowire an already existing bean:
UserDAO manualUserDAO = new UserDAO();
factory.initializeBean(manualUserDAO, "beanNameIfNeeded");
However, if a bean requires that it be autowired before it can be used, I prefer to use the first mechanism and mark the constructor as private/protected to make sure that it cannot be created via 'new' and force it to be created via a factory like above.
UPDATE 11/27/17
I personally didn't like to have to use the factory every time I wanted to create an autowired instance. Particularly if some other process was creating the instance, such as deserializing from a database, etc.
I ended up creating a aspect to automatically handle the autowiring.
First, I created an annotation to flag classes that I wanted automatically autowired:
#Documented
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface AutowireAfterCreation {
}
Then I created an aspect that uses an 'after construction' point cut to do the autowiring. Unfortunately, I was unable to figure out a point cut that was only called after the 'last' constructor was finished, but it doesn't seem to hurt to autowire multiple times, at least in my case.
public aspect AutowiringAfterCreation {
#Autowired
private AutowireCapableBeanFactory beanFactory;
/**
* After construction, autowire the instance.
* #param o Newly created object to be autowired.
*/
after(Object o) returning : target(o) && initialization((#AutowireAfterCreation *).new(..)) {
// this aspect will actually autowire the instance multiple times if the class is part of an inheritance
// Hierarchy. This is not optimal, but it should not hurt anything to autowire more than once.
// FUTURE: modify the aspect so it only runs once, regardless of how many constructor calls are necessary.
beanFactory.autowireBeanProperties(o, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
beanFactory.initializeBean(o, "unused");
}
}
Then I had to tell Spring about the aspect so the factoryBean is autowired into the aspect itself:
<bean class="AutowiringOnDemand" factory-method="aspectOf"/>
Now I can create any instance and have it automatically autowired simply by attaching the annotation:
#AutowireAfterCreation
public class TestEntity {
#Value("${some.config.value}")
private String value;
#Autowired
private TestRepository repository;
}
Finally, all you have to do is create an instance, and it is automatically autowired after the completion of the constructors:
TestEntity entity = new TestEntity();
UPDATE 1/2/2018
The interface ApplicationContext has changed, and get() has been removed, but you can still use the first mechanism, but you need to call getAutowireCapableBeanFactory() instead.
So the first two lines in the example at the top for this answer would now look like:
ApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());
AutowireCapableBeanFactory factory = springContext.getAutowireCapableBeanFactory();
You can take a look at spring java configuration.
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
In example below all dependencies of UserDAO will be automatically set by spring.
It should be something like this:
#Configuration
#PropertySource("classpath:configuration.properties")
public class ApplicationConfig {
#Bean
public UserDAO userDAO() {
return new UserDAO();
}
#Bean
public CustomUserDetails customUserDetails (UserDAO userDAO) {
CustomUserDetails customUserDetails = new CustomUserDetails ();
customUserDetails.setUserDAO(userDAO());
return customUserDetails;
}
}

Categories

Resources