servlet.listener

本文详细介绍了Servlet中的Listener机制,包括各种Listener接口及触发场景,并通过示例代码展示了如何使用这些Listener来跟踪在线用户数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JSP/Servlet 中的事件处理写过AWT或Swing程序的人一定对桌面程序的事件处理机制印象深刻:通过实现Listener接口的类可以在特定事件(Event)发生时,呼叫特定的方法来对事件进行响应。

其实我们在编写JSP/Servle程序时,也有类似的事件处理机制,所不同的是在JSP/Servlet中是在web.xml中注册Listener,由Container在特定事件发生时呼叫特定的实现Listener的类。

1. Servlet中的Listener和Event:

在JSP 2.0/Servlet 2.4中,共有八个Listener接口,六个Event类别。

l        ServletContextListener

[接口方法] contextInitialized()与 contextDestroyed() 
[接收事件] ServletContextEvent 
[触发场景] 在Container加载Web应用程序时(例如启动 Container之后),会呼叫contextInitialized(),而当容器移除Web应用程序时,会呼叫contextDestroyed ()方法。

l        ServletContextAttributeListener

[接口方法] attributeAdded()、 attributeReplaced()、attributeRemoved() 
[接收事件] ServletContextAttributeEvent 
[触发场景] 若有对象加入为application(ServletContext)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、attributeRemoved()。

l        HttpSessionListener

[接口方法] sessionCreated()与sessionDestroyed () 
[接收事件] HttpSessionEvent 
[触发场景] 在session(HttpSession)对象建立或被消灭时,会分别呼叫这两个方法。

l        HttpSessionAttributeListener

[接口方法] attributeAdded()、 attributeReplaced()、attributeRemoved() 
[接收事件] HttpSessionBindingEvent 
[触发场景] 若有对象加入为session(HttpSession)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、 attributeRemoved()。

l        ServletRequestListener

[接口方法] requestInitialized()与 requestDestroyed() 
[接收事件] RequestEvent 
[触发场景] 在request(HttpServletRequest)对象建立或被消灭时,会分别呼叫这两个方法。

l        ServletRequestAttributeListener

[接口方法] attributeAdded()、 attributeReplaced()、attributeRemoved() 
[接收事件] HttpSessionBindingEvent 
[触发场景] 若有对象加入为request(HttpServletRequest)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、 attributeRemoved()。

l        HttpSessionBindingListener

[接口方法] valueBound()与valueUnbound() 
[接收事件] HttpSessionBindingEvent 
[触发场景] 实现HttpSessionBindingListener接口的类别,其实例如果被加入至session(HttpSession)对象的属性中,则会呼叫 valueBound(),如果被从session(HttpSession)对象的属性中移除,则会呼叫valueUnbound(),实现HttpSessionBindingListener接口的类别不需在web.xml中设定。

l        HttpSessionActivationListener

[接口方法] sessionDidActivate()与 sessionWillPassivate() 
[接收事件] HttpSessionEvent 
[触发场景] Activate与Passivate是用于置换对象的动作,当session对象为了资源利用或负载平衡等原因而必须暂时储存至硬盘或其它储存器时(透过对象序列化),所作的动作称之为Passivate,而硬盘或储存器上的session对象重新加载JVM时所采的动作称之为Activate,所以容易理解的,sessionDidActivate()与sessionWillPassivate()分别于Activeate后与将Passivate前呼叫。

2. 注册监听器

除了HttpSessionBindingListener和HttpSessionActivationListener外,必须在web.xml中向容器注册,容器才会在对应的事件发生时呼叫对应的类别,如:

<listener>

<listener-class>

demo.servlet.listener.CustomServletContextListener

</listener-class>

</listener>



Listener是Servlet的监听器,它能够监听客户端的哀求、服务端的垄断等。穿越监听器,能够积极激励一些垄断,例如监听在线的用户的数量。当添置一个HttpSession时,就激励sessionCreated(HttpSessionEvent se)措施,这么就能够给在线人数加1。常用的监听接口有以下几个:

ServletContextAttributeListener监听对ServletContext属性的垄断,例如添置、剔除、修正属性。

ServletContextListener监听Servlet

 
 
Context。当创立ServletContext时,激励contextInitialized(ServletContextEvent sce)措施;当烧毁ServletContext时,激励contextDestroyed(ServletContextEvent sce)措施。

HttpSessionListener监听HttpSession的垄断。当创立一个Session时,激励session Created(HttpSessionEvent se)措施;当烧毁一个Session时,激励sessionDestroyed (HttpSessionEvent se)措施。

HttpSessionAttributeListener监听HttpSession中的属性的垄断。当在Session添置一个属性时,激励attributeAdded(HttpSessionBindingEvent se) 措施;当在Session剔除一个属性时,激励attributeRemoved(HttpSessionBindingEvent se)措施;当在Session属性被重新设置时,激励attributeReplaced(HttpSessionBindingEvent se) 措施。

下?**颐强⒁桓鱿枋档睦樱飧黾嗵髂芄黄詹樵谙叩娜耸T赟ervletContext初始化和烧毁时,在服务器扼制台打印对应的消息。当ServletContext里的属性添置、改换、剔除时,在服务器扼制台打印对应的消息。

要获得以上的功能,监听器定然告终以下3个接口:

HttpSessionListener

ServletContextListener

ServletContextAttributeListener

我们看翔实的代码,见示例14-9。

【过程源代码】

1 // ==================== Program Discription =====================
2 // 过程名目:示例14-9 : EncodingFilter .Java
3 // 过程目标:学习利用监听器
4 // ==============================================================
5 import javax.servlet.http.*;
6 import javax.servlet.*;
7
8 public class OnLineCountListener implements HttpSessionListener,
ServletContextListener,ServletContextAttributeListener
9 {
10 private int count;
11 private ServletContext context = null;
12
13 public OnLineCountListener()
14 {
15 count=0;
16 //setContext();
17 }
18 //创立一个session时激励
19 public void sessionCreated(HttpSessionEvent se)
20 {
21 count++;
22 setContext(se);
23
24 }
25 //当一个session失效时激励
26 public void sessionDestroyed(HttpSessionEvent se)
27 {
28 count--;
29 setContext(se);
30 }
31 //设置context的属性,它将激励attributeReplaced或attributeAdded措施
32 public void setContext(HttpSessionEvent se)
33 {
34 se.getSession().getServletContext().
setAttribute("onLine",new Integer(count));
35 }
36 //添置一个新的属性时激励
37 public void attributeAdded(ServletContextAttributeEvent event) {
38
39 log("attributeAdded('" + event.getName() + "', '" +
40 event.getValue() + "')");
41
42 }
43
44 //剔除一个新的属性时激励
45 public void attributeRemoved(ServletContextAttributeEvent event) {
46
47 log("attributeRemoved('" + event.getName() + "', '" +
48 event.getValue() + "')");
49
50 }
51
52 //属性被轮换时激励
53 public void attributeReplaced(ServletContextAttributeEvent event) {
54
55 log("attributeReplaced('" + event.getName() + "', '" +
56 event.getValue() + "')");
57 }
58 //context剔除时激励
59 public void contextDestroyed(ServletContextEvent event) {
60
61 log("contextDestroyed()");
62 this.context = null;
63
64 }
65
66 //context初始化时激励
67 public void contextInitialized(ServletContextEvent event) {
68
69 this.context = event.getServletContext();
70 log("contextInitialized()");
71
72 }
73 private void log(String message) {
74
75 System.out.println("ContextListener: " + message);
76 }
77 }

<think>我们正在处理一个关于Tomcat迁移到JakartaEE时出现的类型转换错误问题。具体错误是:`classorg.apache.jasper.servlet.JspServletcannotbecasttoclassjakarta.servlet.Servlet`。这个错误通常发生在从JavaEE迁移到JakartaEE的过程中,因为包名从`javax.servlet`改为了`jakarta.servlet`。`org.apache.jasper.servlet.JspServlet`是Tomcat中用于处理JSP的Servlet类,在迁移后,它应该实现`jakarta.servlet.Servlet`接口,而不是`javax.servlet.Servlet`。但是,错误信息表明类型转换失败,这意味着可能出现了类加载器问题或者类版本不匹配。###原因分析1.**类加载器隔离问题**:在Tomcat中,Web应用通常由单独的类加载器加载,而Tomcat自身的类(如JspServlet)由公共类加载器加载。如果Web应用的类加载器加载了JakartaServletAPI,而Tomcat内部仍然使用旧的`javax.servlet`版本,那么就会导致同一个接口在两个不同的类加载器中有不同的定义(一个是`javax.servlet.Servlet`,另一个是`jakarta.servlet.Servlet`)。因此,当尝试将Tomcat的`JspServlet`(实现`javax.servlet.Servlet`)转换为Web应用类加载器中的`jakarta.servlet.Servlet`时,由于它们被不同的类加载器加载,Java会认为它们是不同的类,从而抛出类型转换异常。2.**JakartaEE版本不匹配**:Tomcat版本可能尚未完全迁移到JakartaEE。例如,Tomcat10及以上版本已经将包名从`javax`迁移到了`jakarta`,而Tomcat9及以下仍然使用`javax`。因此,如果你在Tomcat10上运行,那么`JspServlet`应该已经实现了`jakarta.servlet.Servlet`。但如果你的应用是为JakartaEE9+(使用`jakarta`包)构建的,却部署在Tomcat9(使用`javax`包)上,就会出现这个问题。3.**依赖冲突**:项目可能同时包含了`javax.servlet`和`jakarta.servlet`的依赖,导致类加载混乱。###解决方案根据上述分析,我们可以采取以下步骤:####1.检查Tomcat版本-如果你使用的是Tomcat10或更高版本,那么它已经原生支持JakartaEE9+(包名是`jakarta.servlet`)。-如果你使用的是Tomcat9或更低版本,那么它只支持JavaEE(包名是`javax.servlet`)。在这种情况下,你需要将应用迁移回使用`javax.servlet`,或者升级Tomcat到版本10+。####2.确保依赖一致-确保你的项目中没有混合使用`javax.servlet`和`jakarta.servlet`的依赖。检查项目的构建文件(如Maven的pom.xml或Gradle的build.gradle),移除所有`javax.servlet`的依赖,并替换为JakartaEE对应的依赖。例如:```xml<!--对于JakartaEE9+--><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>5.0.0</version><scope>provided</scope></dependency>```####3.使用Tomcat10+如果还没有使用Tomcat10+,请升级。你可以从[ApacheTomcat官网](https://tomcat.apache.org/)下载Tomcat10或更高版本。####4.检查部署描述符确保你的`web.xml`(如果使用)中声明的ServletAPI版本与JakartaEE一致。例如,对于JakartaEE9,web.xml头部应该使用:```xml<web-appxmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaeehttps://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0">```####5.清理和重建在更改依赖和配置后,清理项目并重新构建,确保所有旧的`javax`类都被移除。###示例错误场景与解决假设你有一个使用Maven构建的项目,部署在Tomcat9上,但你的项目依赖了JakartaServletAPI5.0.0(包名为`jakarta.servlet`)。那么当Tomcat9尝试加载其内置的`JspServlet`(实现`javax.servlet.Servlet`)时,你的应用却期望它被转换为`jakarta.servlet.Servlet`,这就导致了类型转换错误。解决方案:将Tomcat升级到10+,或者将项目中的ServletAPI依赖改为`javax.servlet`(但这样你就不能使用JakartaEE的其他特性,如Servlet5.0+的新功能)。###总结迁移到JakartaEE时,确保应用服务器(如Tomcat)的版本与项目依赖的JakartaEE版本一致。Tomcat10+是支持JakartaEE9+的官方版本。同时,避免在项目中混用`javax`和`jakarta`的依赖。§§相关问题§§1.如何将现有的JavaEE项目迁移到JakartaEE?2.Tomcat10与Tomcat9的主要区别是什么?3.在迁移过程中如何处理其他JakartaEE组件(如JPA、EJB)?</think>### 解决Tomcat迁移到Jakarta EE时的JspServlet类型转换错误 #### 问题分析 当出现 `class org.apache.jasper.servlet.JspServlet cannot be cast to class jakarta.servlet.Servlet` 错误时,根本原因是 **Tomcat版本与Jakarta EE规范不匹配**: 1. **包名冲突**:Jakarta EE 9+ 将 `javax.servlet` 重命名为 `jakarta.servlet`,而旧版Tomcat(≤9.x)仍使用 `javax.*` 包 2. **类加载器隔离**:Tomcat的JspServlet实现仍为`javax.servlet.Servlet`,但应用期望`jakarta.servlet.Servlet` 3. **版本不兼容**:迁移工具可能未完全处理JSP引擎的适配 --- ### 解决方案 #### ✅ 方案1:升级Tomcat版本(推荐) **Jakarta EE 9+ 需要Tomcat 10+原生支持**: ```bash # 下载Tomcat 10.1.x+ wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.24/bin/apache-tomcat-10.1.24.tar.gz ``` 1. 确认`catalina.home`指向Tomcat 10+ 2. 检查`$CATALINA_HOME/lib`包含: - `jakarta.servlet-api-6.0.0.jar` - `tomcat-jasper.jar`(已适配jakarta) #### ✅ 方案2:使用兼容层工具 若需临时运行在Tomcat 9上: 1. 添加转换层依赖(Maven): ```xml <dependency> <groupId>org.eclipse.ee4j</groupId> <artifactId>jakartaee-migration</artifactId> <version>1.0.10</version> </dependency> ``` 2. 在应用启动时加载转换器: ```java @WebListener public class JakartaTransformer implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { new JavaxToJakartaTransformer().transform(sce.getServletContext()); } } ``` #### ✅ 方案3:重构项目依赖 1. 更新所有Servlet相关依赖: ```xml <!-- 替换前 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <!-- 替换后 --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <!-- Jakarta EE 10 --> </dependency> ``` 2. 执行包名全局替换: ```bash # 使用Eclipse Transformer工具 java -jar eclipse-transformer.jar ./my-webapp ``` #### ✅ 验证步骤 1. 检查JSP编译结果: ```bash $CATALINA_HOME/work/Catalina/localhost/myapp/org/apache/jsp/ # 应生成类似 index_jsp.class 文件 ``` 2. 反编译验证: ```java // 正确结果应包含: import jakarta.servlet.*; import jakarta.servlet.http.*; ``` --- ### 关键注意事项 1. **不可混合使用包**:禁止同时存在`javax.servlet`和`jakarta.servlet` 2. **插件兼容性**: - Maven WAR插件 ≥ 3.3.2 - 使用`maven-war-plugin`的`filterDeploymentDescriptor`配置 3. **工具链更新**: - Eclipse IDE 2023-12+(原生支持Jakarta) - IntelliJ插件 `Jakarta EE Tools` > **迁移路径参考**: > Tomcat 9(Java EE 8)→ Tomcat 10(Jakarta EE 9)→ Tomcat 11(Jakarta EE 11)[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值