I was asked in one of interview that how we can initialize bean while project deployment in Spring ?
There are several options:
Your bean can implement InitializingBean interface and initialization work can be done inside afterPropertiesSet() method
You can just add a method in a bean class and annotate it with #PostConstruct
You can add method in a bean class and mark it as an init method. Using xml config the bean definition would look like this:
<beans>
<bean id="myBean" class="..." init-method="init"/>
</beans>
And using Java config like this:
#Bean(initMethod="init")
public MyBean myBean() {
return new MyBean();
}
You can also implement your own BeanPostProcessor and provide implementation in postProcessAfterInitialization or postProcessBeforeInitialization methods.
One caveat: all this initialization logic is a part of bean lifecycle, which doesn't mean that it will be invoked during the project deployment.
However if bean is a singleton bean then by default it is created during the spring context start up. I guess it is what you mean by project deployment.
Related
We are using spring 3.2.
We defined a bean myAccountVO in spring.xml files and set the scope to prototype, but the spring creates this bean as singleton bean.
Here is the spring xml:
<bean name="myAccountVO1"
class="valueobject.AccountVO"
scope="prototype" >
<property name="accountNo" value="0105069413007" />
<property name="accountType" value="01" />
</bean>
The service class is:
#Service //I've tested the #Scope("prototype") but no luck
public class AccountSummary {
#Autowired //I also tested #Resource but same result
private AccountSummaryVO myAccountSummaryVO1;
AccountSummaryVO getAccount(){
return myAccountSummaryVO1
}
}
Later we use this service as:
#Autowired
AccountSummary accountSummary;
............
accountSummary.getAccount()
As far as I get the AccountSummary class, itself, is a singleton and will not be instantiated every time.
It seems are very basic usecase, but I don't know what am I missing.
I don't see where you are injecting myAccountVO1.
But I guess when you reveal the injected place that it's probably a member of a bean which itself is not in the scope prototype, e.g. #Service or #Controller. The service bean will be instantiated with a newly created myAccountVO1, but this instance stays there forever.
Change the scope of the containing bean. See 4.5.3 Singleton beans with prototype-bean dependencies.
This applies as well to the beans which have the service beans injected.
If I have a bean defined in an xml file like so :
<bean id="myBean" class="com.myClass">
</bean>
Should "myBean" be autowired, ie should the class "com.myClass" be initialized by Spring ?
I have no Spring annotations in "com.myClass" but the class still seems to be initialized because it is declared in an xml file.
Yes, it is normal that your class to be initialised even though auto-wiring is not stated. The reason for this is:
Declared Spring beans have a life-cycle and the first step in this life-cycle is for Spring to initialise the bean.
The basic life-cycle is as follows:
Initialise Bean
Insert values
Calling certain methods depending on which interfaces you implement. This is useful for further custom initialisation and configuration.
Now your bean is ready for use by your application and will stay in the application context until your application context is destroyed.
Finally, if you implement the DisposableBean interface, the destroy method is called for any de-initialisation process that you may require.
This depends on whether you have any other beans that want Spring to inject myBean into them. If no one uses your bean, you can omit it.
I wonder how can I properly inject a prototype bean to a singleton one in a web app. Consider this example:
<bean id="order" class="com.foo.Order" scope="prototype"/>
<bean id="orderService" class="com.foo.OrderService">
<property name="userPreferences" ref="userPreferences"/>
</bean>
I thought of using getBean() but isn't that a way to make my code dependent to spring itself?
I need a short java code example to demonstrate how to inject an order bean in my OrderService singleton.
Thanks
You can use jsr-330 Providers, just put:
#Autowired
Provider<Order> orderProvider;
in your singleton bean, and then use the provider:
public Whatever yourMethod() {
Order order = orderProvider.get();
}
As far as I understand When Using Dependency Injection all bean are initializing on Start.
<bean id="userPreferences" class="com.foo.UserPreferences">
</bean>
<!-- a singleton-scoped bean injected to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">
<!-- a reference to the userPreferences bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
and the configuration above means that userService and userPreferences created when application starts. Is it correct?
When using Autowiring and using <context:component-scan>
public class SimpleUserService{
#Autowired
UserPreferences userPreferences;
//omitted
}
1) Is userPreference created on Application init?
2) What is the default scope for bean injected by autowire and how can we change it?
3) How affects bean creation and bean injection?
Hope I made myself clear.
First of all you should add #Service or #Component to the SimpleUserService class.
1 Yes, the ONE instance of UserPreferences is created at application intialization
2 Default scope is singleton, You can change it with the #Scope annotation (#See Spring Reference: 3.11.4.4 Specifying bean scope)
3 Component scan and XML configuration work in the same way (life cycle)
Maybe you should spend some time in understanding the Spring life cycle. You need to understand that Spring works a bit in this way (not 100% correct):
first it creates a pool of beans
then it injects the properties into the beans
But it does NOT work this way: taking a class, look what references it needs creating this references (recursive) and then creating the class.
If you understand this, then you will also understand, that the #Scope of a bean is defined at the bean declaration/class, but not at the references.
1) Is userPreference created on
Application init?
In either case userPreferences is initialized when Spring Context is loaded. You can change this behavior by adding lazy-init="true" to the bean configuration.
2) What is the default scope for bean
injected by autowire and how can we
change it?
The scope of what is injected is all beans loaded into Spring. If you import an XML configuration from another project, it too would be included. I'm not sure if you can limit your scope.
3) How affects bean creation and bean
injection?
Whether is autowired, or configured via XML, the behavior should be the same. I prefer explicitly defining dependencies over automatic annotations. Then again I also like strongly typed languages.
the configuration above means that userService and userPreferences created when application starts. Is it correct?
Yes
Is userPreference created on Application init?
Yes
What is the default scope for bean injected by autowire and how can we change it?
The default scope is always "singleton". This can be changed either using #Scope with #Bean or the scope XML attribute on <bean>.
How affects bean creation and bean injection?
This isn't a clear question. If you change the bean scope, you change when it gets created (start of application, on each request, on each session, etc). The wiring configuration remains the same, only the lifecycle changes.
The #autowired notation is an obsolete way to say #inject. THe latter is a feature of JavaEE 6.
stackoverflow.com/questions/7142622/what-is-the-difference-between-inject-and-autowired-in-spring-framework-which
I came across an example of #Autowired:
public class EmpManager {
#Autowired
private EmpDao empDao;
}
I was curious about how the empDao get sets since there are no setter methods and it is private.
Java allows access controls on a field or method to be turned off (yes, there's a security check to pass first) via the AccessibleObject.setAccessible() method which is part of the reflection framework (both Field and Method inherit from AccessibleObject). Once the field can be discovered and written to, it's pretty trivial to do the rest of it; merely a Simple Matter Of Programming.
Java allows you to interact with private members of a class via reflection.
Check out ReflectionTestUtils, which is very handy for writing unit tests.
No need for any setter, you just have to declare the EmpDao class with the annotation #component in order that Spring identifies it as part of the components which are contained in the ApplicationContext ...
You have 2 solutions:
To manually declare your beans in the XML file applicationContext :
<bean class="package.EmpDao" />
To use automatic detection by seeting these lines in your context file:
<context:component-scan base-package="package" />
<context:annotation-config />
AND to use the spring annotation to declare the classes that your spring container will manage as components:
#Component
class EmpDao {...}
AND to annotate its reference by #Autowired:
#Component (or #Controller, or #Service...)
class myClass {
// tells the application context to inject an instance of EmpDao here
#Autowired
EmpDao empDao;
public void useMyDao()
{
empDao.method();
}
...
}
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
Spring knows the existence of the beans EmpDao and MyClass and will instantiate automatically an instance of EmpDao in MyClass.
Spring uses the CGLib API to provide autowired dependency injection.
References
Usage of CGLib forum comment by Rod Johnson
3.3.1. Injecting dependencies
Pro Spring - Analyzing Spring Dependencies
Further Reading
Introduction to the Spring Framework by Rod Johnson