面试专题之Java web编程

题目

  1. JAVA应用服务器有那些?
  2. 启动项目时如何实现不在链接里输入项目名就能启动?
  3. 1分钟之内只能处理1000个请求,你怎么实现,手撕代码?
  4. JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?(JSP)
  5. 说一说四种会话跟踪技术
  6. 讲讲Request对象的主要方法
  7. 过滤器有哪些作用和用法?
  8. 请谈谈你对Javaweb开发中的监听器的理解?
  9. 说说web.xml文件中可以配置哪些内容?
  10. get和post的区别
  11. cookie和session的区别?cookie和sessionStorage、localStroage之间的区别?
  12. session怎么保证多次访问是同一个ID?关闭了浏览器怎么办?
  13. 谈谈Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分别是做什么的?有什么区别?
  14. 如何设置请求的编码以及响应内容的类型?
  15. Servlet相关接口 , Servlet里面有哪些方法 ? Servlet执行时一般实现哪几个方法?
  16. Servlet 3中的异步处理指的是什么?
  17. servlet生命周期?servlet是单例模式么?为什么是单例?Servlet和cgi有什么区别?
  18. 服务器收到用户提交的表单数据,到底是调用Servlet的doGet()还是doPost()方法?
  19. servlet写过么,底层是怎么处理前台传来的请求的
  20. Servlet中如何获取用户提交的查询参数或表单数据?
  21. Servlet中如何获取用户配置的初始化参数以及服务器上下文参数?
  22. 登录功能如何保证安全性。(MD5+盐)为什么用MD5,讲一下机制。还有什么保证安全的加密方式?
  23. 设计一个怎么使得验证码有效期,过了一段时间就过期了。
  24. 如何实现单点登录

答案

1. JAVA应用服务器有那些?
应用服务器主要为应用程序提供运行环境,为组件提供服务。Java 的应用服务器很多,从功能上分为两大类,JSP 服务器Java EE 服务器,也可分其他小类。
相对来说 Java EE 服务器的功能更加强大。相对来说 Java EE 服务器的功能更加强大。我平时就用Tomcat。
JSP 服务器有 Tomcat 、Bejy TIger 、Geronimo 、 Jetty 、Jonas 、Jrun 、Orion 、Resin。
Java EE 服务器有TongWeb 、BES ApplicaTIon Server 、 Apusic ApplicaTIon Server 、 IBM Websphere 、Sun ApplicaTIon Server 、Oracle 的 Oracle9i/AS 、Sun Java System Application Server 、Bea Weblogic 、JBoss、开源GlassFish。
2. 启动项目时如何实现不在链接里输入项目名就能启动?
修改tomcat的配置文件文件:server.xml,将path中配置的项目名称去掉

<Context docBase="userManager" path="/userManage" reloadable="true" source="org.eclipse.jst.jee.server:userManager"/>

修改成:

<Context docBase="userManager" path="/" reloadable="true" source="org.eclipse.jst.jee.server:userManager"/>

这样项目启动的时候就用不用输入项目名称了。
如: localhost:8000

3. 1分钟之内只能处理1000个请求,你怎么实现,手撕代码?

我知道的有两种方式可以实现:
(1) Application 对所有用户访问的次数计数。同时定义一个计时器,单位为一分钟。如果Application 中的用户在单位时间内超出请求次数,就拒绝处理该请求。一分钟再刷新application的值为0.
使用一个Map 维护变量:

// 泛型 String 表示用户标识,List中存放用户不同请求的时间戳。
private Map<String, List<Long>> map = new ConcurrentHashMap<>();

我们只需要在单位计数中判断 List中数量是否超出限制即可。

(2) 使用 aop 实现请求的限制,在需要限制的请求方法上加上 aop 逻辑。即可实现,思路如下:
    面试专题之Java web编程_第1张图片
自定义注解类实现请求限制的拦截逻辑,在需要限制的方法上使用注解,超出限制后拒绝处理请求。

4. JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?(JSP)
相同点:
它们本质上都是java类
不同点:
(1)JSP经编译后变成Servlet
(2)jsp更擅长表现于页面显示,Servlet更擅长于逻辑控制
(3)Servlet的应用逻辑是在java文件中,并且完全从表现层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。
联系:
JSP是Servlet技术的扩展,本质上是Servlet的简易方式。

5. 说一说四种会话跟踪技术

(1)表单隐藏域

<input type="hidden" id="xxx" value="xxx">

在表单的提交中,加入这样一段数据提交的隐藏域,用户在输入时是看不到的,但是可以通过查看网页源代码来看到,在服务端只能通过post的方式获取参数。这种方式在禁用Cookie的情况下也能工作,但是关闭浏览器后就会失效。

(2)URL重写
http://www.XXX.com/news?id=xxxx
在提交请求的URL后面加上请求需要的参数,常见的GET的请求。安全性能不高,参数可以在地址栏中看到,而且对于参数的长度有限制(1024字节),禁用Cookie的情况下也能使用,但是关闭浏览器后就会失效。

(3)Cookie

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // TODO Auto-generated method stub
    super.doGet(req, resp);
    
    // 新建一个Cookie
    Cookie cookie = new Cookie("name", "pwd");
    // 设置Cookie的生命周期
    cookie.setMaxAge(Integer.MAX_VALUE);
    // 将Cookie发送到客户端
    resp.addCookie(cookie);
    
    // Cookie的修改,创建一个和已有的cookie同名,然后再添加到客户端,自动修改
    Cookie secCookie = new Cookie("name", "newPwd");
     resp.addCookie(secCookie); // cookie修改
     
     // cookie的删除, 创建一个和已有的cookie同名,并设置maxAge为0,添加到客户端,就会自动删除
     Cookie thirCookie = new Cookie("name", "thirPwd");
     thirCookie.setMaxAge(0); // 修改生命周期为0
     resp.addCookie(thirCookie);  // 删除客户端cookie
}

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。 客户端浏览器会把Cookie保存起来,并由浏览器通过域名管理不同网站的Cookie。

除了以上的Cookie属性之外,还写一些常用的属性,可以根据实际的需求设置。
面试专题之Java web编程_第2张图片
(4)Session
Session代表服务器与浏览器的一次会话过程,这个过程是连续的,也可以时断时续的。在Servlet中,session指的是HttpSession类的对象。
Session创建时间的误解:一般的误解是Session在客户端访问的时候就会被创建,但其实 Session 的真正创建时机是服务端程序调用 HttpServletRequest.getSession(true) . 我们知道JSP中有个内置对象是session,其实那是因为在我们编写的JSP代码中,默认有这么一句:HttpSession session = HttpServletRequest.getSession(true);在将JSP编译为Servlet代码的时候,Session就会被创建。但是Session会占用服务器的内存,因此我们不需要的时候,最好将该属性置false。 <% @page session=”false”%>
但客户端访问.html 等静态资源时,不涉及将JSP编译为Servlet,因此Session不会创建。当客户端第一次访问JSP页面时,服务器端将创建一个Session并保存在内存中,同时为客户端返回一个sessionID,以供客户端下次请求应用的时候带着sessionID来表明自己的身份。一次会话一个Session,Session通过sessionID来唯一标识。同时Session默认是在服务器的内存中维护的(虽然我们可以通过技术将session持久化),因此Session的长度不宜太大(虽然本身没有长度限制)。

Session原理:因为http是无状态的连接,Session也不能根据连接来识别是否是同一次会话,因此客户端第一次请求JSP/Servlet之后,服务端会自动生成一个名叫JSESSIONID的Cookie,该Cookie的值就是sessionID,发送到客户端,客户端再次连接的时候,会自动带上这个JSESSIONID,找到相应的session。如果客户端端禁用了Cookie,那么这个JSESSIONID会通过URL重写发送到服务端。

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Cookie: JSESSIONID=819B75C412FB029EDEF52B11484A642B
Host: localhost:8080
Referer: http://localhost:8080/market/
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36

Session的生命周期:
它的生命周期不累加的,而Cookie的生命周期是累加的,不累加的意思就是Session的计时是从最近一次访问开始的,而Cookie是从开始到结束,无论你期间是否使用。

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // TODO Auto-generated method stub
    super.doGet(req, resp);
    
    // 真正的创建一个Session
    HttpSession session = req.getSession(true);
    // 设置Session的生命周期
    session.setMaxInactiveInterval(Integer.MAX_VALUE);
  }

Session相关的属性:
面试专题之Java web编程_第3张图片

6. 讲讲Request对象的主要方法

序号 方法简述
1 Cookie[] getCookies()返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。
2 HttpSession getSession(boolean create)返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。
3 Enumeration getParameterNames()返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
4 Object getAttribute(String name)以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。
5 String getCharacterEncoding()返回请求主体中使用的字符编码的名称。
6 String getMethod()返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
7 String getParameter(String name)以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
8 String getRemoteHost()返回发送请求的客户端的完全限定名称
9 String getRemoteAddr()返回发送请求的客户端的互联网协议(IP)地址
10 String getRemoteHost()返回发送请求的客户端的完全限定名称。

7. 过滤器有哪些作用和用法?
过滤器的常见用途:
(1)对用户的请求进行统一的认证、对访问的请求进行记录和审核
(2)对用户传输的数据过滤和替换,转换图像格式,对响应内容进行压缩,减少网络传输
(3)对用户的请求和响应进行加密处理
(4)触发资源访问事件

Filter工作流程:
面试专题之Java web编程_第4张图片
和 Filter相关的接口定义:

// 编写一个Filter需要 实现这个接口
public interface Filter {
    
    // 初始化Filter
    public default void init(FilterConfig filterConfig) throws ServletException {}

    // Filter的逻辑实现,如果有多个Filter,必须在末尾执行 chain.doFilter(req, resp);
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    // 过滤器的销毁过程,可用于关闭该过滤器中打开的资源
    public default void destroy() {}
}

// 当有多个过滤器连成一串的时候,知道真正的请求资源之前的一系列过滤
public interface FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}

// 过滤器的配置相关
// 做Filter初始化的时候,作为参数传入,初始化关于过滤器的配置
public interface FilterConfig {

    public String getFilterName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration<String> getInitParameterNames();

}

注意事项: Filter 的执行顺序是在 web.xml 中定义的顺序,在多个Filter中的chain 中,一定在处理完当前Filter的逻辑之后,调用chain.doFilter(request, response) 转到下一个Filter

简单例子:

/**
 * 实现字符编码过滤的过滤器
 * @author ytuan
 */
public class FilterTest implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");

        chain.doFilter(req, resp);
    }

}

8. 请谈谈你对Javaweb开发中的监听器的理解?

监听器示意图:
面试专题之Java web编程_第5张图片
JavaWeb中的监听器按照事件源分为三大类:作用范围由大而小
(1)ServletContext (针对整个应用程序上下文)
(2)HttpSession (针对单个用户会话)
(3)ServletRequest (针对某一次ServletRequest )

针对这以上这三种不同作用域的对象,又把对象本身的事件类型分为三种:  
(1)域对象自身的创建和销毁事件监听
(2)域对象中属性的增删事件监听
(3)监听绑定到HttpSession域中某个对象的状态事件监听

这里的对象创建和销毁包括三个,域对象中属性的增删包括ServletContext 和 ServletRequest 两个对象。需要重点注意一下HttpSession绑定的对象,它不同于前两者。

保存在Session域中的对象可以有多种状态:
绑定(session.setAttribute(“bean”,Object))到Session中;
从 Session域中解除绑定(session.removeAttribute(“bean”));
随Session对象持久化到一个存储设备中;
随Session对象从一个存储设备中恢复;

Servlet 规范中定义了两个特殊的监听器接口"HttpSessionBindingListener和HttpSessionActivationListener"来帮助JavaBean 对象了解自己在Session域中的这些状态: ,实现这两个接口的类不需要 web.xml 文件中进行注册。
(1)HttpSessionBindingListener接口
实现了HttpSessionBindingListener接口的JavaBean对象可以感知自己被绑定到Session中和 Session中删除的事件
当对象被绑定到HttpSession对象中时,web服务器调用该对象的
void valueBound(HttpSessionBindingEvent event)方法
当对象从HttpSession对象中解除绑定时,web服务器调用该对象的void valueUnbound(HttpSessionBindingEvent event)方法
(2)HttpSessionActivationListener接口
实现了HttpSessionActivationListener接口的JavaBean对象可以感知自己被活化(反序列化)和钝化(序列化)的事件
当绑定到HttpSession对象中的javabean对象将要随HttpSession对象被钝化(序列化)之前,web服务器调用该javabean对象的
void sessionWillPassivate(HttpSessionEvent event) 方法。这样javabean对象就可以知道自己将要和HttpSession对象一起被序列化(钝化)到硬盘中.
当绑定到HttpSession对象中的javabean对象将要随HttpSession对象被活化(反序列化)之后,web服务器调用该javabean对象的
void sessionDidActive(HttpSessionEvent event)方法。这样javabean对象就可以知道自己将要和 HttpSession对象一起被反序列化(活化)回到内存中

9. 说说web.xml文件中可以配置哪些内容?


<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    <context-param>
        <param-name>nameparam-name>
        <param-value>ytuan996param-value>
    context-param>

    
    <error-page>
        <exception-type>exception-type>
        <error-code>500error-code>
        <location>error.jsplocation>
    error-page>
    
    <filter>
        
        <init-param>
            <param-name>param-name>
            <param-value>param-value>
        init-param>
        <filter-name>filter-name>
        <filter-class>filter-class>
    filter>

    
    <filter-mapping>
        <filter-name>filter-name>
        <url-pattern>url-pattern>
    filter-mapping>

    
    <listener>
        <listener-class>listener-class>
    listener>

    
    <servlet>
        <servlet-name>servlet-name>
        <servlet-class>servlet-class>
    servlet>

    
    <servlet-mapping>
        <servlet-name>servlet-name>
        <url-pattern>url-pattern>
    servlet-mapping>

    
    <welcome-file-list>
        <welcome-file>welcome-file>
    welcome-file-list>
web-app>

11. get和post的区别
本质上是无区别的,
在浏览器端,get一般由url调用,顺带一提url的限制也是浏览器的原因,事实上http标准协议对url的长度没有限制,而post一般由表单调用
在restful规范中,get被认为是幂等的,用来请求数据,而post不幂等,用来实现资源的创建
推荐阅读GET 和 POST 到底有什么区别?

12. cookie和session的区别?cookie和sessionStorage、localStroage之间的区别?
第一种回答:
图例:
面试专题之Java web编程_第6张图片
(1)session 在服务器端,cookie 在客户端(浏览器)
(2)session 默认被存在在服务器的一个文件里(不是内存)
(3)session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是(4)如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
(5)session 可以放在 文件、数据库、或内存中都可以。

用户验证这种场合一般会用 session 因此,维持一个会话的核心就是客户端的唯一标识,即 session id

第二种回答:
类似这种面试题,实际上都属于“开放性”问题,你扯到哪里都可以。不过如果我是面试官的话,我还是希望对方能做到一点——不要混淆 session 和 session 实现。
本来 session 是一个抽象概念,开发者为了实现中断和继续等操作,将 user agent 和 server 之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”,也就是 session 的概念。
而 cookie 是一个实际存在的东西,http 协议中定义在 header 中的字段。可以认为是 session 的一种后端无状态实现。而我们今天常说的 “session”,是为了绕开 cookie 的各种限制,通常借助 cookie 本身和后端存储实现的,一种更高级的会话状态实现。
所以 cookie 和 session,你可以认为是同一层次的概念,也可以认为是不同层次的概念。具体到实现,session 因为 session id 的存在,通常要借助 cookie 实现,但这并非必要,只能说是通用性较好的一种实现方案。

两种回答个人认为可以结合着来说,从代表会话的session(概念层面)到代表利用cookie实现的session(应用层面),并且结合着原理和实现来讲。

三者区别:
面试专题之Java web编程_第7张图片

13. session怎么保证多次访问是同一个ID?关闭了浏览器怎么办?
发送http请求时,消息头中会自动携带cookie信息,这其中就会包括SESSIONID信息,所以只要我们没有关闭浏览器,消息头中都会自动携带这个信息,以供服务器访问相应的session。 但是一旦关闭浏览器cookie中的JSESSIONID信息没有了,不会自动携带这个session信息了,服务器找不到对应的session,就会自动添加新的session,这个新添加的session显然不是我们需要的。这时就需要手动添加在cookie中添加JSESSIONID信息来防止关闭失效。

//在servletA中设置cookie
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();
        session.setAttribute("name", "张三");
        out.println("创建一个session并放入姓名属性");
        //手动添加cookie,保存JSESSIONID信息
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(60*30);//设置cookie的生命周期为30min
    相应 给浏览器一个 session id   
        response.addCookie(cookie);
    }


//在servletB中就可以正常访问session了
        public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        HttpSession httpSession = request.getSession();
        String name = (String) httpSession.getAttribute("name");
        out.println("name = "+name);
    }

14. 谈谈Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分别是做什么的?有什么区别?
Hibernate的对象有三种状态:瞬时态(transient)、持久态(persistent)和游离态(detached),瞬时态的实例可以通过调用save()、persist()或者saveOrUpdate()方法变成持久态;游离态的实例可以通过调用 update()、saveOrUpdate()、lock()或者replicate()变成持久态。save()和persist()将会引发SQL的INSERT语句,而update()或merge()会引发UPDATE语句。save()和update()的区别在于一个是将瞬时态对象变成持久态,一个是将游离态对象变为持久态。merge()方法可以完成save()和update()方法的功能,它的意图是将新的状态合并到已有的持久化对象上或创建新的持久化对象。对于persist()方法,按照官方文档的说明:① persist()方法把一个瞬时态的实例持久化,但是并不保证标识符被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时间;② persist()方法保证当它在一个事务外部被调用的时候并不触发一个INSERT语句,当需要封装一个长会话流程的时候,persist()方法是很有必要的;③ save()方法不保证第②条,它要返回标识符,所以它会立即执行INSERT语句,不管是在事务内部还是外部。至于lock()方法和update()方法的区别,update()方法是把一个已经更改过的脱管状态的对象变成持久状态;lock()方法是把一个没有更改过的脱管状态的对象变成持久状态。

15. 如何设置请求的编码以及响应内容的类型?
设置请求的编码:request.setCharacterEncoding(String)
例如:request.setCharacterEncoding(“utf-8”)
设置响应内容的类型:response.setContentType(String) or response.setHeader(String, String)
例如:response.setContentType(“text/html; charset=utf-8”)

16. Servlet相关接口 , Servlet里面有哪些方法 ? Servlet执行时一般实现哪几个方法?
(1)init() 方法
在 Servlet 的生命期中,仅执行一次 init() 方法。它是在服务器装入 Servlet 时执行的。 可以配置服务器,以在启动服务器或客户机首次访问 Servlet 时装入 Servlet。 无论有多少客户机访问 Servlet,都不会重复执行 init() 。
缺省的 init() 方法通常是符合要求的,但也可以用定制 init() 方法来覆盖它,典型的是管理服务器端资源。
(2)service() 方法
service() 方法是 Servlet 的核心。每当一个客户请求一个HttpServlet 对象,该对象的service() 方法就要被调用,而且传递给这个方法一个"请求"(ServletRequest)对象和一个"响应"(ServletResponse)对象作为参数。 在 HttpServlet 中已存在 service() 方法。缺省的服务功能是调用与 HTTP 请求的方法相应的 do 功能。
(3)doGet() 方法
当一个客户通过 HTML 表单发出一个 HTTP GET 请求或直接请求一个 URL 时,doGet() 方法被调用。与 GET 请求相关的参数添加到 URL 的后面,并与这个请求一起发送。当不会修改服务器端的数据时,应该使用 doGet() 方法。
(4)doPost() 方法
当一个客户通过 HTML 表单发出一个 HTTP POST 请求时,doPost() 方法被调用。与 POST 请求相关的参数作为一个单独的 HTTP 请求从浏览器发送到服务器。当需要修改服务器端的数据时,应该使用 doPost() 方法。
(5)destroy() 方法
destroy() 方法仅执行一次,即在服务器停止且卸装 Servlet 时执行该方法。典型的,将 Servlet 作为服务器进程的一部分来关闭。缺省的 destroy() 方法通常是符合要求的,但也可以覆盖它,典型的是管理服务器端资源。
(6)getServletConfig() 方法
getServletConfig() 方法返回一个 ServletConfig 对象,该对象用来返回初始化参数和 ServletContext。ServletContext 接口提供有关 servlet 的环境信息。
(7)getServletInfo() 方法
getServletInfo() 方法是一个可选的方法,它提供有关 servlet 的信息,如作者、版本、版权。

当服务器调用 sevlet 的 service()、doGet() 和 doPost() 这三个方法时,均需要 “请求”和“响应”对象作为参数。“请求”对象提供有关请求的信息,而“响应”对象提供了一个将响应信息返回给浏览器的一个通信途径。

执行过程中调用的方法:

public void init(ServletConfig config) 
public ServletConfig getServletConfig() 
public String getServletInfo() 
public void service(ServletRequest request,ServletResponse response) 
public void destroy()

17. Servlet 3中的异步处理指的是什么?

在Servlet 3中引入了一项新的技术可以让Servlet异步处理请求。有人可能会质疑,既然都有多线程了,还需要异步处理请求吗?答案是肯定的,因为如果一个任务处理时间相当长,那么Servlet或Filter会一直占用着请求处理线程直到任务结束,随着并发用户的增加,容器将会遭遇线程超出的风险,这种情况下很多的请求将会被堆积起来而后续的请求可能会遭遇拒绝服务,直到有资源可以处理请求为止。异步特性可以帮助应用节省容器中的线程,特别适合执行时间长而且用户需要得到结果的任务,如果用户不需要得到结果则直接将一个Runnable对象交给Executor并立即返回即可。

补充:多线程在Java诞生初期无疑是一个亮点,而Servlet单实例多线程的工作方式也曾为其赢得美名,然而技术的发展往往会颠覆我们很多的认知,就如同当年爱因斯坦的相对论颠覆了牛顿的经典力学一般。事实上,异步处理绝不是Serlvet 3首创,如果你了解Node.js的话,对Servlet 3的这个重要改进就不以为奇了。

下面是一个支持异步处理请求的Servlet的例子。

package chimomo.learning.java.code.jsp;
 
import javax.servlet.AsyncContext;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * @author Created by Chimomo
 */
@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
        // 开启Tomcat异步Servlet支持
        req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
 
        // 启动异步处理的上下文
        final AsyncContext ctx = req.startAsync();
 
        // ctx.setTimeout(30000);
        ctx.start(() -> {
            // 在此处添加异步处理的代码
            ctx.complete();
        });
    }
}

此题答案来自 Java - Servlet 3中的异步处理指的是什么?

18. servlet生命周期?servlet是单例模式么?为什么是单例?Servlet和cgi有什么区别?

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
(1)Servlet 通过调用 init () 方法进行初始化。
(2)Servlet 调用 service() 方法来处理客户端的请求。
(3)Servlet 通过调用 destroy() 方法终止(结束)。
(4)最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
面试专题之Java web编程_第8张图片
生命周期的方法详细解释可以参考 菜鸟教程部分

毫无疑问Servlet是单例的(默认情况下),具体来讲是收到以下几个因素的影响:
(1)是否在分布式环境中部署
(2)是否实现SingleThreadModel,如果实现则最多会创建20个实例
(3)在web.xml中声明了几次,即使同一个Servlet,如果声明多次,也会生成多个实例。

而它之所以是单例是因为tomcat代码中(StandardWrapper类)定义是单例的
具体分析过程参见Servlet到底是单例还是多例你了解吗?

还有一个问题关于Cgi,本人从来没听说过cgi故暂时不比较了。

19. 服务器收到用户提交的表单数据,到底是调用Servlet的doGet()还是doPost()方法?
HTML的

元素有一个method属性,用来指定提交表单的方式,其值可以是get或post。我们自定义的Servlet一般情况下会重写doGet()或doPost()两个方法之一或全部,如果是GET请求就调用doGet()方法,如果是POST请求就调用doPost()方法,那为什么这样呢?我们自定义的Servlet通常继承自HttpServlet,HttpServlet继承自GenericServlet并重写了其中的service()方法,这个方法是Servlet接口中定义的。HttpServlet重写的service()方法会先获取用户请求的方法,然后根据请求方法调用doGet()、doPost()、doPut()、doDelete()等方法,如果在自定义Servlet中重写了这些方法,那么显然会调用重写过的(自定义的)方法,这显然是对模板方法模式的应用。当然,自定义Servlet中也可以直接重写service()方法,那么不管是哪种方式的请求,都可以通过自己的代码进行处理,这对于不区分请求方法的场景比较合适。

20. servlet写过么,底层是怎么处理前台传来的请求的

(1)浏览器向服务器发出GET请求(请求服务器ServletA)
(2)服务器上的容器逻辑接收到该url,根据该url判断为Servlet请求,此时容器逻辑将产生两个对象:请求对象(HttpServletRequest)和响应对象(HttpServletResponce)
(3)容器逻辑根据url找到目标Servlet(本示例目标Servlet为ServletA),且创建一个线程A
(4)容器逻辑将刚才创建的请求对象和响应对象传递给线程A
(5)容器逻辑调用Servlet的service()方法
(6)service()方法根据请求类型(本示例为GET请求)调用doGet()(本示例调用doGet())或doPost()方法
(7)doGet()执行完后,将结果返回给容器逻辑
(8)线程A被销毁或被放在线程池中

其中需要注意的是:
(1)在容器中的每个Servlet原则上只有一个实例
(2)每个请求对应一个线程
(3)多个线程可作用于同一个Servlet(这是造成Servlet线程不安全的根本原因)
(4)每个线程一旦执行完任务,就被销毁或放在线程池中等待回收

不过上面都是浅析,要深究就要从tomcat原理层面说起,推荐阅读:Servlet工作原理

21. Servlet中如何获取用户提交的查询参数或表单数据?

三种方法:
(1)String str=request.getParameter("参数名称")方法可以获得参数值。
(2)String[] str=request.getParameterValues("参数名称")可以获得复选框类的数据
(3)Map map = request.getParameterMap(); 可以获得提交的全部数据。其中map的key是字符串类型,value是字符串数组类型!

22. Servlet中如何获取用户配置的初始化参数以及服务器上下文参数?

获取Servlet初始化参数:
(1)在Servlet中直接调用getinitparaneterr()方法来初始化参数
(2)通过ServletConfig借口的gerInitParameter()方法.
getServletConfig该方法定义在Servlet接口中,返回ServletConfig接口的引用,所有Servlet都继承了该方法.当容器实例化Servlet之前,会从web.xml中读取这个Servlet的初始化参数,并交给ServletConfig,然后再调用init方法时,容器会传送这个ServletConfig的引用到Servlet. 每个Servlet都会有一个ServletConfig引用.一旦有了ServletConfig的引用就可以调用getInitParameter方法来取得Servlet中设置的初始化参数

取得上下文初始化参数?
(1)servlet的ServletConfig对象拥有该servlet的ServletContext的一个引用,所以可这样取得上下文初始化参数:
getServletConfig().getServletContext().getInitParameter()
(2)也可以在Servlet中直接调用getServletContext().getInitParameter()

23. 登录功能如何保证安全性。(MD5+盐)为什么用MD5,讲一下机制。还有什么保证安全的加密方式?
信息摘要是把明文内容按照某种规则生成一段哈希值,即使明文信息改变了一点生成的结果也会完全不同,md5就是一种信息摘要的实现,可以把任意长度的明文生成长度为128位的哈希值
摘要哈希生成分三步:
(1)收集相关业务参数,在这里是金额和目标账户。当然,实际应用中的参数肯定比这多得多,这里只是做了简化。
(2)按照规则,把参数名和参数值拼接成一个字符串,同时把给定的密钥也拼接起来。之所以需要密钥,是因为攻击者也可能获知拼接规则。
(3)利用 MD5 算法,从原文生成哈希值。MD5 生成的哈希值是 128 位的二进制数,也就是 32 位的十六进制数。

除此之外还有Base64位加密(可加密解密)、sha1加密(加密不可逆)、AES加密(需要密钥才能解密)、RSA加密(公钥加密,私钥解密)

推荐阅读:漫画趣解MD5算法

24. 设计一个怎么使得验证码有效期,过了一段时间就过期了。
看存储在哪里,如果是cookie那就设置cookie的过期时间,如果是redis那就设置redis中值的过期时间。

25. 如何实现单点登录
这个要不会看大佬写的文章就完事了 单点登录(SSO)看这一篇就够了

我在这里只总结一下:
在同样一个顶域名下:
客户端将cookie的域设置为顶域,比如默认情况下cookie是属于a.baidu.com或者b.baidu.com的,改成baidu.com。 后端则可以使用Spring-Session共享会话。
在不同域下的登陆:
假设有登陆服务 SSO,用户访问另一个app服务,没有登陆,然后就跳转到SSO,SSO假设也没有登陆,然后输入账密开始登陆,成功后SSO记录好已经登陆的状态,并跳转到app服务(还携带了一个ST(Service Ticket)参数),app拿到st之后就去找sso服务进行验证,验证成功后就保存已登陆状态。

你可能感兴趣的:(面试)