问题
I've been trying to get Spring to inject an @Autowired dependency into my application without avail. What am I doing wrong?
I created a bean called TimeService. Its job is to return the current time to anyone that asks.
package com.foxbomb.springtest.domain.time;
import java.util.Date;
import org.springframework.stereotype.Service;
@Service
public class TimeService {
public TimeService() {
super();
System.out.println("Instantiating TimeService...");
}
public Date getTime() {
return new Date();
}
}
Of course, I need to tell Spring about this, so I added the following to web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Great, and some Spring configuration:
<?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: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 base-package="com.foxbomb.springtest.domain" />
</beans>
Now all we need is a calling class that would like to use this dependency. Unfortunately, the @Autowired here seems to do nothing:
package com.foxbomb.springtest;
import...
@Configurable
public class TimeManager {
public TimeManager() {
super();
System.out.println("Instantiating TimeManager...");
}
@Autowired
private TimeService timeService;
public Date getTime() {
return timeService.getTime();
}
}
And lastly, a JSP that wants to display the time:
<%@page import="com.foxbomb.springtest.ApplicationContextImpl"%>
<%@page import="com.foxbomb.springtest.TimeManager"%>
<html>
<head>
<title>Spring Test</title>
</head>
<body>
<h1>Autowired Dependencies....</h1>
<p>
Time is now <%=new TimeManager().getTime()%>!
</p>
</body>
</html>
But all I get is:
java.lang.NullPointerException
com.foxbomb.springtest.TimeManager.getTime(TimeManager.java:26)
回答1:
When you access TimeManager
object like this:
Time is now <%=new TimeManager().getTime()%>!
Spring does not know anything about this class. You are basically creating a new object, that's it!
Probably Spring creates an instance of TimeManager
and injects dependencies properly (however you should use @Service
rather than @Configuration
annotation), but you are not using this instance in your JSP. Instead you are creating new, unmanaged instance, that is completely independent and unaware of Spring and dependencies...
I think this will work:
<%= WebApplicationContextUtils.
getWebApplicationContext(application).
getBean(TimeManager.class).
getTime() %>
Ugly? Sure. Because the whole approach of accessing services from JSP (view) is ugly. You should at least have a servlet that accesses Spring beans and puts result in request attributes. These attributes can then be accessed in JSP that you forward to - without ugly scriptlets.
If you really want to do this "the right" way, try Spring MVC or other popular Java web framework.
回答2:
The @Autowire annotation in TimeManager was not recognized, because you told spring to start searching for annotation configuration information in the wrong package.
TimeManager is in com.foxbomb.springtest.
You have this configuration:
<context:annotation-config base-package="com.foxbomb.springtest.domain"/>
Notice that "com.foxbomb.springtest != com.foxbomb.springtest.domain".
Change your configuration to include this:
<context:annotation-config base-package="com.foxbomb.springtest"/>
Edit: Spring must instantiate TimeManager.
You will need to:
- Have TimeManager be a data member of the controller class.
- @Autowire TimeManager into the controller class (or get it from spring somehow).
- Add the TimeManager to some appropriate scope (maybe session, maybe request, maybe application).
- Access this TimeManager on your jsp page. Maybe something like this:
It is now ${MyTimeManager.time} balonia watch time.
回答3:
I tend to agree with @TomaszNurkiewicz; use a framework. However, a framework is way overkill for a lot of applications. If it's overkill for you, this answer details how to do it without all the manual work of getting the bean yourself. IMO doing it manually defeats the purpose.
回答4:
You should be using @Component
(or a child stereotype annotation) rather than @Configuration
, and annotating your TimeManager
with that. @Configuration
is used for Java based container configuration, which is not what you are doing here.
回答5:
Finally!
I got it working with the code in the above example. The trick was to set up Aspect/J and Weaving. This allows the @Configurable annotated class to automatically realize that its dependent on Spring to inject dependencies.
There wasn't much wrong with the base package :) I accidentally made a xml typo, trying to add the base-package attribute to the context:annotation-config tag. The correct definition was:
<context:annotation-config/>
<context:component-scan base-package="com.foxbomb.springtest"/>
I need actually eventually need to change it to com.foxbomb.springtext to include the class that was trying to access the bean too - as in the end it's also annotated.
Thanks everyone for your help!
来源:https://stackoverflow.com/questions/7620574/cant-get-spring-to-inject-my-dependencies