简体   繁体   English

使用Spring注入的InstantiationException

[英]InstantiationException using Spring injection

I am experimenting with Spring injection for the first time. 我是第一次尝试使用Spring注射器。 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. 在src / main / java下,我有一个包含Hello,Animal,Cat的包'example'。

Under src/main/webapp/WEB-INF, I have web.xml and springapp-servlet.xml. 在src / main / webapp / WEB-INF下,我有web.xml和springapp-servlet.xml。

When I deploy my app with Tomcat, I get a: 当我使用Tomcat部署我的应用程序时,我得到一个:

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 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 Cat.java

package example;

import org.springframework.stereotype.Service;

@Service
public class Cat implements Animal {
  public String sound() {
    return "Miaou";
  }
}

Animal.java Animal.java

package example;

public interface Animal {
  public String sound() ;
}

web.xml 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 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. 我最初认为也许我的springapp-servlet.xml甚至没有读过,但是如果我在我的web.xml中的名字springapp-servlet.xml上输入错误,我在部署时遇到错误,所以我显然有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之外,所有代码都保持不变:

Hello.java 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());
  }    
}

This is wrong: 这是错的:

@Service
public class Hello extends HttpServlet {

Servlet's lifecycle is controlled by the servlet container, not by Spring. Servlet的生命周期由servlet容器控制,而不是由Spring控制。 Thus you can't autowire Spring beans directly to servlet. 因此,您无法将Spring bean直接自动装配到servlet。 Spring should not create servlets at all. Spring根本不应该创建servlet。 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. 基本上Spring并不知道你的servlet,它试图实例化它,但它不是由servlet容器创建的用于处理请求的实例。

Finally, your servlet doesn't have a no-arg constructor. 最后,您的servlet没有no-arg构造函数。 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: 解决方案是直接从注册的Web应用程序上下文中获取所需的Spring bean:

WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
Animal animal = context.getBean(Animal.class);

See also (for other solutions) 另见(其他解决方案)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM