Servlet结构&JSP的生命周期&JSP和Servlet关系
介绍Servlet结构
Servlet继承树中各类型|接口的特性
Servlet接口
- init(ServletConfig config),创建Servlet对象后立即调用该方法完成其他初始化工作。
- service(ServletReuquest req,ServletResponse resp),处理客户端请求,执行业务操作,利用响应对象响应客户端请求。
- destroy(),在销毁Servlet对象之前调用该方法,释放资源。
- getServletConfig(),ServletConfig是容器向servlet传递参数的载体。
- getServletInfo(),获取servlet相关信息。
GenericServlet抽象类
- 定义了一个通用的,不依赖于具体协议的Servlet,给出了除service()方法外的其余四个方法的实现。
- public void init(ServletConfig config) thows SerletExcepiton
- protected void init() thows SerletExcepiton
- 第一个是servlet接口的init(),调用第二个init(), 重写第二个init()即可
HttpServlet
- 继承自 GenericServlet. 针对于处理 HTTP 协议的请求所定制。
- public void service(ServletRequest req, ServletResponse res)
- protected void service(HttpServletRequest req, HttpServletResponse res)
- protected void doGet(request,response)
- protected void doPost(request,response)
- public service()是父类的方法,protected service()是自己的方法。前者首先把参数分别转换为HttpServletRequest和HttpServletResponse ,再调用protected service();protected service()根据HTTP请求方法的类型调用相应doXXX()方法
- 我们自己编写的servlet应该继承HttpServlet,一般要覆盖doPost或者doGet方法/service。
JSP和Servlet关系
JSP 本质上是 Servlet 的一种简单形式
JSP 是一种技术,允许使用静态数据和带有特殊标记的动态数据混合编写动态 HTTP 响应
Servlet 是一种允许您使用 Java 类编写动态 HTTP 响应的技术
但是实现大多数 JSP 服务器(容器)是为了支持作为 Servlet 技术扩展的 JSP 技术。JSP 页面在执行之前首先在内部转换为 Servlet 类
Servlet | JSP |
---|---|
Servlet 是一个 java 代码 | JSP是一个基于 html 的代码 |
servlet 编写代码比 JSP 更难,因为它是 java 中的 html | JSP 很容易编码,因为它是 html 中的 java |
在 MVC 方法中,Servlet 扮演着controller的角色 | JSP是MVC方法中显示输出的view |
Servlet 比 JSP 快 | JSP 比 Servlet 慢,因为 JSP 生命周期的第一步是将 JSP 转换为 java 代码,然后进行编译 |
Servlet 可以接受所有协议请求 | JSP 只接受 http 请求 |
在 Servlet,我们可以覆盖 service ()方法 | 在 JSP 中,我们不能覆盖它的 service ()方法 |
在 Servlet 中,默认的session 管理是不启用的,用户必须显式地启用它 | 在 JSP session 管理是自动启用的 |
在 Servlet 中,我们必须在一个 Servlet 文件中实现业务逻辑和表示逻辑之类的所有东西 | 在 JSP 中,业务逻辑通过 javabean 表示逻辑分离 |
修改在 Servlet 是一项耗时的任务,因为它包括重新加载、重新编译和重新启动服务器 | JSP 修改速度很快,只需点击刷新按钮即可 |
JSP的生命周期
编译阶段: servlet容器编译servlet源文件,生成servlet类
初始化阶段: 加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法
执行阶段: 调用与JSP对应的servlet实例的服务方法
销毁阶段: 调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例
延申
Filter
过滤器是在请求的预处理和后处理中调用的对象
Servlet 过滤器是可插拔的,也就是说它的条目是在 web.xml 文件中定义的,如果我们从 web.xml 文件中删除 filter 的条目,过滤器将自动删除,我们不需要更改 servlet,因此,维护成本将减少
主要作用:
- 将请求参数记录到日志文件
- 资源请求的身份验证和自动化
- 在将请求体或头发送到 servlet 之前对其进行格式化
- 压缩发送到客户机的响应数据
- 通过添加一些 cookie、头信息等来改变响应
过滤器的生命周期
初始化方法:public void init(FilterConfig filterConfig);
拦截请求方法:public void doFilter
销毁方法:public void destroy();
Listener
类似于前端的事件绑定,java中的监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等
与 servlet 的配置一样,过滤器位于 web.xml 内部,类似的侦听器也在 web.xml 内部使用 < listener > 标记配置
Request
- ServletRequestListener (处理request对象创建和销毁)
- ServleRequestAttributeListener (处理域对象中的数据添加 替换 删除)
Session
- HttpSessionListener (处理session对象创建和销毁)
- HttpSessionAttributeListener 处理session域对象中的数据添加 修改 删除)
- HttpSessionBindingListener (处理session对象监听器绑定和解绑定接口)
- HttpSessionActivationListener (处理session对象钝化和活化状态接口)
Application
- ServletContextListener (处理application对象创建和销毁)
- ServletContextAttributeListener (处理application域对象中的数据添加 修改 删除)
filter&listener区别
过滤器用于预处理和后处理请求
过滤器就像一个水过滤器,其中传入(请求)和传出(响应)值将被过滤
监听器类似于触发器,可以附加到应用程序服务器中的事件(让我们在这里使用术语容器)。使用监听器,您可以跟踪应用程序级别、会话级别、生命周期更改、属性更改等。实现的接口是 javax.servlet。监听器接口
监听器就像倾听(触发器)——无论何时需要,我都会被执行
责任链设计模式
使用责任链模式来实现松散耦合,将客户端的请求传递给对象链来处理它们。稍后,链中的对象将自己决定谁将处理请求,以及是否需要将请求发送到链中的下一个对象
什么时候使用责任链设计模式?
- 当需要解耦请求的发送方和接收方时
- 在运行时确定的多个对象是处理请求的候选对象
- 当不希望在代码中显式指定处理程序时
- 当您希望向几个对象中的一个发出请求而不显式指定接收方时
当多个对象可以处理一个请求且处理程序不必是特定对象时,建议使用此模式。此外,处理程序是在运行时确定的。请注意,没有被任何处理程序处理的请求是有效的用例
优点
- 为了降低耦合度,解耦将要求发送方和接收方
- 简化对象。对象不需要知道链的结构
- 提高对象分配职责的灵活性。通过更改链中的成员或更改其顺序,允许动态地添加或删除责任
- 增加请求处理的新类很方便
缺点
- 请求必须被接收,不能保证
- 系统的性能会受到影响,而且在代码调试中也不容易导致循环调用
- 可能不容易观察到操作的特点,由于调试
观察者设计模式
当对象之间存在一对多关系时,如果一个对象被修改,它的观察者模式对象将被自动通知。观察者模式属于行为模式的范畴
在观察者模式中,有许多观察者(订阅者对象)正在观察一个特定的主题(发布者对象)。观察者在一个主题上注册,以便在该主题发生变化时得到通知
Filter和Interceptor的异同
Filter是 web 服务器的一部分,而不是 Spring 框架。我们可以使用过滤器来操作甚至阻止传入请求的请求到达任何 servlet。反之亦然,我们也可以阻止响应到达客户端
Handlerinterceptor 是 Spring MVC 框架的一部分,位于 DispatcherServlet 和我们的控制器之间。我们可以在请求到达控制器之前拦截请求,在视图呈现之前和之后拦截请求
Filter在请求到达 DispatcherServlet 之前截获它们,使它们成为粗粒度任务的理想选择,例如:
- 认证
- 日志记录和审计
- 图片和数据压缩
- 任何我们希望从 springmvc 解耦的功能
另一方面,HandlerIntercepors 拦截调度 servlet 和我们的控制器之间的请求。这是在 Spring MVC 框架内完成的,提供了对 Handler 和 ModelAndView 对象的访问。这样可以减少重复,并允许更细粒度的功能,例如:
- 处理横切关注点,例如应用程序日志记录
- 详细的授权检查
- 操作 Spring 上下文或模型
Spring AOP概念
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
SpringAOP实现方式
Schema-based
Aspectj
相同点
在不修改源码的情况下都能实现功能的扩展
不同点
- SchemaBased方式基于接口来区别前置和后置和环绕和异常通知的,而AspectJ方式是在配置文件中使用标签来区分。
- AspectJ方式在配置中的配置方式发现其切点的声明以及对应的通知组装中,切点只在Aop:aspect标签下有效。而SchemaBased方式声明的切点在全局有效.SchemaBased的切点的通用性比AspectJ方式要好。
- AspectJ方式扩展涉及参数的流程:
- 切点方法中声明形参完成数据处理
- 修改通知方法声明形参接收对应的实参
- 修改配置文件中的切点声明,切点中的方法上声明对应的参数类型。同时还要声明参数的形参名
- 在通知的配置上声明参数名
- 在SchemaBased方式涉及形参的流程:
- 在切点方法上声明形参完成功能处理
- 在配置文件中修改切点的路径为带有参数的切点
- 直接在通知方法中的形参中的Object[]中获取参数使用即可
总结:不涉及到参数问题使用AspectJ方式完成功能扩展比较方便,但是涉及到参数后使用SchemaBased方式比较方便
代理设计模式
代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象
为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问
代理模式分为静态代理、动态代理【JDK动态代理、CGLIB动态代理】
代理模式的角色
- 抽象的类或者接口–定义完成一件怎样的事情
- 代理对象—完成这件事情的对象,直接面向用户的
- 被代理对象–完成事件背后的隐藏内容,用户看不到
动态代理|静态代理
静态代理
这种代理方式需要代理对象和目标对象实现一样的接口
优点:可以在不修改目标对象的前提下扩展目标对象的功能
缺点:
- 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类
- 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改
动态代理
JDK动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成
JDK动态代理存在的问题
JDK代理的产生必须要实现对应的接口的,如果没有对应的接口,这个时候代理对象就没有办法产生
解决方案:CGLIB动态代理
CGLIB动态代理
此处引用代理模式
CGLIB是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展
CGLIB特点
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
- 如果想代理没有实现接口的类,就可以使用CGLIB实现。
- CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。
- 它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
- CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
- 不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLIB与动态代理最大的区别就是
- 使用动态代理的对象必须实现一个或多个接口
- 使用CGLIB代理的对象则无需实现接口,达到代理类无侵入。