JavaWEB相关面试题

什么是Servlet

狭义的 Servlet 是指Java语言实现的一个接口,广义的 Servlet 是指任何实现了这个 Servlet 接口的类,一般情况下,人们将 Servlet 理解为后者。
这里写图片描述
Servlet运行于支持 Java 的应用服务器中。WEB 容器才是与客户端直接打交道的家伙,它监听了端口,请求过来后,根据 url 等信息,确定要将请求交给哪个 Servlet 去处理,然后调用那个 Servletservice 方法,service 方法根据客户端的请求方式调用 do××() 方法,最后WEB 容器再把这个请求的响应返回给客户端。

说一下Servlet的体系结构。

所有的Servlet都必须要实现的核心的接口是javax.servlet.Servlet。每一个Servlet都必须要直接或者是间接实现这个接口,或者是继承javax.servlet.GenericServlet或者javax.servlet.http.HTTPServlet。最后,Servlet使用多线程可以并行的为多个请求服务。

Servlet 接口:定义了一个Servlet 应该具有的方法(如init、service 与destroy 方法等),所有的Servlet都应该直接或间接实现此接口。

GenericServlet 抽象类:通用Servlet,对Servlet 接口的默认实现,这是一个抽象类,其中的大部分方法都做了默认实现,只有service() 方法是一个抽象方法需要继承者自己实现。

HttpServlet 抽象类:对HTTP 协议进行了优化的Servlet,继承自GenericServlet 类,并且实现了其中的service() 抽象方法,默认的实现中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXX() 方法。通常我们编写Servlet 直接继承该抽象类即可。

解释下Servlet的生命周期。

  1. 加载Servlet 类,创建该类的实例。每一个用户都会产生一个新的线程(所以说Servlet 是线程不安全的)

  2. Servlet 通过init() 方法进行初始化

  3. Servlet 调用service(req,resp) 方法,根据请求方式调用对应的do××() 方法,来处理客户端的请求

  4. Servlet 通过destroy() 方法终止

  5. Servlet 被JVM 的垃圾回收机制收集

Servlet是线程安全的吗

不是,Servlet 在第一次被加载的时候创建,创建后就一直驻留在 WEb 容器为后续的请求提供服务,所以Servlet 默认是单例的。这也意味着在多线程的环境下会产生安全性问题。最好的解决办法就是不要在 Servlet 中创建实例变量。

这个问题可关联到 SpringMVC 中的 Controller 是否是线程安全的,原理是类似的。

doGet()方法和doPost()方法有什么区别?

  • GET 方法是默认的浏览器向Web 服务传递信息的方法,它会产生一个 很长的字符串,出现在浏览器的地址栏中。而POST 方式则是把数据作为一个单独的消息以标准输出的形式传到后台程序,所以使用POST 不会将数据显示在地址栏中。
  • 对于GET 方式,服务端用Request,QueryString 获取变量的值;对于POST 方式,服务端使用Request,Form 获取提交的数据。
  • GET 方式受传输数据字节的限制,POST 方式不受限制。

PS

关于上面这些知识点我以前写了一篇博文,有兴趣的可以看一下。

HTTP 响应的结构是怎么样的?

  • 状态行(Status Code):描述了响应的状态。可以用来检查是否成功的完成了请求。请求失败的情况下,状态码可用来找出失败的原因。
  • HTTP头部(HTTP Header):它们包含了更多关于响应的信息。比如:头部可以指定认为响应过期的过期日期,或者是指定用来给用户安全的传输实体内容的编码格式。
  • 主体(Body):它包含了响应的内容。它可以包含HTML代码,图片,等等。主体是由传输在HTTP消息中紧跟在头部后面的数据字节组成的。

HTTP 协议是非常重要的协议,理解了 HTTP 协议能解决好多疑问。

sendRedirect()forward()方法有什么区别?

  • sendRedirect()重定向:客户端发送两次请求,重定向(redirect)以后,之前请求作用域范围以内的对象就失效了,因为会产生一个新的请求,地址栏也会发生变化。
  • forward()转发:客户端只发送一次请求,转发(forwarding)以后,之前请求作用域范围以内的对象仍然可以访问,地址栏不会发生变化。

什么是URL编码和URL解码?

URL编码是负责把URL里面的空格和其他的特殊字符替换成对应的十六进制表示,反之就是解码。

  • 可以用URLEncoder.encoder(String url,String encoder)方法进行URL编码
  • URLDecoder.decode(String url,String encoder)方法进行URL解码

JSP请求是如何被处理的?

浏览器首先要请求一个以.jsp扩展名结尾的页面,发起JSP请求,然后,Web服务器读取这个请求,使用JSP编译器把JSP页面转化成一个Servlet类。

需要注意的是,只有当第一次请求页面或者是JSP文件发生改变的时候JSP文件才会被编译,然后服务器调用Servlet类,处理浏览器的请求。一旦请求执行结束,Servlet会把响应发送给客户端。

jdk动态代理与CGLIB动态代理的区别

jdk 动态代理:jdk 中的动态代理是通过反射类 Proxy 以及 InvocationHandler 回调接口实现的。有一点需要注意的是,被代理的对象必须是接口的实现类,也就是说只能对该类所有实现接口的方法进行动态织入,因此存在着一定的局限性。

CGLIB 动态代理:CGLIB 会动态的为一个类生成一个代理的子类,子类重写要代理的类的所有不是 final 的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。因为 CGLIB 使用字节码处理框架 ASM,来转换字节码并生成新的类,所以它比使用 java 反射的 jdk 动态代理要快。

Spring IoC 容器的优点

IoC 容器把对象的依赖关系有序的建立起来,简化了对象依赖关系的管理,在很大程度上简化了面向对象系统的复杂性。

IoC 容器可以把资源的获取方向反转,让IoC 容器主动管理这些依赖关系,将这些关系注入到组件中,可以使依赖关系的适配和管理变得更加灵活。

如果合作对象的引用或依赖关系的管理由具体对象来完成,会导致代码的高度耦合和可测试性降低,这对复杂的面向对象系统的设计是非常不利的。有了IoC 容器之后,这些依赖关系可以通过把对象的依赖注入交给框架或者IoC 容器来完成,这种从具体对象手中交出控制的做法是非常有价值的,它可以在解耦代码的同时提高代码的可测试性。

猜你喜欢

转载自blog.csdn.net/codejas/article/details/80469066