【学习笔记】监听器Listener

本文详细介绍了JavaEE中Servlet技术的监听器概念及其应用场景。包括ServletContextListener、HttpSessionListener、ServletRequestListener等监听器的实现原理及示例代码,并探讨了如何利用监听器优化服务器资源管理和用户交互。

1.Listener概述

javaEE包括13门规范,在课程中主要学习servlet技术 和 jsp技术,其中 servlet规范包括三个技术点:servlet  listener  filter。
监听器就是监听某个对象的的状态变化的组件
监听器的相关概念:
事件源:被监听的对象  ----- 三个域对象 request  session  servletContext

2.监听器种类:6+2:

第一维度:按照被监听的对象划分:ServletRequest域   HttpSession域   ServletContext域
第二维度:按照监听的内容分:监听域对象的创建与销毁    监听域对象的属性变化

2.1  监听三大域对象的创建与销毁的监听器

(1)监听器ServletContextListener用于监听ServletContext域对象的创建与销毁。使用时需要实现这个接口

ServletContext域的生命周期:服务器启动时创建,服务器关闭时销毁。

ServletContextListener监听器的主要作用

  • 初始化的工作:初始化对象,初始化数据 ---- 加载数据库驱动  连接池的初始化
  • 加载一些初始化的配置文件 --- spring的配置文件
  • 任务调度----定时器----Timer/TimerTask

示例:

package com.xing.servletContext;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;

import javafx.scene.input.DataFormat;

public class ServletContextListener implements javax.servlet.ServletContextListener{

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		// TODO Auto-generated method stub
//		ServletContext servletContext = sce.getServletContext();//获取被监听的servletContext域对象
//		ServletContext source = (ServletContext) sce.getSource();//通用方法,获取被监听的对象
		System.out.println("ServletContext域对象创建了");
		
		//计息任务调度
		/*Timer timer=new Timer();
		//timer.scheduleAtFixedRate(task, firstTime, period);---task:任务  firstTime:第一次执行时间  period:间隔执行时间
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				System.out.println("每隔三秒开始计息.....");
			}}, new Date(), 3000);*/
		
		
		//银行真正计息业务
		Timer timer=new Timer();
		SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//		String date = format.format(new Date());
		Date parse=null;
		try {
			parse = format.parse("2018-09-01 10:29:00");//String转Date
		} catch (ParseException e) {
			e.printStackTrace();
		}
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				System.out.println("银行开始计息");
				
			}
		}, parse, 24*60*60*1000);
		
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		// TODO Auto-generated method stub
		System.out.println("ServletContext域对象销毁了");
		
	}

}

配置文件:

<listener>
    <listener-class>com.xing.servletContext.ServletContextListener</listener-class>
</listener>

(2)监听器HttpSessionListener用于监听Httpsession域的创建于销毁

HttpSession对象的生命周期:第一次调用request.getSession时创建;服务器关闭销毁   session过期   手动销毁

public class HttpSessionListener implements javax.servlet.http.HttpSessionListener{

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		// TODO Auto-generated method stub
		HttpSession session = se.getSession();
		HttpSession source = (HttpSession) se.getSource();
		System.out.println("session创建了"+source.getId());
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		// TODO Auto-generated method stub
		System.out.println("session销毁了");
	}

}

(3)监听器ServletRequestListener用于监听ServletRequest域创建与销毁

ServletRequest的生命周期:每一次请求都会创建request;销毁:请求结束

2.2 监听三大域对象的属性变化的监听器

  • ServletContextAttibuteListener监听器
  • HttpSessionAttributeListener监听器
  • ServletRequestAriibuteListenr监听器

ServletContextAttributeListener监听器示例:

package com.xing.attribute;

import javax.servlet.ServletContextAttributeEvent;

public class ServletContextAttributeListener implements javax.servlet.ServletContextAttributeListener{

	@Override
	public void attributeAdded(ServletContextAttributeEvent scab) {
		// TODO Auto-generated method stub
		System.out.println("放到域中的属性:"+scab.getName()+scab.getValue());
	}

	@Override
	public void attributeRemoved(ServletContextAttributeEvent scab) {
		// TODO Auto-generated method stub
		System.out.println("删除域中的属性:"+scab.getName()+scab.getValue());
	}

	@Override
	public void attributeReplaced(ServletContextAttributeEvent scab) {
		// TODO Auto-generated method stub
		System.out.println("修改前的域中的属性:"+scab.getName()+scab.getValue());
		
	}

}

 

 

2.3 对象感知监听器:与session中的对象相关的监听器

(1)将要被绑定到session中的对象有几种状态:

绑定状态:一个对象被放到session域中

解绑状态:这个对象从session域中移除

钝化状态:将session内存中的对象持久化(序列化)到磁盘

活化状态:将磁盘上的对象再次恢复到session内存中

面试题:当用户很多时,怎样对服务器进行优化?

(2)绑定与解绑的监听器HttpSessionBindingListener(第七个监听器)

package com.xing.domain;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class Persion implements HttpSessionBindingListener{
	//不用再xml配置
	private String name;
	private String id;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	@Override
	public void valueBound(HttpSessionBindingEvent event) {
		// TODO Auto-generated method stub
		System.out.println("person被绑定。。。"+event.getName());
		
	}
	@Override
	public void valueUnbound(HttpSessionBindingEvent event) {
		// TODO Auto-generated method stub
		System.out.println("person被解绑。。。"+event.getName());
	}
	
}

 

钝化与活化的监听器HttpSessionActivationListener(第八个监听器)

(注意:还要实现io包的Serializable接口,对象才能真正被钝化到磁盘)

对象被钝化到work/catalina/localhost/下的文件夹

package com.xing.domain;

import java.io.Serializable;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;

public class Customer implements HttpSessionActivationListener,Serializable{
	private String id;
	private String name;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public void sessionWillPassivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
		System.out.println("customer被钝化,,,");
		
	}
	@Override
	public void sessionDidActivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
		System.out.println("customer被活化,,,");
	}
	

}

可以通过配置文件指定对象钝化时间 --- 对象多长时间不用被钝化:在META-INF下创建一个context.xml

<Context>
 <!-- maxIdleSwap:session中的对象多长时间不使用就钝化 -->
 <!-- directory:钝化后的对象的文件写到磁盘的哪个目录下  配置钝化的对象文件在												work/catalina/localhost/钝化文件 -->
 <Manager className="org.apache.catalina.session.PersistentManager" 																	maxIdleSwap="1">
  <Store className="org.apache.catalina.session.FileStore" directory="itcast205" />
 </Manager>
</Context>

案例:邮件发送程序(需要一个mail.jar)

发送邮件的协议:SMTP协议
接收邮件的协议:POP3,IMAP

package com.xing.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

public class MailUtils {
//这个程序一般不需要自己写,会用就ok

	//email:邮件发给谁  subject:主题  emailMsg:邮件的内容
	public static void sendMail(String email, String subject, String emailMsg)
			throws AddressException, MessagingException {
		
		// 1.创建一个程序与邮件服务器会话对象 Session
		Properties props = new Properties();
		props.setProperty("mail.transport.protocol", "SMTP");//发邮件的协议
		props.setProperty("mail.host", "smtp.163.com");//发送邮件的服务器地址
		props.setProperty("mail.smtp.auth", "true");// 指定验证为true

		// 创建验证器
		Authenticator auth = new Authenticator() {
			public PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("xxxxx@163.com", "123");//发邮件的账号的验证
			}
		};

		Session session = Session.getInstance(props, auth);

		// 2.创建一个Message,它相当于是邮件内容
		Message message = new MimeMessage(session);

		message.setFrom(new InternetAddress("xxxxx@163.com")); // 设置发送者

		message.setRecipient(RecipientType.TO, new InternetAddress(email)); // 设置发送方式与接收者

		message.setSubject(subject);//邮件的主题

		message.setContent(emailMsg, "text/html;charset=utf-8");

		// 3.创建 Transport用于将邮件发送
		Transport.send(message);
	}
}
package com.xing.mail;

import javax.mail.MessagingException;
import javax.mail.internet.AddressException;

public class SendMailTest {
	public static void main(String[] args) throws AddressException, MessagingException {
		MailUtils.sendMail("xxxx@163.com", "测试", "这是一个测试邮件");
	}

}

案例:用户生日当天发送祝福邮件

package com.itheima.birthday;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.mail.MessagingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import com.itheima.mail.MailUtils;

public class BirthdayListener implements ServletContextListener{

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//当web应用启动 开启任务调动---功能在用户的生日当前发送邮件
		//开启一个定时器
		Timer timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			
			@Override
			public void run() {
				// 为当前的生日的用户发邮件
				//1、获得今天过生日的人
				//获得今天的日期
				SimpleDateFormat format = new SimpleDateFormat("MM-dd");
				String currentDate = format.format(new Date());
				//根据当前时间从数据查询今天过生日的人
				QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
				String sql = "select * from customer where birthday like ?";
				List<Customer> customerList = null;
				try {
					customerList = runner.query(sql, new BeanListHandler<Customer>(Customer.class) ,"%"+currentDate+"%");
				} catch (SQLException e) {
					e.printStackTrace();
				} //08-18
				//2、发邮件
				if(customerList!=null&&customerList.size()>0){
					for(Customer c : customerList){
						String emailMsg = "亲爱的:"+c.getRealname()+",生日快乐!";
						try {
							MailUtils.sendMail(c.getEmail(), "生日祝福", emailMsg);
							System.out.println(c.getRealname()+"邮件发送完毕");
						} catch (MessagingException e) {
							e.printStackTrace();
						}
					}
				}
				
				
			}
		}, new Date(), 1000*10);
		//实际开发中起始时间是一个固定的时间
		//实际开发中间隔时间是1天
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		
	}

}

 

转载于:https://my.oschina.net/u/3943244/blog/1940588

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值