struts2 框架写的代码中,有个监听继承ServletContextListener

struts2 框架写的代码中,有个监听继承ServletContextListener,第1张

在 Servlet

API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。

当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由ServletContextListener 来处理。在 ServletContextListener 接口中定义了处理ServletContextEvent 事件的两个方法

Java代码

/**

* 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,

* 并且对那些在Web 应用启动时就需拆核要被初始化的Servlet 进行初始化。

*/

contextInitialized(ServletContextEvent sce)

/**

* 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。

*/

contextDestroyed(ServletContextEvent sce)

下面通过两个具体的例子来介绍 ServletContextListener 的用法。

例一:在服务启动时,将数据库中的数据加载进内存,并将其赋值给一个属性名,其它的 Servlet 就可以通过 getAttribute 进行属性值的访问。

有如下两个步骤:

1 : ServletContext 对象是一个为整个 web 应用提供共享的内存,任何请求都可以访问里面的内容

2 :如何实现在服务启动的时候就动态的加入到里面的内容:我旅模掘们需要做的有:

1 ) 实现 servletContextListerner 接口 并将要共享的通过 setAttribute ( name,data )方法提交到内存中去 ;

2 )应用项目通过 getAttribute(name) 将数据取到 。

Java代码

public class ServletContextLTest implements ServletContextListener{

// 实现其中的销码派毁函数

public void contextDestroyed(ServletContextEvent sce) {

System.out.println("this is last destroyeed")

}

// 实现其中的初始化函数,当有事件发生时即触发

public void contextInitialized(ServletContextEvent sce) {

ServletContext sct=sce.getServletContext()

Map<Integer,String>depts=new HashMap<Integer,String>()

Connection connection=null

PreparedStatement pstm=null

ResultSet rs=null

try{

connection=ConnectTool.getConnection()

String sql="select deptNo,dname from dept"

pstm=connection.prepareStatement(sql)

rs=pstm.executeQuery()

while(rs.next()){

depts.put(rs.getInt(1), rs.getString(2))

}

// 将所取到的值存放到一个属性键值对中

sct.setAttribute("dept", depts)

System.out.println("======listener test is beginning=========")

}catch(Exception e){

e.printStackTrace()

}finally{

ConnectTool.releasersc(rs, pstm, connection)

}

}

}

在完成上述编码后,仍需在 web.xml 中进行如下配置,以使得该监听器可以起作用。

Xml代码

<listener>

<listener-class>ServletContextTest.ServletContextLTest</listener-class>

</listener>

在完成上述配置后, web 服务器在启动时,会直接加载该监听器,通过以下的应用程序就可以进行数据的访问。

Java代码

public class CreateEmployee extends HttpServlet{

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

ServletContext sct=getServletConfig().getServletContext()

// 从上下文环境中通过属性名获取属性值

Map<Integer,String>dept=(Map<Integer,String>)sct.getAttribute("dept")

Set<Integer>key=dept.keySet()

response.setContentType("text/htmlcharset=utf-8")

PrintWriter out=response.getWriter()

out.println("<html>")

out.println("<body>")

out.println("<form action='/register' action='post'>")

out.println("<table alignb='center'>")

out.println("<tr>")

out.println("<td>")

out.println("username:")

out.println("</td>")

out.println("<td>")

out.println("<input type='text' name='username'")

out.println("</tr>")

out.println("<tr>")

out.println("<td>")

out.println("city:")

out.println("</td>")

out.println("<td>")

out.println("<select name='dept'")

for(Integer i:key){

out.println("<option value='"+i+"'>"+dept.get(i)+"</option>")

}

out.println("</select>")

out.println("</td>")

out.println("<tr>")

out.println("</table>")

out.println("</form>")

out.println("</body>")

out.println("</html>")

out.flush()

}

}

例二:书写一个类用于统计当Web 应用启动后,网页被客户端访问的次数。如果重新启动Web 应用,计数器不会重新从1 开始统计访问次数,而是从上次统计的结果上进行累加。

在实际应用中,往往需要统计自Web 应用被发布后网页被客户端访问的次数,这就要求当Web 应用被终止时,计数器的数值被永久存储在一个文件中或者数据库中,等到Web 应用重新启动时,先从文件或数据库中读取计数器的初始值,然后在此基础上继续计数。

向文件中写入或读取计数器的数值的功能可以由自定义的 MyServletContextListener 类来完成,它具有以下功能:

1 、在 Web 应用启动时从文件中读取计数器的数值,并把表示计数器的 Counter 对象存放到 Web应用范围内。存放计数器的文件的路径为helloapp/count/count.txt 。

2 、在Web 应用终止时把Web 应用范围内的计数器的数值保存到count.txt 文件中。

Java代码

public class MyServletContextListener implements ServletContextListener{

public void contextInitialized(ServletContextEvent sce){

System.out.println("helloapp application is Initialized.")

// 获取 ServletContext 对象

ServletContext context=sce.getServletContext()

try{

// 从文件中读取计数器的数值

BufferedReader reader=new BufferedReader(

new InputStreamReader(context.

getResourceAsStream("/count/count.txt")))

int count=Integer.parseInt(reader.readLine())

reader.close()

// 创建计数器对象

Counter counter=new Counter(count)

// 把计数器对象保存到 Web 应用范围

context.setAttribute("counter",counter)

} catch(IOException e) {

e.printStackTrace()

}

}

public void contextDestroyed(ServletContextEvent sce){

System.out.println("helloapp application is Destroyed.")

// 获取 ServletContext 对象

ServletContext context=sce.getServletContext()

// 从 Web 应用范围获得计数器对象

Counter counter=(Counter)context.getAttribute("counter")

if(counter!=null){

try{

// 把计数器的数值写到 count.txt 文件中

String filepath=context.getRealPath("/count")

filepath=filepath+"/count.txt"

PrintWriter pw=new PrintWriter(filepath)

pw.println(counter.getCount())

pw.close()

} catch(IOException e) {

e.printStackTrace()

}

}

}

}

将用户自定义的 MyServletContextListener 监听器在 Servlet 容器进行注册, Servlet 容器会在启动或终止 Web 应用时,会调用该监听器的相关方法。在 web.xml 文件中, <listener>元素用于向容器注册监听器:

Xml代码

<listener>

<listener-class>ServletContextTest .MyServletContextListener<listener-class />

</listener>

通过上述两个例子,即可以非常清楚的了解到 ServletContextListener 接口的使用方法及技巧。

在Container 加载Web 应用程序时(例如启动 Container 之后),会呼叫contextInitialized() ,而当容器移除Web 应用程序时,会呼叫contextDestroyed

() 方法。

通过 Tomcat 控制台的打印结果的先后顺序,会发现当 Web 应用启动时,Servlet 容器先调用contextInitialized() 方法,再调用lifeInit 的init() 方法;

当Web 应用终止时,Servlet 容器先调用lifeInit 的destroy() 方法,再调用contextDestroyed() 方法。

由此可见,在Web 应用的生命周期中,ServletContext 对象最早被创建,最晚被销毁。

org.springframeword.web.cotext.ContextLoaderlistener

spring的监听器,并不是下载的。是在你自卜闷己下汪行的jar包型陵弯中copy到的路径的

在Java Web项目中,经常要在项目开始运行时启动一个线程,每隔一定的时间就老让敬运行一定的代码,比如扫描数据库的变化等等。要实现这个功能,可以现在侍慎web.xml文件中定义滑唤一个Listener,然后在这个Listener中启动一个线程,在线程里面实现功能。

1. 自定义Listener

在Struts+Spring+Hibernate的Web项目中,web.xml里面一般都会有这样的代码:

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

这几句代码使得Web项目的容器(也就是Web服务器,比如Tomcat)在项目启动时实例化了一个org.springframework.web.context.ContextLoaderListener类。

类似的,我们也可以在web.xml里面自己定义一个Listener,让Web服务器去实例化:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

<filter>

<filter-name>struts2</filter-name>

<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>

</filter>

<filter-mapping>

<filter-name>struts2</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<listener>

<listener-class>com.XXX.listener.WSListener</listener-class>

</listener>

<welcome-file-list>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>

</web-app>

在以上的web.xml文件中,我们就让Web服务器在启动时实例化我们自己定义的com.XXX.listener.WSListener类(一般自己定义的Listener类要写在org.springframework.web.context.ContextLoaderListener的后面),然后在该类中去启动线程:

public class WSListener implements ServletContextListener{

private WSThread wsThread

@Overridepublic void contextDestroyed(ServletContextEvent event) {// TODO Auto-generated method stub

if (wsThread != null &&wsThread.isRunning){

wsThread.stopThread()

}

}

@Overridepublic void contextInitialized(ServletContextEvent event) {// TODO Auto-generated method stub

if (wsThread == null){

wsThread = new WSThread(event)

wsThread.start()

}

}

}

Listener类是由Web服务器管理的,当Web服务器启动时,将Listener类实例化并调用其contextInitialized(ServletContextEvent event)方法,当Web服务器关闭时,调用其contextDestroyed(ServletContextEvent event)方法,因此我们可以分别在这两个方法里面实现线程的启动和结束。

2. 在Spring容器以外获得其内部的Bean的实例的引用

被启动的线程用于间隔一定的时间扫描一次数据库,找出新增加的数据。在一般的Struts+Spring+Hibernate的Web项目中,Spring容器中的Bean是由Spring容器管理的,而我们这里启动的线程并不在Spring容器中,那么怎样获得Spring容器中Bean的实例的引用进而访问数据库呢?可以使用Spring的WebApplicationContextUtils工具类,该工具类获得Spring容器的引用,再获得其内部的Bean的实例的引用。

线程的代码:

public class WSThread extends Thread{public volatile boolean isRunning = true // 两次扫描之间休眠的时间

public long s_time private WebApplicationContext context private PropService propService private Prop prop private Temp2Service temp2Service private Temp2 temp2

private TempService tempService

ServletContextEvent event public WSThread(ServletContextEvent e){this.event = e this.context = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext()) this.propService = (PropService) context.getBean("propService") this.temp2Service = (Temp2Service) context.getBean("temp2Service")

}

public void run(){while (isRunning){try {this.prop = propService.findByName("scan_time") this.s_time = Integer.parseInt(prop.getValue())*1000

sleep(s_time)

System.out.println("Run!!!!!!")

} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace()

}

}

}

public void stopThread(){

isRunning = false

}

public boolean isRunning(){return isRunning

}

}

在该线程的构造函数中,使用了从Listener传过来的ServletContextEvent变量,用该变量的getServletContext()方法,获取Web项目的servletContext,然后再以这个ServletContext作为参数,使用WebApplicationContextUtils的getRequiredWebApplicationContext()方法获取ApplicationContext对象,最后再通过ApplicationContext的getBean()方法获取到Bean的实例,实现对数据库的访问。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/8177529.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存