问题
I am experimenting with Spring injection for the first time. I am surely forgetting something obvious but I don't know what it is.
Under src/main/java, I have a package 'example' containing Hello, Animal, Cat.
Under src/main/webapp/WEB-INF, I have web.xml and springapp-servlet.xml.
When I deploy my app with Tomcat, I get a:
javax.servlet.ServletException: Error instantiating servlet class example.Hello
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
What am I missing for the injection to work?
Source below:
Hello.java
package example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class Hello extends HttpServlet {
private final Animal animal;
@Autowired
public Hello(final Animal animal) {
this.animal = animal;
}
@Override
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write(animal.sound());
}
}
Cat.java
package example;
import org.springframework.stereotype.Service;
@Service
public class Cat implements Animal {
public String sound() {
return "Miaou";
}
}
Animal.java
package example;
public interface Animal {
public String sound() ;
}
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springapp-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>example.Hello</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
springapp-servlet.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
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:component-scan base-package="example" />
<mvc:annotation-driven />
</beans>
I initially thought that perhaps my springapp-servlet.xml was not even read, but if I make a typo on the name springapp-servlet.xml in my web.xml, I do get an error at deployment time, so I clearly have the correct path for springapp-servlet.xml. It is being but yet the injection isn't working.
UPDATE:
I am showing below the solution that worked for me thanks to the answers below. All code remains the same except for Hello:
Hello.java
public class Hello extends HttpServlet {
@Inject
private Animal animal;
@Override
public void init(final ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
@Override
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write(animal.sound());
}
}
回答1:
This is wrong:
@Service
public class Hello extends HttpServlet {
Servlet's lifecycle is controlled by the servlet container, not by Spring. Thus you can't autowire Spring beans directly to servlet. Spring should not create servlets at all. Basically Spring doesn't know anything about your servlet, it tries to instantiate it, but it's not the same instance that was created by the servlet container and that is used to handle requests.
Finally, your servlet doesn't have a no-arg constructor. Such constructor is required, but it won't make your example pass.
The solution is to fetch desired Spring beans directly from registered web application context:
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
Animal animal = context.getBean(Animal.class);
See also (for other solutions)
- Access Spring beans from a servlet in JBoss
来源:https://stackoverflow.com/questions/14283750/instantiationexception-using-spring-injection