【Spring注解驱动开发】面试官:如何将Service注入到Servlet中?朋友又栽了!!

简介: 最近,一位读者出去面试前准备了很久,信心满满的去面试。没想到面试官的一个问题把他难住了。面试官的问题是这样的:如何使用Spring将Service注入到Servlet中呢?这位读者平时也是很努力的,看什么源码啊、多线程啊、高并发啊、设计模式啊等等。没想到却在一个很简单的问题上栽了跟头,这就说明学习知识要系统化,要有条理,切忌东学一点,西记一点,否则,到头来,啥也学不到。

如何实现将Service注入到Servlet中??

这里,我们列举两种解决方法(推荐使用第二种)

方法一:

直接重写Servlet的Init()方法,代码如下:

public void init(ServletConfig servletConfig) throws ServletException {
    ServletContext servletContext = servletConfig.getServletContext();
    WebApplicationContext webApplicationContext = WebApplicationContextUtils
            .getWebApplicationContext(servletContext);
    AutowireCapableBeanFactory autowireCapableBeanFactory = webApplicationContext
            .getAutowireCapableBeanFactory();
    autowireCapableBeanFactory.configureBean(this, BEAN_NAME);
}

这里的BEAN_NAME即为我们需要注入到Spring容器中的服务,但这并不是一个好的方法,因为我们需要在每一个Servlet中都进行这样的操作。

方法二:

我们可以写一个类似于“org.springframework.web.struts.DelegatingRequestProcessor”的委托的Bean,然后通过配置的方法把我们的服务注入到servlet中,具体方法如下,

Step 1:编写委托类DelegatingServletProxy

package com.telek.pba.base.util;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
 * 以下是类似org.springframework.web.struts.DelegatingRequestProcessor的一个委托
 * 用于通过配置的方法,在Servlet中注入Service
 * @author binghe
 * */
public class DelegatingServletProxy extends GenericServlet{
    private static final long serialVersionUID = 1L;
    private String targetBean;
    private Servlet proxy;
   @Override
   public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{
           proxy.service(req, res);
   }
     /**
      * 初始化
      */
      public void init() throws ServletException {
          this.targetBean = getServletName();
          getServletBean();
          proxy.init(getServletConfig());
      }
     /**
      * 获取Bean
      */
      private void getServletBean() {
          WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
          this.proxy = (Servlet) wac.getBean(targetBean);
      }
}

Step 2:修改Web.xml配置

在纯Servlet模式下,我们的配置方式如下(以下由于代码高亮插件的问题,请将代码中的#替换成尖括号)

<servlet>
  <description>活动发起模块活动查询分页Servlet</description>
  <display-name>launchActivityQueryServlet</display>
  <servlet-name>LaunchActivityQueryServlet</servlet-name>
  <servlet-class>com.telek.pba.launch.servlet.LaunchActivityQueryServlet</servlet-class>
<servlet>
<servlet-mapping>
  <servlet-name>LaunchActivityQueryServlet</servlet-name>
  <url-pattern>/servlet/launch/LaunchActivityQueryServlet</url-pattern>
</servlet-mapping>
</servlet>

如果采用我们这种代理的方法,则配置应该修改为:

<servlet>
  <description>活动发起模块活动查询分页Servlet</description>
  <display-name>launchActivityQueryServlet</display>
  <servlet-name>launchActivityQueryServlet</servlet-name>
  <servlet-class>com.telek.pba.base.util.DelegatingServletProxy</servlet-class>
<servlet>
<servlet-mapping>
  <servlet-name>launchActivityQuery</servlet-name>
  <url-pattern>/servlet/launch/LaunchActivityQueryServlet</url-pattern>
</servlet-mapping>
</servlet>

注意:默认情况下,Servlet的配置中,LaunchActivityQuery的首字母一般为大写,而我们的标题中已注明,我们采用Spring的注解模式,如果是自动扫描注解的话,默认情况下,注解的value值为首字母小写,即:launchActivityQuery,因此,在我们新的配置中,要注意将首字母改为小写,否则会报无法找到Bean的错误。

Step 3:至此,我们就可以像SSH的注入方式一样,注入Servlet了,以下是个小示例:

package com.telek.pba.launch.servlet;
import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import com.telek.pba.base.model.PbaUserInfo;
import com.telek.pba.launch.dao.IPbaActivityInfoCurrentDAO;
@Component
public class LaunchActivityQueryServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    //注入IPbaActivityInfoCurrentDAO
    @Resource
    private IPbaActivityInfoCurrentDAO pbaActivityInfoCurrentDAO;
    public LaunchActivityQueryServlet() {
        super();
    }
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //sth to do
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //sth to do
    }
    public void init() throws ServletException {
        // Put your code here
    }
}

最后,请留心在Spring配置文件中,配置上自动扫描包的路径:

<context:component-scan base-package="com.telek.pba.*.dao.impl,
                     com.telek.pba.*.service.impl,
                     com.telek.pba.*.servlet"/>

大功告成!

相关文章
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
1197 3
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
830 1
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
394 2
一键注入 Spring 成员变量,顺序编程
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
1241 1
|
消息中间件 存储 前端开发
资深Android开发的5个经典面试题
本文首发于公众号“AntDream”,欢迎关注。文章详细解答了五个常见的Android面试题,涵盖内存泄漏与溢出、Binder机制、MVC/MVP/MVVM架构、Handler机制及Context对象等内容,帮助读者深入了解Android开发的核心概念。
551 0
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
565 4
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
2861 2