I'm using Spring and am trying to autowire (using annotations) a DAO into a Service, which is then wired into a controller. Having
#Autowired
Movie movieDao;
on its own doesn't work, as I think the new method gets called, so that DAO isn't managed by Spring. The following does work, but it will look messy if I have to copy and paste that context configuration into each method
#Autowired
MovieDao movieDao;
#Override
public List<Movie> findAll() {
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:app-context.xml");
context.refresh();
MovieDao movieDao = (MovieDao) context.getBean("movieDao", MovieDao.class);
return movieDao.findAll();
}
where this code is in my Service class. Is there a more elegant way to ensure that my DAO is initialised properly, rather than copying and pasting the first 4 lines of that method into each Service method?
[edit] The class that contains the code above is a class called MovieServiceImpl, and it essentially corresponds to the DataServicesImpl class in the architecture described on this page. (I'll add a summary/description of that architecture and what I'm trying to do soon). This is the code: http://pastebin.com/EiTC3bkj
I think that the main problem is that you want to instantiate your service directly (with new) and not with Spring:
MovieService movieService = new MovieServiceImpl();
When you do this, your MovieServiceImpl instance is constructed but not initialised (the field #Autowired MovieDao is null).
If you want to instantiate properly your object with field injection, you need to use Spring. As explained in the documentation or in this example, you can automatically detect all your annotated beans and initialize them in your context with the component scanning.
Example
In your case, using annotiations on (#Component, #Service, etc) and in (#Autowired, #Inject, etc) your beans, your project could look like this:
Spring configuration app-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Use component scanning to auto-discover your beans (by annotation) and initialize them -->
<context:component-scan base-package="com.se325.a01" />
<!-- No need to declare manually your beans, because beans are auto-discovered thanks to <context:component-scan/> -->
</beans>
Entry point of your application App.java
package com.se325.a01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.se325.a01.model.Movie;
import com.se325.a01.service.MovieService;
public class App {
public static void main(String[] args) {
// Let's create the Spring context based on your app-context.xml
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});
// Now your context is ready. All beans are initialised.
// You can retrieve and use your MovieService
MovieService movieService = context.getBean("movieService");
Movie matrixMovie = new Movie("Matrix");
movieService.create(matrixMovie);
}
}
In fact, when you are using Spring, it is really important to understand how the context is initialized. In the example above, it can be sum up as:
Your entry point App#main is called.
The configuration app-context.xml is loaded by ClassPathXmlApplicationContext.
The package com.se325.a01 is scanned thanks to the line <context:component-scan base-package="com.se325.a01" />. All annotated beans (#Component, #Service, etc) are contructed but not yet initialised.
When all the beans are constructed, Spring initialises them by injecting dependencies. In the example, the #Autowired annotations which mark the dependencies are also discovered thanks to the line <context:component-scan ... \>.
The context is ready with all beans :)
Notes
All this answer explains how you can use component scanning and annotations to use Spring in a main entry point. However, if you are developing a server application, the entry point is the WEB-INF/web.xml.
As #chrylis said, field injection is error prone. Prefer using constructor-based injection.
Related
I have a servlet packaged in an ear file, and I cannot get it to resolve #Value annotated properties.
The app is in two parts: a servlet packaged in a war file, which is then included by different applications packaged in an ear file. The application supplies the implementation of a class (ResourceManager) defined by an interface in the servlet, and also the property file containing the value of the property for the #Value annotated field.
The war file contains:
web.xml:
<servlet>
<servlet-class>... extends MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/spring-ws.xml
classpath:/spring-app.xml
</param-value>
</init-param>
</servlet>
spring-ws.xml:
<context:annotation-config/>
<context:property-placeholder location="classpath:/spring-ws.properties"/>
The values in spring-ws.properties are referenced directly from spring-ws.xml, and all work fine.
The servlet class contains:
public class MyServlet extends MessageDispatcherServlet
#Autowired private ResourceManager resourceManager; // original annotation - got this to work
#Value("${app.name:}") private String appName; // added later - cannot get this to work
The app.name is optional, hence the trailing ":".
The ear file adds (packaged in a jar file in the ear lib directory):
spring-app.xml:
<context:property-placeholder location="classpath:/spring-app.properties"/>
<bean class="ResourceManagerImpl">
...
</bean>
spring-app.properties:
app.name=myApp
My first problem was with the #Autowired annotation: not sure I ever got to the bottom of that correctly, but I managed to get it to work by adding this code to the servlet:
#Override
protected void initFrameworkServlet() throws ServletException {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(getWebApplicationContext().getAutowireCapableBeanFactory());
bpp.processInjection(this);
}
This may not be the best way to fix this, but it was the first I found and it worked, so I used it and moved on. Then I added a #Value annotated field, and I can't find a way to make this work. The javadocs for AutowiredAnnotationBeanPostProcessor say that it should process #Value annotations as well, but it doesn't appear to: the appName property is always blank (presumably from the default).
I do have a workaround, using beans:
#Autowired #Qualifier("appName") private String appName;
<bean id="appName" class="java.lang.String">
<constructor-arg value="myApp"/>
</bean>
But I'm sure there must be a better way of doing this. I've read this post Difference between applicationContext.xml and spring-servlet.xml in Spring Framework, but I'm not sure it applies: I don't think I even have an application context here, just a servlet context defined in the web.xml for the (single) servlet class.
I've also seen this: Spring 3.0.5 doesn't evaluate #Value annotation from properties, which looks like the same problem, but the solution there appeared to be to move the "<context:property-placeholder>" from the application context to the servlet context, whereas as I said before, I don't think I even have an application context here...
Finally, I've had a quick go at simplifying the problem, removing the separate app and packaging everything in a single war, but I don't think that is the problem (although could obviously be wrong...): spring can resolve the class path for the app.xml file so it must be able to resolve the class path for the app.properties file.
Any help much appreciated, but I guess at this point it is a bit of an academic interest, as I have a workable solution (using beans) and the people that pay the bills don't really care how it works as long as it works! I'd just like to know so next time I don't have to copy (what I think is) a flawed workaround.
Using spring-ws-core 2.1.4, which pulls in spring 3.2.4 via maven dependencies.
Thanks
Update - Solved
Turns out the key to fixing this was M Deinum's comment that "You also have a duplicate element...". I had two separate PropertyPlaceholderConfigurers in the same context, so the second was ignored and its properties never used. There was no problem with the context itself (which is a servlet context not a root context), or the annotation processing.
So the fix was simply to remove the property placeholder from the spring-app.xml, and combine both property files in the spring-ws.xml
<context:property-placeholder
location="classpath:/spring-ws.properties,
classpath:/spring-app.properties"/>
TL;DR's answer here Spring: namespace vs contextConfigLocation init parameters in web.xml is also an awesome explanation of how the different contexts are processed!
Cheers,
Your servlet isn't a spring managed bean it is managed by the Servlet container. Hence the reason why #Autowired doesn't work in the first place. Spring will only process beans it knows.
Both the ContextLoaderListener and your servlet (basically any servlet that extends FrameworkServlet) have there own instance of an ApplicationContext. The one from the ContextLoaderListener is used as a parent by the context constructed in the servlet. So you indeed have an ApplicationContext in your servlet.
Now for this #Value to resolve properly you need to have a PropertyPlaceHolderConfigurer to resolve the placeholders. As PropertyPlaceHolderConfigurer is a BeanFactoryPostProcessor it only operates on beans in the same context, so the one loaded/configured by the ContextLoaderListener doesn't do anything for beans related to the context from your servlet. (Hence you need to add <context:property-placeholder ... /> element to the servlet context).
You also have a duplicate element in general you want to avoid that kind of situation as it will lead to problems at same time, either one overriding the other or you will get exceptions that placeholders cannot be resolved by either one of the PropertyPlaceHolderConfigurer
Your init code is also overly complex and you don't need the AutowiredAnnotationBeanPostProcessor simply use the available methods.
getWebApplicationContext().getAutowireCapableBeanFactory().autowireBean(this);
Which also does more then what only the AutowiredAnnotationBeanPostProcessor does.
for #Autowired annotation, you just need to have a class with those annotations:
#Configuration
#PropertySource("classpath:myFile.properties")
#ComponentScan("com.company.package")
The #Configuration is used by Spring to tell it's a class for configuration (it replaces the xml files that you talked about, xml conf file is Spring 2, annotation is new with Spring 3 and 4)
The #ComponentScan manage the IOC (#Autowire)
The #PropertySource load the prop file
Then the class to initialized at startup with the prop file:
#Component("myFileProperties")
public class MyFileProperties{
#Value("${app.name}")
private String appName;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName= appName;
}
}
Take a look here if you want it can inspire you (a conf file in a web context that I developped): https://github.com/ebrigand/RSSLiker/blob/master/src/main/java/com/mrm/rss/init/WebAppConfig.java
There is a workaround for this.
You can create a static field in a java class to store the value in.
public class SystemPropertyHelper {
public static String propertyValue;
}
And create a java class annotated with #Service or #Component, which you can inject the property in, and pass this value to the static field.
#Component
public class SpringBeanClass {
#Value("${propertyName}")
private String propertyValue;
#PostConstruct
public void init() {
SystemPropertyHelper.propertyValue = propertyValue;
}
}
This way you can always access the property value through the static field SystemPropertyHelper.propertyValue
I have a graph of Spring beans which autowire each other. Heavily simplified illustration:
<context:annotation-config/>
<bean class="Foo"/>
<bean class="Bar"/>
<bean class="Baz"/>
...
public class Foo {
#Autowired Bar bar;
#Autowired Baz baz;
}
public class Bar {
#Autowired Foo foo;
}
public class Baz {
#Autowired Foo foo;
}
All of these beans don't have scope specified which imply they are singletons (making them explicit singletons doesn't change anything, I've tried).
The problem is that after the instantiation of a single application context, instances of Bar and Baz contain different instances of Foo. How could this happen?
I have tried to create public no args constructor for Foo and debugging has confirmed Foo is created more than once. The stack trace for all of these creations is here.
I have also tried to enable debug logging for Spring, and among all other lines, got the following:
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
I understand that my beans are cross-referencing each other, but I would expect Spring framework to respect singleton scope and initialize a singleton bean once, and then autowire it to whoever wants it.
The interesting fact that if I use old school private constructor with public static Foo getInstance accessor, this works just fine - no exceptions are thrown during the context setup.
FWIW, I am using Spring version 3.0.5 (also tried with 3.1.2, same results) with o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations) constructor.
I can easily convert my code to use static initializer but I want to understand why would Spring behave this way. Is this a bug?
EDIT: Some additional investigation showed that
After the application context is initialized, all subsequent requests to context.getBean(Foo.class) always return the same instance of Foo.
Replacing #Autowired with setters (about 20 usages of this bean) still results multiple constructions of this object, but all dependencies are injected with the same reference.
To me above suggests that this is a Spring bug pertaining to #Autowired implementation. I am going to post to Spring community forums and post back here if I manage to obtain anything useful.
Child context(s) can reinstantiate the same singleton beans if you are not careful with context:component-scan annotations (there are other Spring context scan annotations as well such as MVC ones and others). This is a common problem when using Spring servlets in web applications, see Why DispatcherServlet creates another application context?
Make sure you are not re-scanning your components in child contexts, or you are scanning only specific packages/annotations and excluding said packages/annotations from root context component scan.
For some reason we are getting this popping up randomly in integration tests and services as well (spring version 4.1.4, java 1.8).
Looks like there might be more than one culprit - Autowiring appeared to be causing this at first.
However, we have resolved the most consistent failures by ensuring we give each impacted bean an 'id' field.
Try using setter injection instead of constructor way and see if it works.In the spring bean xml specify Bean A ref to Bean B and vice versa.
My Spring configuration was like follows:
<context:annotation-config/>
<bean class="Bar" />
<bean class="Foo" />
<bean class="Baz" />
Classes are identical to yours
Test app like follows:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml");
Foo foo = ctx.getBean(Foo.class);
Baz baz = ctx.getBean(Baz.class);
Bar bar = ctx.getBean(Bar.class);
System.out.println(foo.equals(baz.foo));
System.out.println(foo.equals(bar.foo));
System.out.println(baz.equals(foo.baz));
System.out.println(foo.baz.toString());
System.out.println(baz.toString());
System.out.println(foo.bar.toString());
System.out.println(bar.toString());
}
}
Output from test app like follows:
true
true
true
Baz#8aef2b
Baz#8aef2b
Bar#215bf054
Bar#215bf054
Using 3.0.6 it works perfectly fine (singleton beans are indeed singletons). There might be something else you did not illustrate here messing up your configuration. Of course, as a side note, using default package may cause some misterious magic to happen ;-)
I'm building a Google App Engine app using Spring 3.1 and am having a problem getting members in one of my jars wired.
I have three projects:
server
server.model
server.persistence
I have an ant build script so that when my workspace builds, it creates jars for server.model and server.persistence, and puts them in the correct lib directory for the server project.
In server, I can autowire things from both server.model and server.persistence, but in server.model my server.persistence beans aren't getting wired even though they're the exact same as in server.
snippet from my servlet application config:
<context:component-scan base-package="com.impersonal.server"/>
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore"/>
<bean autowire="byType" id="userList" class="com.impersonal.server.model.UserList"/>
I have the following code in both the server project and the server.model project, and only the server one gets fulfilled. Here's the one failing:
package com.impersonal.server.model;
import java.util.ArrayList;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import com.impersonal.server.persistance.AppEngineDataStore;
import com.impersonal.server.persistance.IDataStore;
public class UserList extends ArrayList<User>
{
private UserList(){}
//this is always null, but the same line in a class in the other project works
private #Autowired AppEngineDataStore _dataStore;
public UserList(UUID userId, String tempId)
{
String poo = "poo";
poo.concat("foo ");
int i = 3;
}
}
Edit:
Just did a test in the server.model project trying to #Autowired something that I don't have defined as a bean in my application config, and didn't get any errors. I should have got a 'no such bean found' error like I do if I do the same thing for the server project.
Any ideas why?
I was instantiating my objects incorrectly. For framework objects and such like MVC controllers, you don't need to do anything to get your #Autowired members wired.
For objects I was creating on the fly, I wasn't going through the IOC container, that's why their dependencies weren't being fulfilled.
<context:component-scan/> tag searches for annotated classes.
If you are going to autowire class using #Autowire annotation, Autowiring class should be annotated with one of stereotype annotation (#Component,#Controller,#Service,#Repository). Spring resolves first annotation configuration and then xml configuration. This is written in spring doc as
Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.
Check proof on spring doc.
So what you need to do is add annotations for classes from server project as well as server.model. Same in case of your third project server.persistence. Add annotations according to layers or functionality.
Try:
#Autowired(required = true)
private AppEngineDataStore _dataStore;
Instead of:
private #Autowired AppEngineDataStore _dataStore;
EDIT 1:
While using the autowire above, in your spring xml, try:
<bean id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore" scope="prototype"></bean>
Instead of:
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore"/>
autowire in xml means slightly different thing. Instead of defining your bean in xml, you can annotate it as #Service, it will be discovered by the component-scan and the #Autowired will work.
In your xml configuration, use autowire-candidate property
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore" autowire-candidate="true" />
I'm developing some kind of plugin which should be called by external java app.
my Plugin is using Spring and of cause I tried to simplify my as I can:
Let's consider that this is 3d party app and it's calling my plugin in its main function.
public class ThirdPartyClass {
public static void main(String[] args) {
GeneralPlugin plugin = new MyPlugin();
plugin.init();
//calling ext. plugin functionality.
plugin.method1();
}
}
Now this is my plugin
package com.vanilla.spring;
#Component
public class MyPlugin implements GeneralPlugin{
#Autowired
Dao mydao;
public void init(){
//some initiation logic goes here...
}
public void method1(){
dao.delete();
}
}
Now my Dao
package com.vanilla.spring;
Component(value="dao")
public class MyDao {
public void delete(){
//SOME DATABASE LOGIC GOES HERE!!!
}
}
now my XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
<context:annotation-config />
<context:component-scan base-package="com.vanilla.spring"></context:component-scan>
</beans>
My problem is that my dao is null and I'm getting NullPointerException when accessing dao object.
I
m believe it happens because I'm initiation bean out of Application context and as the result my Autowiring is not working.
Is there any other way to make autowiring work?
"Spring beans" are just that: Java beans. They have no intrinsic abilities other than those given to them by inheritance or object instantiation.
The Spring Application Context is responsible for creating the bean and "wiring" it, which is the process of creating other beans in the context and calling the bean's setters (and constructors) with the results to configure them. To do this is uses the XML configuration file and annotations to decide what to create and where to put it.
If you aren't going to use an actual Application Context, then you have to do all of that work yourself, manually. That is, create the DAO with the proper data source, create the plugin bean, and set the DAO on the plugin bean.
In this specific example, since the 3rd party application controls the instantiation of your plugin bean, you will likely have to either a) create the DAO in the plugin constructor (which is what you're using Spring to avoid in the first place), or b) create an Application Context in the plugin constructor and reference the beans the plugin needs by querying the context. This isn't quite as useful as letting the context do everything, but at least you don't have to configure the rest of the beans your application uses manually (with user names, connection URLs, etc).
If you go the second route you would then need the Spring configuration file somewhere in the classpath or somehow otherwise able to be referenced by the plugin bean.
I want to write a standalone application with IOC, how do I use springs dependency injection in there? I'm using JIdea. There is spring 2.5 support but I want to use spring 3.0 here is the way I tried!
I experience in using Spring MVC we can inject dependencies there in a WebApplicationContext but how do I inject dependencies in a standalone application
I tried this
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"com\\ttg\\xmlfile.xml"});
but I cannot see that the dependencies are injected by the beans defined there (in the XML file)
I put the above code in the main method and two bean definitions for two Objects,in one Java class's constructor I used the other class's object - which was injected to this object - and called a method on that which will print some thing but it didn't worked I thought that the above code creates all the dependencies and injects them but it doesn't seem like that
How do I properly use Springs IOC, dependency injection in my stand alone app which does not contain a WebApplicationContext?
Please mention steps.
suppose you have:
class Bean1 {
Bean2 bean2;
}
class Bean2 {
String data;
}
the context.xml file
<bean id="bean1" class="Bean1">
<property name="bean2" ref="bean2" />
</bean>
<bean id="bean2" class="Bean2" />
then this should be true
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"context.xml"});
Bean1 bean1 = (Bean1) context.getBean("bean1");
// bean1.bean2 should not be null here.
you can use autowiring support provided by spring, in order to inject dependencies (and possibly apply post processors) to an object that is not part of the application context.
In your case, this object is your standalone application.
Here is the way to achieve this. In this example, I use #Autowired (for b1), traditional DI (for b2) and initialization hook for b3. The autowiring support with annotations assumes you have defined the appropriate spring post-processor in your application context (e.g. by declaring <context:annotation-config/>).
public class StandaloneApp implements InitializingBean {
#Autowired private Bean1 b1;
private Bean2 b2;
private Bean3 b3;
public void afterPropertiesSet() throws Exception {
this.b3 = new Bean3(b1, b2);
}
public void setB2(Bean2 b2) {
this.b2 = b2;
}
public static void main(String... args) {
String[] locations = // your files relative to the classpath
ApplicationContext ac = new ClasspathXmlApplicationContext(locations);
// or use FileSystemXmlApplicationContext if the files are not in the classpath
StandaloneApp app = new StandaloneApp();
AutowireCapableBeanFactory acbf = ac.getAutowireCapableBeanFactory();
acbf.autowireBeanProperties(app, AUTOWIRE_BY_NAME, false);
acbf.initializeBean(app, "standaloneApp"); // any name will work
}
}
In this example, all b1, b2 and b3 should be non-null (assuming b1 and b2 beans exist in your application context).
I haven't tested it (might not even compile due to some typo), but the idea is in the last 3 lines. See the javadocs for AutowireCapableBeanFactory and mentionned methods to see exactly what happens.
If you prefer (mostly) pure java, you can use java config:
#Configuration
pubic class MyConfig {
#Bean
public Bean1 bean1() { return new Bean1(); }
#Bean
public Bean2 bean2() { return new Bean2(bean1()); }
}
And then to instantiate:
ApplicationContext ctx =
new AnnotationConfigApplicationContext(MyConfig.class);
Keep in mind there's some things that pure annotation driven configuration doesn't yet support (such as things like tx:annotation-driven), which you might need some xml glue code for.
<beans>
<tx:annotation-driven />
<context:annotation-config/>
<bean class="MyConfig"/>
</beans>
And then use a standard xml based way of creating the ApplicationContext (like ClasspathXmlApplicationContext, or the spring web context loader, etc...).
How did you confirm that your beans aren't being wired correctly? One common issue is the xml config file not being in the right place. Can you give us some more information like your project layout and the code you use to obtain the beans from the container?
If you add log4j logging to your app, you should see a cascade of messages coming out that will tell you a lot about what Spring is and is not doing. If you don't have that feedback, you're in the dark. You might be able to ferret out the answer just by getting more information out of Spring from log4j.
Are you calling context.getBean("beanName") to get a reference to the bean or are you doing a new SomeClass()? If you do it through getBean() then the injected properties should be set.
Also, be sure to use the same bean factory (ClassPathXmlApplicationContext instance) for retrieving all your beans. This should most likely be static final and used by the entire application.
you can use the command #Autowired