Java web 面试题
什么是Servlet?狭义的 Servlet 是指Java语言实现的一个接口,广义的 Servlet 是指任何实现了这个 Servlet 接口的类,一般情况下,人们将 Servlet 理解为后者。Servlet运行于支持 Java 的应用服务器中。WEB 容器才是与客户端直接打交道的家伙,它监听了端口,请求过来后,根据 url 等信息,确定要将请求交给哪个 Servlet 去处理,然后...
什么是Servlet
?
狭义的 Servlet
是指 Java 语言实现的一个接口,广义的 Servlet
是指任何实现了这个 Servlet
接口的类,一般情况下,人们将 Servlet
理解为后者。
Servlet
运行于支持 Java 的应用服务器中。WEB 容器才是与客户端直接打交道的家伙,它监听了端口,请求过来后,根据 url
等信息,确定要将请求交给哪个 Servlet
去处理,然后调用那个 Servlet
的 service
方法,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
的生命周期。
加载
Servlet
类,创建该类的实例。每一个用户都会产生一个新的线程 (所以说Servlet
是线程不安全的)Servlet
通过init()
方法进行初始化Servlet
调用service(req,resp)
方法,根据请求方式调用对应的do××()
方法,来处理客户端的请求Servlet
通过destroy()
方法终止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 容器来完成,这种从具体对象手中交出控制的做法是非常有价值的,它可以在解耦代码的同时提高代码的可测试性。
更多推荐
所有评论(0)