关于SpringMVC里面,进行自定义事件,分发处理耗时操作服务的示例解析
事件处理在spring的应用程序上下文(ApplicationContext )里面,是通过ApplicationEvent和ApplicationListener 实现的,spring本身的一些事件有ContextRefreshedEvent,ContextStartedEvent,ContextStoppedEvent, etc. 同时spring可以允许我们自定义事件,并进行事件的捕获及处理( 这种机制可以让我们做一些耗时操作的服务,或者消息服务之类的等),下面本人通过发送邮件服务对这个spring特性进行示例应用下。
1 . 首先自定义我们的邮件发送事件实体
package com.hisoka.applicationEvent;
import org.springframework.context.ApplicationEvent;
import com.hisoka.POJO.Email;
/**
* EmailMonitorEvent.java
*
* @author: Hinsteny
* @date: 2015年11月25日
* @copyright: 2015 All rights reserved.
*
*/
public class EmailMonitorEvent extends ApplicationEvent {
/**
* serialVersionUID
* long
*/
private static final long serialVersionUID = 7197120866146492975L;
private final String sendAddress;
private final Email email;
public EmailMonitorEvent(Object source, String sendAddress, Email email) {
super(source);
this.sendAddress = sendAddress;
this.email = email;
}
public String getSendAddress() {
return sendAddress;
}
public Email getEmail() {
return email;
}
}
2 . 这里实现ApplicationEventPublisherAware,然后就可以触发并发布一个自定义事件
package com.hisoka.applicationEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import com.hisoka.POJO.Email;
import com.hisoka.support.email.MailSender;
/**
* EmailService.java
*
* @author: Hinsteny
* @date: 2015年11月25日
* @copyright: 2015 All rights reserved.
*
*/
@Component
public class EmailService implements ApplicationEventPublisherAware {
private Logger logger = LoggerFactory.getLogger(EmailService.class);
@Autowired
MailSender mailSender;//发送邮件的工具类
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
public void sendEmail(String toAddress, String title, String content) {
Email email = new Email();
email.setTitle(title);
email.setContent(content);
email.setToAddress(toAddress);
EmailMonitorEvent event = new EmailMonitorEvent(this, mailSender.getMailUser(), email);
logger.debug("publish send email Event!");
publisher.publishEvent(event);
// other service
}
}
3 . 然后实现ApplicationListener接口,即接收我们的自定义事件及处理事件
package com.hisoka.applicationEvent;
import java.io.IOException;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* EmailListNotifier.java
*
* @author: Hinsteny
* @date: 2015年11月25日
* @copyright: 2015 All rights reserved.
*
*/
@Component
public class EmailListNotifier implements ApplicationListener<EmailMonitorEvent> {
private Logger logger = LoggerFactory.getLogger(EmailListNotifier.class);
@Resource
private EmailJob emailJob;//发送邮件的服务类
@Override
public void onApplicationEvent(EmailMonitorEvent event) {
try {
logger.debug("Just do send email service!");
emailJob.send(event.getEmail());
} catch (MessagingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4 . 发送邮件的服务类代码
package com.hisoka.applicationEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.StringTemplateResourceLoader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import com.hisoka.POJO.Email;
import com.hisoka.support.email.MailSender;
import com.hisoka.utils.Strings;
/**
* @author: Hinsteny
* @date: 2015年11月25日
* @copyright: 2015 All rights reserved.
*/
@Component
public class EmailJob {
private static final String url = "email.tmpl";
@Resource
private MailSender mailSender;
public void send(Email email) throws MessagingException, IOException {
//邮件模板
String emailTemplate = Strings.getContentFromInputStream(new ClassPathResource(url).getInputStream(),"utf-8");
Map<String,Object> data = new HashMap<>();
data.put("totalRegister", 15);
StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate(emailTemplate);
t.binding(data);
mailSender.send(email.getToAddress(), email.getTitle(), t.render());
}
}
5 . 最后就是进行邮件发送的工具类
package com.hisoka.support.email;
import java.util.Date;
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.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.springframework.stereotype.Component;
import com.hisoka.support.config.Config;
/**
* MailSender.java
*
* @author: Hinsteny
* @date: 2015年11月25日
* @copyright: 2015 All rights reserved.
*
*/
@Component
public class MailSender {
@Config("mail.user")
private String mailUser;
@Config("mail.password")
private String mailPassword;
@Config("mail.host")
private String mailHost;
public String getMailUser() {
return mailUser;
}
public void setMailUser(String mailUser) {
this.mailUser = mailUser;
}
public String getMailPassword() {
return mailPassword;
}
public void setMailPassword(String mailPassword) {
this.mailPassword = mailPassword;
}
public String getMailHost() {
return mailHost;
}
public void setMailHost(String mailHost) {
this.mailHost = mailHost;
}
/**
* 邮件发送
*
* @param receiver 接收邮箱
* @param subject 主题
* @param content 内容
* @throws MessagingException
*/
public void send(String receiver, String subject, String content) throws MessagingException {
Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", mailHost);
props.put("mail.debug", "true");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(mailUser, mailPassword);
}
});
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(mailUser));
String[] arr = receiver.split(",|,");
InternetAddress[] address = new InternetAddress[arr.length];
for (int i = 0; i < arr.length; i++) {
address[i] = new InternetAddress(arr[i]);
}
msg.addRecipients(Message.RecipientType.TO, address);
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setContent(content, "text/html;charset=utf-8");
Transport.send(msg);
}
}
上面我们在实际应用中,一般请求一个服务 (譬如上面EmailService的sendEmail方法),假如我们的发送邮件是一个耗时的操作 (查一些邮件内容需要的数据,做数据库记录等),这里我们要是等到所有事情做完并发完邮件,那客户端等待的时间就比较长了 (或者说客户体验不好,哈哈),并且客户端不需要发送邮件服务返回什么数据,那我们在这里可以先给客户端返回,把真正的邮件发送服务安排到一个事件处理里面 (这里一般还可以用多线程的方式去处理),这样很明显对客户端的响应就快速,友好多了嘛
关于spring的自定义事件分发处理的介绍就到这了,后面再学习更多的spring特性,哈哈