Avoid Spring ApllicationContext instanciation - java

I use Spring 3 to make a simple configuration.
I have an XML file called PropertyBeans.xml like that :
<bean id="propertyBean" class="com.myapp.PropertyBean">
<property name="rootDirLogPath" value="C:\Users\dede" />
</bean>
I have the bean which match this XML and then I want to use this bean with the value injected. Actually I have :
ApplicationContext context = new ClassPathXmlApplicationContext("AppPropertyBeans.xml");
PropertyBean obj = (PropertyBean) context.getBean("propertyBean");
String rootDirLogPath = obj.getRootDirLogPath();
This works great but I want to know if there's a way to avoid the instantiation of ApplicationContext at each time I want to use a bean. I've heard about BeanFactory is that a good idea? Which are the others solutions?
In other words: Am I supposed to called this Application context instanciation in every Controller in spring MVC?

If you want to use spring beans in controllers, add line to applicationContext.xml:
<context:spring-configured/>
<task:annotation-driven/>
<context:component-scan base-package="by" />
Then write your controller following way:
#Controller
public class IndexController {
#Autowired
private UserService userService;
#Autowired
private GroupService groupService;
// methods with #RequestMapping annotation
}
This is trivial thing, so If you have questions it is strongly recommended to read "Spring in action book", chapter 7: Building web applications

The whole idea of the ApplicationContext is that there is one (hence the name, context of the application).
So if you're creating a new one every time, you're doing it wrong.
If you use dependency injection properly, the object containing that code will already be instantiated by the injection container (Spring) and the propertyBean will have been injected.

Use autowiring or implements the InitializingBean interface.

You can simply add the context as member in your class like:
private ApplicationContext context;
and instanciate it in the constructor or an init() method.

Related

How to autowire a bean into a 2 different controllers (Spring)

I am learning spring and i have a problem that i do not know how to solve.
#Service
#Transactional
public class SchoolService {
#Autowired
private CourseDao courseDao;
#Autowired
private EducationDao educationDao;
#Autowired
private StudentDao studentDao;
#Autowired
private TeacherDao teacherDao;
#Autowired
private StatisticsDao statisticsDao;
............
}
This code is injecting my DAOS into this service class but then i need to inject the class above into two controllers.
One way i have tried was with this code but that did not work.
#Autowired
SchoolService sm;
How would i inject it into my controller class. I have tried making the controller class a #Component but nothing seems to work.
ClassPathXmlApplicationContext container = new ClassPathXmlApplicationContext("application.xml");
SchoolService sm = container.getBean(SchoolService.class);
This way works but i do not want to create a new applicationcontext for each time i want to get that bean.
Yes i am using xml at the moment, please don't shoot me :D
Thanks.
Try creating the controller bean in the application.xml file instead of annotating the controller.
Since its obviously an educational question, I'll try to provide a very detailed answer as much as I can:
Once basic thing about spring that all the auto-wiring magic happens only with beans that are managed by spring.
So:
Your controllers must be managed by spring
Your service must be managed by spring
Your DAOs must be managed by spring
Otherwise, autowiring won't work, I can't stress it more.
Now, Think about the Application Context as about the one global registry of all the beans. By default the beans are singletons (singleton scope in terms of spring) which means that there is only one object (instance) of that bean "retained" in the Application Context.
The act of autowiring means basically that the bean (managed by spring) - controller in your case has dependencies that spring can inject by looking in that global registry, getting the matching bean and setting to the data field on which the #Autowired annotation is called.
So, if you have two controllers (again, both managed by spring), you can:
#Controller
public class ControllerA {
#Autowired
private SchoolService sm;
}
#Controller
public class ControllerB {
#Autowired
private SchoolService sm;
}
In this case, the same instance of school service will be injected into two different controllers, so you should good to go.

AnnotationConfigApplicationContext has not been refreshed yet

I am developing a spring MVC application. When I try to use AnnotationConfigApplicationContext in my controller class I am getting the following error. I have no idea what this statement exactly means.
#RequestMapping(value = "/generate", method = RequestMethod.POST)
public ModelAndView generateMappingFile(#ModelAttribute Mapping mapping)
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MappingFileGenerator mfg = ctx.getBean(MappingFileGenerator.class);
}
Error Message -->
java.lang.IllegalStateException:org.springframework.context.annotation.AnnotationConfigApplicationContext#116b3c0 has not been refreshed yet
Can someone explain me what went wrong here ? I am using Spring 4.0.1.. I am new to spring mvc.
When you are creating a new instance of an ApplicationContext (regardless which type) you are basically creating new instances of each and every bean configured in that ApplicationContext. That is nice the first time, it might work the second and depending on the amount of beans, the type of beans will crash after that. As the context will never be destroy (until the app crashed and is restarted) you will run into possible memory issues, performance issues, strange transactional problems etc.
A general rule of thumb is to never construct a new instance of an ApplicationContext but to use dependency injection instead.
If you really want access to the ApplicationContext put a field of that type in your controller and put #Autowired on it.
#Controller
public class MyController {
#Autowired
private ApplicationContext ctx;
….
}
Then you can do a lookup for the bean you need in the method. This can be handy if you use the ApplicationContext as a factory for your beans. If all the beans you need are singletons it is better to simply inject the bean you need.
#Controller
public class MyController {
#Autowired
private MappingFileGenerator mfg ;
….
}
Now Spring will inject the MappingFileGenerator and it is available for use in your methods. No need to create a new instance of an ApplicationContext.
More information is in the Spring Reference Guide.
#M.Deinum's comment will get quite a few more upvotes.
Think of creating a new ApplicationContext as instantiating a new (instance of an) application. Do you want to do that every time this (or any other method in said application) is called? No, you don't.
I'm guessing you think you do because you need access to your ApplicationContext in this method. To do that - i.e. to get access to the running application context (rather than creating a new one), you want to do
#Controller // or #Service / #Component / ... : tells Spring that this is a bean, and to inject the specified dependencies
class YourClass {
#Autowired // tells Spring that this object is a dependency should should be injected
ApplicationContext ctx;
#RequestMapping(value = "/generate", method = RequestMethod.POST)
public ModelAndView generateMappingFile(#ModelAttribute Mapping mapping) {
MappingFileGenerator mfg = ctx.getBean(MappingFileGenerator.class);
}
The key here is the Autowired annotation, which tells Spring to inject the annotated object as a dependency.
I highly suggest following the links I've included (for starters), as what you're doing here suggests pretty strongly that you haven't wrapped your head around what DI is and does for you, and until you do, using it is likely to be counterproductive toward it's own ends for you.
In case it helps someone, i was having this issue on a new URL Mapping added to a gradle project, i was missing the first slash of the url and that causing this "illegalstate not refreshed yet" on my tests

Understanding Spring #Autowired usage

I am reading the spring 3.0.x reference documentation to understand Spring Autowired annotation:
3.9.2 #Autowired and #Inject
I am not able to understand the below examples. Do we need to do something in the XML for it to work?
EXAMPLE 1
public class SimpleMovieLister {
private MovieFinder movieFinder;
#Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
EXAMPLE 2
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
How can the two classes be autowired implementing the same interface and using the same class?
Example:
class Red implements Color
class Blue implements Color
class myMainClass{
#Autowired
private Color color;
draw(){
color.design();
}
}
Which design method will be called? How do I make sure the design method of Red class will be called and not Blue?
TL;DR
The #Autowired annotation spares you the need to do the wiring by yourself in the XML file (or any other way) and just finds for you what needs to be injected where and does that for you.
Full explanation
The #Autowired annotation allows you to skip configurations elsewhere of what to inject and just does it for you. Assuming your package is com.mycompany.movies you have to put this tag in your XML (application context file):
<context:component-scan base-package="com.mycompany.movies" />
This tag will do an auto-scanning. Assuming each class that has to become a bean is annotated with a correct annotation like #Component (for simple bean) or #Controller (for a servlet control) or #Repository (for DAO classes) and these classes are somewhere under the package com.mycompany.movies, Spring will find all of these and create a bean for each one. This is done in 2 scans of the classes - the first time it just searches for classes that need to become a bean and maps the injections it needs to be doing, and on the second scan it injects the beans. Of course, you can define your beans in the more traditional XML file or with an #Configuration class (or any combination of the three).
The #Autowired annotation tells Spring where an injection needs to occur. If you put it on a method setMovieFinder it understands (by the prefix set + the #Autowired annotation) that a bean needs to be injected. In the second scan, Spring searches for a bean of type MovieFinder, and if it finds such bean, it injects it to this method. If it finds two such beans you will get an Exception. To avoid the Exception, you can use the #Qualifier annotation and tell it which of the two beans to inject in the following manner:
#Qualifier("redBean")
class Red implements Color {
// Class code here
}
#Qualifier("blueBean")
class Blue implements Color {
// Class code here
}
Or if you prefer to declare the beans in your XML, it would look something like this:
<bean id="redBean" class="com.mycompany.movies.Red"/>
<bean id="blueBean" class="com.mycompany.movies.Blue"/>
In the #Autowired declaration, you need to also add the #Qualifier to tell which of the two color beans to inject:
#Autowired
#Qualifier("redBean")
public void setColor(Color color) {
this.color = color;
}
If you don't want to use two annotations (the #Autowired and #Qualifier) you can use #Resource to combine these two:
#Resource(name="redBean")
public void setColor(Color color) {
this.color = color;
}
The #Resource (you can read some extra data about it in the first comment on this answer) spares you the use of two annotations and instead, you only use one.
I'll just add two more comments:
Good practice would be to use #Inject instead of #Autowired because it is not Spring-specific and is part of the JSR-330 standard.
Another good practice would be to put the #Inject / #Autowired on a constructor instead of a method. If you put it on a constructor, you can validate that the injected beans are not null and fail fast when you try to start the application and avoid a NullPointerException when you need to actually use the bean.
Update: To complete the picture, I created a new question about the #Configuration class.
Nothing in the example says that the "classes implementing the same interface". MovieCatalog is a type and CustomerPreferenceDao is another type. Spring can easily tell them apart.
In Spring 2.x, wiring of beans mostly happened via bean IDs or names. This is still supported by Spring 3.x but often, you will have one instance of a bean with a certain type - most services are singletons. Creating names for those is tedious. So Spring started to support "autowire by type".
What the examples show is various ways that you can use to inject beans into fields, methods and constructors.
The XML already contains all the information that Spring needs since you have to specify the fully qualified class name in each bean. You need to be a bit careful with interfaces, though:
This autowiring will fail:
#Autowired
public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }
Since Java doesn't keep the parameter names in the byte code, Spring can't distinguish between the two beans anymore. The fix is to use #Qualifier:
#Autowired
public void prepare( #Qualifier("bean1") Interface1 bean1,
#Qualifier("bean2") Interface1 bean2 ) { ... }
Yes, you can configure the Spring servlet context xml file to define your beans (i.e., classes), so that it can do the automatic injection for you. However, do note, that you have to do other configurations to have Spring up and running and the best way to do that, is to follow a tutorial ground up.
Once you have your Spring configured probably, you can do the following in your Spring servlet context xml file for Example 1 above to work (please replace the package name of com.movies to what the true package name is and if this is a 3rd party class, then be sure that the appropriate jar file is on the classpath) :
<beans:bean id="movieFinder" class="com.movies.MovieFinder" />
or if the MovieFinder class has a constructor with a primitive value, then you could something like this,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg value="100" />
</beans:bean>
or if the MovieFinder class has a constructor expecting another class, then you could do something like this,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg ref="otherBeanRef" />
</beans:bean>
...where 'otherBeanRef' is another bean that has a reference to the expected class.

benefit of #Autowired annotation in Java

Maybe, because of my wrong English, I couldn't understand the benefit of using #Autowired annotation.
According to the tutorial we can simplify the first(I.) case to second case(II.) by means of #Autowired.
My question is, what is the meaning of the #Autowired ? Because it doesnt tell any more, since without using #Autowired the compiler can figure out that "EmpDao emDao" and "EmpManager" are closely related according the declaration.
code cited from here
I.
<bean id="empDao" class="EmpDao" />
<bean id="empManager" class="EmpManager">
<property name="empDao" ref="empDao" />
</bean>
public class EmpManager {
private EmpDao empDao;
public EmpDao getEmpDao() {
return empDao;
}
public void setEmpDao(EmpDao empDao) {
this.empDao = empDao;
}
...
}
II.
<context:annotation-config />
<bean id="empManager" class="autowiredexample.EmpManager" />
<bean id="empDao" class="autowiredexample.EmpDao" />
import org.springframework.beans.factory.annotation.Autowired;
public class EmpManager {
#Autowired
private EmpDao empDao;
}
#Autowired is spring-specific. #Inject is the standard equivallent. It is an annotation that tells the context (spring, or in the case of #Inject - any DI framework) to try to set an object into that field.
The compiler has nothing to do with this - it is the DI framework (spring) that instantiates your objects at runtime, and then sets their dependencies at the points you have specified - either via XML or via an annotation.
I agree it is a possible scenario for a DI framework to try to inject dependencies into all fields, even if they are not annotated. (And if you want to exclude a particular field, to annotate it). But they chose the other strategy (configuration-over-convention). By the way:
if using xml config and choose some form of autowiring, the dependencies of the bean will be automatically autowired without the need to specify anything
you can specify per-context autowiring settings.
When the server bootstraps itself. It finds
<context:annotation-config />
in the application context and then goes through the classes defined in the contexts. If there are any beans that are autowired, it injects that into the class by referring the context file.
Basically, it promotes convention over configuration. That's what most frameworks do these days to reduce the development time.
the #Autowired Spring annotation tells Spring to for a bean named 'empDao' and inject it into the EmpManager class, without you having to add the empDao bean as a property in your spring config file.
#Autowired tells Spring to find a bean of the declared type and wire in that bean, rather than requiring an explicit lookup by bean name. It can, under certain circumstances, make configuring applications easier if you only have one implementation of your types in a given Spring context.

spring mvc annotation #Inject does not work

i have the following in my app-servlet.xml
<mvc:annotation-driven />
<context:component-scan base-package="com.merc.myProject.web.controllers"/>
<context:component-scan base-package="com.merc.myProject.web.forms"/>
what ever I have in my controller package gets injected but the same thing in the forms package is always null.
my form looks something like this
public class SelectDatesForm {
#Inject IUserService userService;
.....
}
my controllers looks like this
#Controller
public class SelectDates {
#Inject IUserService userService;
.....
}
somebody please help
<context:component-scan> looks for classes annotated with things like #Component, #Controller, #Service, and so on, and configures those as beans. If those classes have properties injected with #Inject or #Resource, then those will be processed also.
However, if your class isn't annotated to start with, then #Inject will not be processed. This is the case for SelectDatesForm. If you annotate this with #Component, it should get picked up.
I'd be a bit careful here, though - forms are generally not good candidates for Spring beans, since they tend to be throw-away, transient objects.
I guess your SelectDatesForm is instantiated manually with new rather than obtained from the Spring context. In this case it is not a Spring bean and therefore not a subject for dependency injection.
Usually you don't need to inject dependencies into manually created objects. If you actually need to do so, you have several options:
Declare your SelectDatesForm as a prototype-scoped bean and obtain a fresh instance of it from Spring context instead of creating it with new:
#Component #Scope("prototype")
public class SelectDatesForm { ... }
and when you need to obtain a new instance of it:
SelectDatesForm newForm = applicationContext.getBean(SelectDatesForm.class);
However, this approach couples your code with Spring's ApplicationContext.
If your have no control over instantiation of SelectDatesForm (i.e. it happens outside of your code), you can use #Configurable
Also you can manually facilitate autowiring of the object created with new:
SelectDatesForm newForm = new SelectDatesForm();
applicationContext.getAutowireCapableBeanFactory().autowireBean(newForm);

Categories

Resources