Injecting Spring Beans into Java Servlets

If you are working in a Java Web Application and you are using Spring IoC Container in your application, there is a chance that you might have to inject Spring Beans into a Java Servlet.

Since there is not a direct way to inject Spring Beans into a Java Servlet, you might try to lookup the Spring Beans from the Spring Context within your servlet and assign the dependencies which means that part of injection would no more be IoC and you would be looking for some concise way of doing this.

To solve this problem, Spring provides a trick which is a class called  org.springframework.web.context.support.HttpRequestHandlerServlet which consists of two behaviors:

  1. It is-a javax.servlet.http.HttpServlet - completes one of the requirements.
  2. and, it is a wrapper around org.springframework.web.HttpRequestHandler which has to be Spring Bean configured with bean injections, if any, to achieve the second goal (dependency injection). This is an interface which has a method called handleRequest(HttpServletRequest request, HttpServletResponse response) which the HttpRequestHandlerServlet delegates to while serving a request. So you need to implement this interface and have the dependencies wired in that class.

Note! Your servlet name (1) and you bean id (2) must match because HttpRequestHandlerServlet uses the servlet name to look up the beans form the context.

Now let’s look at an example:

  • Write your Spring bean (which is also a request handler / implements HttpRequestHandler). This bean should be configured to be component scanned. In the example below, this bean has a service called HelloService wired using Spring DI annotation @Autowired which will be injected by the Spring IoC container.
/**
* AnnotatedHttpServletRequestHandler.java
* Feb 15, 2012
*/

package
 com.sourceallies.spring.noxml.demo.web.servlet.handler
;

 
import
 java.io.IOException
;

import
 java.io.PrintWriter
;

import
 java.util.logging.Logger
;

 
import
 javax.servlet.ServletException
;

import
 javax.servlet.http.HttpServletRequest
;

import
 javax.servlet.http.HttpServletResponse
;

 
import
 org.springframework.beans.factory.annotation.Autowired
;

import
 org.springframework.stereotype.Component
;

import
 org.springframework.web.HttpRequestHandler
;

 
import
 com.sourceallies.spring.noxml.demo.service.HelloService
;

 
/**
* @author Lal
*
*/

@Component
(
"annotatedServletHandler"
)

public
 class
 AnnotatedHttpServletRequestHandler implements
 HttpRequestHandler {

 
private
 static
 final
 Logger LOGGER =
 Logger.getLogger
(
AnnotatedHttpServletRequestHandler.class
.getName
(
)
)
;

 
@Autowired
private
 HelloService helloService;

 
@Override
public
 void
 handleRequest(
HttpServletRequest request, HttpServletResponse response)
 throws
 ServletException, IOException
 {

response.setContentType
(
"text/html"
)
;

PrintWriter
 writer =
 response.getWriter
(
)
;

writer.write
(
"<h1>Spring Beans Injection into Java Servlets!</h1><h2>"
 +
 helloService.sayHello
(
"World"
)
 +
 "</h2>"
)
;

}
  • Write your Servlet. This servlet class extends org.springframework.web.context.support.HttpRequestHandlerServlet.
package
 com.sourceallies.spring.noxml.demo.web.servlet
;

 
import
 javax.servlet.annotation.WebServlet
;

 
import
 org.springframework.web.context.support.HttpRequestHandlerServlet
;

 
/**
* Servlet implementation class AnnotatedHttpServlet
*/

@WebServlet(
description =
 "Http Servlet using pure java / annotations"
, urlPatterns =
 {
 "/annotatedServlet"
 }
, name =
 "annotatedServletHandler"
)

public
 class
 AnnotatedHttpServlet extends
 HttpRequestHandlerServlet {

 
private
 static
 final
 long
 serialVersionUID =
 1L;

}

Notice the @Component(”annotatedServletHandler”) and @WebServlet(…, name = “annotatedServletHandler”). The bean id and the servlet name are exactly same.

Now, this will absolutely work and in fact you got access to Spring Beans from the Servlet provided that your Spring bean annotatedServletHandler was registered in the Spring Root Context (the context that is setup using org.springframework.web.context.ContextLoaderListener ). However, it could be possible that your Web related beans, annotatedServletHandler for instance, are registered in the Spring Dispatcher Context. If this is the case, the previous example would not work. This leads to a situation where you have to implement your own HttpRequestHandlerServlet that could lookup both root and dispatcher contexts.

Here is an implementation of such a HttpRequestHandlerServlet which is pretty much similar to what Spring provides but with added functionality to support dispatcher context as well.

package
 com.sourceallies.spring.noxml.demo.web.servlet.framework
;

 
import
 java.io.IOException
;

import
 java.util.logging.Logger
;

 
import
 javax.servlet.ServletException
;

import
 javax.servlet.http.HttpServlet
;

import
 javax.servlet.http.HttpServletRequest
;

import
 javax.servlet.http.HttpServletResponse
;

 
import
 org.springframework.beans.factory.NoSuchBeanDefinitionException
;

import
 org.springframework.context.i18n.LocaleContextHolder
;

import
 org.springframework.util.StringUtils
;

import
 org.springframework.web.HttpRequestHandler
;

import
 org.springframework.web.HttpRequestMethodNotSupportedException
;

import
 org.springframework.web.context.WebApplicationContext
;

import
 org.springframework.web.context.support.WebApplicationContextUtils
;

import
 org.springframework.web.servlet.FrameworkServlet
;

 
import
 com.sourceallies.spring.noxml.demo.initializer.ApplicationContextInitializer
;

 
@SuppressWarnings(
"serial"
)

public
 class
 MyHttpRequestHandlerServlet extends
 HttpServlet {

 
private
 static
 final
 Logger LOGGER =
 Logger.getLogger
(
MyHttpRequestHandlerServlet.class
.getName
(
)
)
;

 
// Replace ApplicationContextInitializer.DISPATCHER_SERVLET_NAME with the

// name of your dispatcher servlet

private
 static
 final
 String
 DISPATCHER_CONTEXT_ATTRIBUTE_NAME =
 FrameworkServlet.SERVLET_CONTEXT_PREFIX
 +
 ApplicationContextInitializer.DISPATCHER_SERVLET_NAME
;

 
private
 HttpRequestHandler target;

 
@Override
public
 void
 init(
)
 throws
 ServletException {

WebApplicationContext wac =
 WebApplicationContextUtils.getRequiredWebApplicationContext
(
getServletContext(
)
)
;

try
 {

this
.target
 =
 (
HttpRequestHandler)
 wac.getBean
(
getServletName(
)
, HttpRequestHandler.class
)
;

}
 catch
 (
NoSuchBeanDefinitionException e)
 {

LOGGER.info
(
"HTTP Request Handler bean was not found in Spring Root Context! Now looking up in the Dispatcher Context..."
)
;

WebApplicationContext context =
 WebApplicationContextUtils.getWebApplicationContext
(
getServletContext(
)
, DISPATCHER_CONTEXT_ATTRIBUTE_NAME)
;

this
.target
 =
 (
HttpRequestHandler)
 context.getBean
(
getServletName(
)
, HttpRequestHandler.class
)
;

}

}

 
@Override
protected
 void
 service(
HttpServletRequest request,
HttpServletResponse response)
 throws
 ServletException, IOException
 {

 
LocaleContextHolder.setLocale
(
request.getLocale
(
)
)
;

try
 {

this
.target
.handleRequest
(
request, response)
;

}
 catch
 (
HttpRequestMethodNotSupportedException ex)
 {

String
[
]
 supportedMethods =
 (
(
HttpRequestMethodNotSupportedException)
 ex)
.getSupportedMethods
(
)
;

if
 (
supportedMethods !=
 null
)
 {

response.setHeader
(
"Allow"
, StringUtils.arrayToDelimitedString
(
supportedMethods, ", "
)
)
;

}

response.sendError
(
HttpServletResponse.SC_METHOD_NOT_ALLOWED
, ex.getMessage
(
)
)
;

}
 finally
 {

LocaleContextHolder.resetLocaleContext
(
)
;

}

}

}

The rest are normal Spring configurations.

References

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误通常是由于构造函数不存在或参数不匹配引起的。可能是您的代码中使用了错误的构造函数或参数,或者您的依赖项中的类发生了更改,导致构造函数不再存在或参数不再匹配。建议检查您的代码和依赖项,并确保使用正确的构造函数和参数。 ### 回答2: 错误注入构造函数 (Error injecting constructor) 是指在使用依赖注入的过程中,因为某个类的构造函数参数或依赖项注入出错导致的异常。这个错误可能由多种原因造成,比如依赖项不存在、类型不匹配等。 Java.lang.nosuchmethoderror 是 Java 中的一个异常类型,表示当前类或接口中不存在要调用的方法或构造函数。这个错误通常都是在运行时才会出现,因为它是针对方法调用的错误。 两者联合出现的情况通常是在使用依赖注入的过程中,容器在创建对象时调用了不存在的构造函数,或者在构造函数中调用了不存在的方法。这时候,就需要检查代码中的依赖项和构造函数,找到并修复其中的错误,才能解决这个问题。 解决方法包括: 1. 检查构造函数参数和依赖项是否正确配置; 2. 检查使用的容器或框架是否能正确解析依赖关系; 3. 确认类或接口中是否存在要调用的方法或构造函数; 4. 确认代码是否正确使用了注解或配置文件等,并且没有产生冲突。 总之,这两个问题都需要我们仔细检查代码并修复错误,只有这样才能让程序正常运行。 ### 回答3: “error injecting constructor, java.lang.nosuchmethoderror” 是Java开发中一个常见的错误,通常发生在使用Spring框架进行依赖注入时。 这个错误提示显示了一个构造函数注入错误,也就是说,Spring无法找到所需的构造函数。如果一个类中有多个构造函数,Spring需要知道应该使用哪个构造函数进行注入。而如果你没有告诉Spring,它就会在使用中抛出此错误。 除了构造函数注入错误,这个错误提示也经常和“java.lang.nosuchmethoderror”一起出现。这意味着在你的代码中存在一个没有找到的方法,通常是由于代码中使用了Java类库的一个过期方法或版本不兼容的问题。 解决这个错误,有几个常见的方法: 1. 检查代码中的注入依赖是否设置正确。在代码中手动注入依赖是一种可选的方案,如果没有正确设置注入的依赖,就会出现这个错误。检查你的代码中是否确实需要手动注入依赖,也看看你的注入代码是否正确设置。 2. 确保Spring所需的库已经正常加载。在使用Spring框架时,你需要正确地加载Spring所需的库。在或许的情况下,类库的版本可能不兼容或过期,这会导致异常。更改或更新所需的库可以解决问题。 3. 检查你的Spring配置文件是否正确。在Spring配置文件中使用注入可以帮助你指定要使用的构造函数。如果你的配置文件中有错误,就会出现错误提示。确保你的配置文件中没有错误或拼写错误。 这些是解决“error injecting constructor, java.lang.nosuchmethoderror”错误的常用方法。如果仍然有问题,需要进一步调试和检查。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值