Servlet的一些面试知识点

1.提出问题

2.问题一:Servlet和Jsp为什么是一个东西?用类之间的关系来说明。

这是一个用于简单计算的Jsp页面,如下图:

Jsp文件首先翻译为Java文件,再将java文件编译为class文件,最后执行class文件。Jap翻译的Java文件如下图:

 在Java文件中可以看到如下重要代码:

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports{
}

可以看到index_jsp类继承了HttpJspBase类,使用API查看HttpJspBase类源码:

 

可以看到官方文档显示HttpJspBase继承HttpServlet,所以由此说明Jsp和Servlet是同一个东西,且Servlet是Jsp的父类。

3.问题二: 怎么样才可以让servlet在服务器启动时实例化。并且那个标签中的数字大或小有什么意义?

 使用<load-on-startup>标签使servlet在服务器启动时实例化。

标签内的的数字代表执行的先后次序,越小越先执行

修改web.xml文件:

    <servlet>
        <servlet-name>DoComputerServlet</servlet-name>
        <servlet-class>com.wpf.jsp.servlet.DoComputerServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

启动服务器不发送请求:

尝试多个servlet自动实例化修改web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>comm</param-name>
        <param-value>全局变量</param-value>
    </context-param>
    <servlet>
        <servlet-name>DoComputerServlet</servlet-name>
        <servlet-class>com.wpf.jsp.servlet.DoComputerServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DoComputerServlet</servlet-name>
        <url-pattern>/doComputer</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>OtherServlet</servlet-name>
        <servlet-class>com.wpf.jsp.servlet.OtherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>OtherServlet</servlet-name>
        <url-pattern>/doOther</url-pattern>
    </servlet-mapping>
</web-app>

 重新启动服务器不发送请求:

4.问题三:说明servlet的生命周期。方法的先后调用?

 首先自创建的DoComputerServlet类继承了HttpServlet类,其中父类存在的一些关于Servlet生命周期的方法,如下代码:

package com.wpf.jsp.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class DoComputerServlet extends HttpServlet {
	//服务方法
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}

	//服务方法
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doPostInit");
		Double num1 = Double.parseDouble(request.getParameter("num1"));
		Double num2 = Double.parseDouble(request.getParameter("num2"));
		String op = request.getParameter("op");
		Double num3 = null;
		if ("+".equals(op)) {
			num3 = num1 + num2;
		} else if ("-".equals(op)) {
			num3 = num1 - num2;

		} else if ("*".equals(op)) {
			num3 = num1 * num2;

		} else {
			if (num2 != 0)
				num3 = num1 / num2;
		}
		request.setAttribute("num3", num3);
		request.getRequestDispatcher("index.jsp").forward(request, response);
	}

	//摧毁方法
	@Override
	public void destroy() {
		System.out.println("DoComputerServletDestroy");
	}

	//初始方法
	@Override
	public void init() throws ServletException {
		System.out.println("DoComputerServletInit");
	}

	//构造方法
	public DoComputerServlet() {
		System.out.println("DoComputerServletConstructor");
	}
}

分别有服务方法,构造方法,初始方法,摧毁方法中添加了输出。启动服务器,并发送多次请求,关闭游览器后重新打开游览器访问,最后关闭服务。命令台的输出为如下图:

 可以看出Servlet的生命周期中,实例化一次初始化一次,服务多次,销毁一次

5.问题四:servlet是线程安全的吗﹖为什么请说明?

浏览器每发送一次请求,服务器提供一个线程去控制请求数据,所以在这次请求中request的数据是线程安全的。

对于动用servlet中的属性值时是不安全的。

Servlet不是线程安全的。

要解释为什么Servlet为什么不是线程安全的,需要了解Servlet容器(即Tomcat)使如何响应HTTP请求的。

当Tomcat接收到Client的HTTP请求时,Tomcat从线程池中取出一个线程,之后找到该请求对应的Servlet对象并进行初始化,之后调用service()方法。要注意的是每一个Servlet对象再Tomcat容器中只有一个实例对象,即是单例模式。如果多个HTTP请求请求的是同一个Servlet,那么着两个HTTP请求对应的线程将并发调用Servlet的service()方法。

上图中的Thread1和Thread2调用了同一个Servlet1,所以此时如果Servlet1中定义了实例变量或静态变量,那么可能会发生线程安全问题(因为所有的线程都可能使用这些变量)。

 servlet不是线程安全的

6.问题五:如何在多个servlet中共享配置的数据,用哪个标签?

首先在web.xml中修改代码:

    <servlet>
        <servlet-name>DoComputerServlet</servlet-name>
        <servlet-class>com.wpf.jsp.servlet.DoComputerServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>DoComputerServlet</servlet-name>
        <url-pattern>/doComputer</url-pattern>
    </servlet-mapping>

 修改DoComputerServlet代码:

//初始方法
	@Override
	public void init() throws ServletException {
		String encoding = this.getInitParameter("encoding");
		System.out.println("DoComputerServletInit————encoding" + encoding);
	}

启动服务器发送请求输出结果:

 生成另有一个Servlet

package com.wpf.jsp.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class OtherServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doPost");
	}

	public OtherServlet() {
		System.out.println("OtherServletConstructor");
	}

	@Override
	public void destroy() {
		System.out.println("OtherServletDestroy");
	}

	@Override
	public void init() throws ServletException {
		String encoding = this.getInitParameter("encoding");
		System.out.println("OtherServletInit————encoding" + encoding);
	}
}

 重新启动发送请求:

OtherServlet无数据

 在web.xml中加入全局变量

    <context-param>
        <param-name>comm</param-name>
        <param-value>全局变量</param-value>
    </context-param>

修改Servlet

//初始方法
	@Override
	public void init() throws ServletException {
		String encoding = this.getInitParameter("encoding");
		System.out.println("DoComputerServletInit————encoding" + encoding);

		String comm = this.getServletContext().getInitParameter("comm");
		System.out.println("DoComputerServletInit————comm" + comm);
	}
@Override
	public void init() throws ServletException {
		String encoding = this.getInitParameter("encoding");
		System.out.println("OtherServletInit————encoding" + encoding);
		String comm = this.getServletContext().getInitParameter("comm");
		System.out.println("OtherServletInit————comm" + comm);
	}

 重启服务器并发送请求:

 多个servlet中共享配置的数据,使用<context-param>标签。

7.问题六:代码实现来说明,filter, servlet,ServletContextListener这三个的启动顺序。

新建一个Filter:

package com.wpf.jsp.filter;

import com.wpf.jsp.domain.User;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class MyFilter implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("MyFilterInit");
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		filterChain.doFilter(servletRequest, servletResponse);
	}

	@Override
	public void destroy() {
		System.out.println("MyFilterDestroy");
	}
}

新建一个Listener:

package com.wpf.jsp.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.ArrayList;
import java.util.List;

public class MyListener implements ServletContextListener {
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		List<String> strings = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			strings.add("abc" + i);
		}
		System.out.println("context---init---");
		ServletContext application = sce.getServletContext();
		application.setAttribute("strings", strings);
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("contextDestroyed");
	}
}

 修改web.xml:

    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.wpf.jsp.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <listener>
        <listener-class>com.wpf.jsp.listener.MyListener</listener-class>
    </listener>

 重启服务器:

  

8.问题七:代码实现监听session属性添加了,或session属性删除了。

新建一个Listener:

package com.wpf.jsp.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener {
	@Override
	public void attributeAdded(HttpSessionBindingEvent se) {
		System.out.println("attributeAdded");
	}

	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) {
		System.out.println("attributeRemoved");
	}

	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) {
		System.out.println("attributeReplaced");
	}

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		System.out.println("sessionCreated");
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		System.out.println("sessionDestroyed");
	}
}

修改web.xml:

<listener>
        <listener-class>com.wpf.jsp.listener.SessionListener</listener-class>
    </listener>

修改servlet:

修改jsp:

  

 重启服务器发送请求:

9.问题八:请实现,tomcat启动时,将数据库中用户表中的所有数据,缓存在系统的userList中。

新建一个Listener:

package com.wpf.jsp.listener;

import com.wpf.jsp.domain.User;
import com.wpf.jsp.service.UserService;
import com.wpf.jsp.service.impl.UserServiceImpl;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.List;

public class UserListListener implements ServletContextListener {
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		UserService userService = UserServiceImpl.getUserService();
		List<User> users = userService.get();
		sce.getServletContext().setAttribute("users", users);
	}
}

修改web.xml:

    <listener>
        <listener-class>com.wpf.jsp.listener.UserListListener</listener-class>
    </listener>

 修改index.jsp:

<%
            List<User> userList = (List<User>) request.getServletContext().getAttribute("users");
            for (User user : userList) {
        %>
        <tr align="center">
            <td><%=user.getId()%>
            </td>
            <td><%=user.getUserName()%>
            </td>
            <td><%=user.getPassword()%>
            </td>
        </tr>
        <%
            }
        %>

 运行服务器:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值