Spring注入Servlet

所以我看到了这个问题:

Springdependency injection到其他实例

并想知道我的方法是否会成功。

1)在我的Spring应用程序上下文中声明bean

                

2)覆盖我的servlet的init方法,如下所示:

  @Override public void init(ServletConfig config) throws ServletException { super.init(config); ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); this.apiData = (ApiData)ac.getBean("apiData"); this.apiLogger = (ApiLogger)ac.getBean("apiLogger"); } 

这个工作还是Spring还没准备好在Web应用程序部署中将bean交付给我的servlet? 我是否必须做一些更传统的事情,比如把bean放在web.xml

您要做的是使每个Servlet都有自己的ApplicationContext实例。 也许这就是你想要的,但我对此表示怀疑。 ApplicationContext对于ApplicationContext应该是唯一的。

执行此操作的适当方法是在ServletContextListener设置ApplicationContext

 public class SpringApplicationContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); sce.getServletContext().setAttribute("applicationContext", ac); } ... // contextDestroyed } 

现在,所有servlet都可以通过ServletContext属性访问相同的ApplicationContext

 @Override public void init(ServletConfig config) throws ServletException { super.init(config); ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute("applicationContext"); this.apiData = (ApiData)ac.getBean("apiData"); this.apiLogger = (ApiLogger)ac.getBean("apiLogger"); } 

我想利用Sotirios Delimanolis提供的解决方案,但为混合添加透明自动assembly。 我们的想法是将普通的servlet转换为支持autowire的对象。

所以我创建了一个父抽象servlet类,它检索Spring上下文,获取和支持自动assembly的工厂,并使用该工厂自动assemblyservlet实例(实际上是子类)。 我还将工厂存储为实例变量,以防子类需要它。

所以父抽象servlet看起来像这样:

 public abstract class AbstractServlet extends HttpServlet { protected AutowireCapableBeanFactory ctx; @Override public void init() throws ServletException { super.init(); ctx = ((ApplicationContext) getServletContext().getAttribute( "applicationContext")).getAutowireCapableBeanFactory(); //The following line does the magic ctx.autowireBean(this); } } 

一个sevlet子类看起来像这样:

 public class EchoServlet extends AbstractServlet { @Autowired private MyService service; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.getWriter().println("Hello! "+ service.getMyParam()); } } 

请注意,EchoServlet唯一需要做的就是在常见的Spring实践中声明一个bean。 魔术是在超类的init()方法中完成的。

我还没有彻底测试过。 但是它使用了一个简单的bean MyService,它也可以从Spring管理的属性文件中获取一个自动assembly的属性。

请享用!


注意:

最好用Spring自己的上下文监听器加载应用程序上下文,如下所示:

  contextConfigLocation classpath:applicationContext.xml   org.springframework.web.context.ContextLoaderListener  

然后像这样检索它:

 WebApplicationContext context = WebApplicationContextUtils .getWebApplicationContext(getServletContext()); ctx = context.getAutowireCapableBeanFactory(); ctx.autowireBean(this); 

只需要导入spring-web库,而不是spring-mvc。

到目前为止,这里的答案只对我有用。 特别是带有@Configuration注释的类被忽略了,我不想使用xml配置文件。 以下是我使用基于Spring(4.3.1)注释的设置进行注射工作的方法:

在web-app下的web.xml中引导AnnotationConfigWebApplicationContext。 作为参数,您需要contextClass和contextConfigLocation(您的带注释的配置类):

  contextClass  org.springframework.web.context.support.AnnotationConfigWebApplicationContext    contextConfigLocation com.example.config.AppConfig   org.springframework.web.context.ContextLoaderListener  

然后覆盖servlet中的init方法。 我使用了一个扩展HttpServlet的抽象类,所以我不必在每个servlet中重复它:

 @Configurable public abstract class MySpringEnabledServlet extends HttpServlet { @Override public void init( ServletConfig config) throws ServletException { super.init(config); SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); } [...] } 

最后我在web.xml中提到的AppConfig类中有我的主要配置:

 @Configuration @ComponentScan(basePackages = "com.example") @Import( { SomeOtherConfig.class }) public class AppConfig { } 

dependend类注释:

 @Component public class AnnotatedClassToInject 

并通过自动assembly注入我的servlet:

 @Autowired private AnnotatedClassToInject myClass; 

Spring独立于Servlet启动。 在spring读取bean xml之后,它将准备好传递bean。 所以在下面的声明之后,bean已经可用了

 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 

另外,正如@LuiggiMendoza所指出的,每个ApplicationContext都会创建/维护自己的bean,因此创建ApplicationContext 一次并从不同的servlet 重用它(而不是在Servlet的init()方法中创建它们init()总是好的。