- 浏览: 642267 次
- 性别:
- 来自: 杭州
-
文章分类
最新评论
-
liuche20083736:
非常好
从问题看本质: 研究TCP close_wait的内幕 -
xiaopohai85707:
优化算法与原来需求不符
过滤字符的性能调优?挤一挤还是有的 -
kmy_白衣:
生成的area图有时候 标签的数值和图标上看上去的数值不一致。 ...
OpenFlashChart2之恶心文档 -
tom&jerry:
大神,请教一个问题,按名称排序为何无效,用的2.4.3 XPA ...
深入浅出jackrabbit之十三 查询之AST和QT -
jd2bs:
改成精确匹配可以了< filter-mapping &g ...
细谈Ehcache页面缓存的使用
/**
*作者:张荣华(ahuaxuan)
*2007-07-11
*转载请注明出处及作者
*/
Javamail,论坛上由已经有很多的讨论,但是俺觉得还是不够完整,不完整不是说讲的不细致,而是指不全面,而是缺少high level的全面论述,所以俺来补充一下。
这篇文章的名字起得很古怪(估计还有人暗地里说文章名字取得如何如何,文章实质却是水货等等了,先不忙下结论,各位看官接着往下看便知),叫简单和复杂之间,为什么要取这么个奇怪的名字,搞得人一头雾水,其实我想要表达的意思是这样的,之前坛子上有很多人讨论过如何使用javamail(包括spring对其的封装),也有人讨论过如何通过jms发送emal,一个是简单的api介绍,一个是比较复杂的异步方案,但是试问除了简单使用其api难道就只能使用jms来进行异步发送了吗,我们可以再找到一种介于这两者之间的方案,就是concurrent(我的建议是在普通的web应用中邮件发送不需要用jms,但是最好也不要使用同步发送,所以普通的web应该使用concurrent来进行异步邮件发送应该是比较好的选择)。
在普通的web应用中,发送邮件应该只能算小任务,而使用jms来发送邮件有点杀鸡用牛刀的味道,那么如果能建立一个线程池来管理这些小线程并重复使用他们,应该来说是一个简单有效的方案,我们可以使用concurrent包中的Executors来建立线程池,Executors是一个工厂,也是一个工具类,我把它的api的介绍简单的翻译了一下(如果翻译有误请大家不要吝啬手中的砖头)
方 法 说 明
newCachedThreadPool() 创建一个包含新线程的线程池,池中线程的数量需要预先指定,该线程池会复用之前创建的线程(前提是该线程还是有效线程)。如果你的要执行的任务是短生命周期的任务的话,使用这种池提高性能是很具代表性的。这个方法有一个重载
newFixedThreadPool() 创建一个线程池以复用指定数量的线程,如果当所有线程都是活动状态时(指这些线程都在运行),那么新的任务将会等待,知道有空余的线程。如果有任何一个线程因为在运行中发生错误而终结(非正常shutdown),那么如果有新的任务要并发处理,concurrent就会创建一个新的线程放入池中。
newSingleThreadExecutor() 创建一个使用单工作线程的executor,
newScheduledThreadPool() 可调度的线程池,池中的线程可以在某一时间延迟之后执行,也可以周期性执行
newSingleThreadScheduledExecutor() 单一可调度的线程
上面我重点解释了newFixedThreadPool(),因为我们将使用newFixedThreadPool方法来创建一个线程池,这个线程池中存放的线程就是我们用来发送邮件的。代码如下:
这样我们就初始化了线程池的大小,接下来就是如何使用这个线程池中的线程了,我们看看MailService是如何来使用线程池中的线程的,这个类中的代码我已经作了详细的解释
MailService中的EmailEntity是对邮件的抽象(我只使用了失血模型,事实上我们也可以让这个EmailEntity来实现Runnable接口,这样Service中的内部类就可以去掉了,同时service中的大部分代码就要搬到EmailEntity及其父类里了,大家更倾向于怎么做呢?),代码如下:
接下来就是在spring的配置文件中配置这些类了,我相信对熟悉spring的人来说这不是什么大问题:
经过这么一番折腾之后,一个邮件发送的雏形就完成了,接着需要什么样的邮件发送功能就可以随意往MailService里添加内容了, 而如果需要用模板来生成html格式的邮件真的需要看http://www.iteye.com/topic/71430这个贴了,无论你是想用velocity还是想用freemarker来做模板引擎,这个贴中的例子都是可以直接拿来使用的
总结,如果自己起线程来发送邮件是一个非常危险的事情,如果并发一高(比如超过20),服务器估计就快撑不住了,而如果使用jms来异步发送邮件,学习的曲线高,成本也高,我不建议为了一个小小的邮件发送就在项目中导入jms(之所以这样说是因为还有很多项目就是基于webservice的,那么使用jms来调度webservice是一个不错的选择),所以使用线程池来实现这个异步的功能既安全又简单,这个例子是开源的,大家可以在自己的项目中随意修改,随意封装。
要注意的是,concurrent在jdk5.0以上版本中才有,如果你使用的是1.4的jdk需要单独下载concurrent包。
作者:张荣华,未经作者同意不得随意转载!
稍微思考一下就知道你的问题处在easyMailExecutorPool没有注入到EasyMailServieImpl,或者easyMailExecutorPool的 public void afterPropertiesSet() throws Exception {
service = Executors.newFixedThreadPool(poolSize);
}
方法没有正确执行,稍微debug一下就知道了,我的代码都是经过测试的
这里没有同步的问题,不需要synchronized,因为EmailEntity是一个实体类,每次请求都会创建一个呀,所以即使是并发,只要服务器有命这里就不会出现什么问题
ps:我不是什么大侠,只是刚起飞的菜鸟,呵呵
你说得对,这几种方案不冲突,所谓得简单和复杂只是针对使用而言。
谢谢你的提醒,本人也比较反对标题党,可是我并不觉得文章的名字有什么不妥,本来就是在简单和复杂之间的选择。而用《复杂方式解释简单内容》在我眼里似乎更加标题党一些,但是本文的题目也确实没有能涵盖住内容,除了线程池,耗时操作,接触到设计模式,域模型等,这一点相信你也看出来了,人人都能写出能工作的代码,本文的一个目的就是想说明写代码不是只要能工作就可以了的。
spring是基础,就不用说了
*作者:张荣华(ahuaxuan)
*2007-07-11
*转载请注明出处及作者
*/
Javamail,论坛上由已经有很多的讨论,但是俺觉得还是不够完整,不完整不是说讲的不细致,而是指不全面,而是缺少high level的全面论述,所以俺来补充一下。
这篇文章的名字起得很古怪(估计还有人暗地里说文章名字取得如何如何,文章实质却是水货等等了,先不忙下结论,各位看官接着往下看便知),叫简单和复杂之间,为什么要取这么个奇怪的名字,搞得人一头雾水,其实我想要表达的意思是这样的,之前坛子上有很多人讨论过如何使用javamail(包括spring对其的封装),也有人讨论过如何通过jms发送emal,一个是简单的api介绍,一个是比较复杂的异步方案,但是试问除了简单使用其api难道就只能使用jms来进行异步发送了吗,我们可以再找到一种介于这两者之间的方案,就是concurrent(我的建议是在普通的web应用中邮件发送不需要用jms,但是最好也不要使用同步发送,所以普通的web应该使用concurrent来进行异步邮件发送应该是比较好的选择)。
在普通的web应用中,发送邮件应该只能算小任务,而使用jms来发送邮件有点杀鸡用牛刀的味道,那么如果能建立一个线程池来管理这些小线程并重复使用他们,应该来说是一个简单有效的方案,我们可以使用concurrent包中的Executors来建立线程池,Executors是一个工厂,也是一个工具类,我把它的api的介绍简单的翻译了一下(如果翻译有误请大家不要吝啬手中的砖头)
方 法 说 明
newCachedThreadPool() 创建一个包含新线程的线程池,池中线程的数量需要预先指定,该线程池会复用之前创建的线程(前提是该线程还是有效线程)。如果你的要执行的任务是短生命周期的任务的话,使用这种池提高性能是很具代表性的。这个方法有一个重载
newFixedThreadPool() 创建一个线程池以复用指定数量的线程,如果当所有线程都是活动状态时(指这些线程都在运行),那么新的任务将会等待,知道有空余的线程。如果有任何一个线程因为在运行中发生错误而终结(非正常shutdown),那么如果有新的任务要并发处理,concurrent就会创建一个新的线程放入池中。
newSingleThreadExecutor() 创建一个使用单工作线程的executor,
newScheduledThreadPool() 可调度的线程池,池中的线程可以在某一时间延迟之后执行,也可以周期性执行
newSingleThreadScheduledExecutor() 单一可调度的线程
上面我重点解释了newFixedThreadPool(),因为我们将使用newFixedThreadPool方法来创建一个线程池,这个线程池中存放的线程就是我们用来发送邮件的。代码如下:
/** * 由spring管理的线程池类,返回的ExecutorService就是给我们来执行线程的 *如果不交给spring管理也是可以的,可以使用单例模式来实现同样功能,但是poolSize *要hardcode了 * @author 张荣华(ahuaxuan) * @version $Id$ */ public class EasyMailExecutorPool implements InitializingBean { //线程池大小,spring配置文件中配置 private int poolSize; private ExecutorService service; public ExecutorService getService() { return service; } public int getPoolSize() { return poolSize; } public void setPoolSize(int poolSize) { this.poolSize = poolSize; } /** * 在 bean 被初始化成功之后初始化线程池大小 */ public void afterPropertiesSet() throws Exception { service = Executors.newFixedThreadPool(poolSize); } }
这样我们就初始化了线程池的大小,接下来就是如何使用这个线程池中的线程了,我们看看MailService是如何来使用线程池中的线程的,这个类中的代码我已经作了详细的解释
/** * 用来发送 mail 的 service, 其中有一个内部类专门用来供线程使用 * @author 张荣华(ahuaxuan) * @since 2007-7-11 * @version $Id$ */ public class EasyMailServieImpl implements EasyMailService{ private static transient Log logger = LogFactory.getLog(EasyMailServieImpl.class); //注入MailSender private JavaMailSender javaMailSender; //注入线程池 private EasyMailExecutorPool easyMailExecutorPool; //设置发件人 private String from; public void setEasyMailExecutorPool(EasyMailExecutorPool easyMailExecutorPool) { this.easyMailExecutorPool = easyMailExecutorPool; } public void setJavaMailSender(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } public void setFrom(String from) { this.from = from; } /** * 简单的邮件发送接口,感兴趣的同学可以在这个基础上继续添加 * @param to * @param subject * @param text */ public void sendMessage(EmailEntity email){ if (null == email) { if (logger.isDebugEnabled()) { logger.debug("something you need to tell here"); } return; } SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); simpleMailMessage.setTo(email.getTo()); simpleMailMessage.setSubject(email.getSubject()); simpleMailMessage.setText(email.getText()); simpleMailMessage.setFrom(from); easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage)); } /** * 发送复杂格式邮件的接口,可以添加附件,图片,等等,但是需要修改这个方法, * 如何做到添加附件和图片论坛上有例子了,需要的同学搜一下, * 事实上这里的text参数最好是来自于模板,用模板生成html页面,然后交给javamail去发送, * 如何使用模板来生成html见 {@link http://www.iteye.com/topic/71430 } * * @param to * @param subject * @param text * @throws MessagingException */ public void sendMimeMessage(EmailEntity email) throws MessagingException { if (null == email) { if (logger.isDebugEnabled()) { logger.debug("something you need to tell here"); } return; } MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message); helper.setTo(email.getTo()); helper.setFrom(from); helper.setSubject(email.getSubject()); this.addAttachmentOrImg(helper, email.getAttachment(), true); this.addAttachmentOrImg(helper, email.getImg(), false); //这里的text是html格式的, 可以使用模板引擎来生成html模板, velocity或者freemarker都可以做到 helper.setText(email.getText(),true); easyMailExecutorPool.getService().execute(new MailRunner(message)); } /** * 添加附件或者是图片 * @param helper * @param map * @param isAttachment * @throws MessagingException */ private void addAttachmentOrImg(MimeMessageHelper helper, Map map, boolean isAttachment) throws MessagingException { for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) { FileSystemResource file = new FileSystemResource(new File(value)); if (!file.exists()) continue; if (isAttachment) { helper.addAttachment(key, file); } else { helper.addInline(key, file); } } } } /** * 用来发送邮件的 Runnable, 该类是一个内部类,之所以使用内部类,而没有使用嵌套类(静态内部类), * 是因为内部类可以之间得到 service 的 javaMailSender * 每次发送邮件都会从线程池中取一个线程, 然后进行发邮件操作 * @author ahuaxuan */ private class MailRunner implements Runnable { SimpleMailMessage simpleMailMessage; MimeMessage mimeMessage; /** * 构造简单文本邮件 * @param simpleMailMessage */ public MailRunner(SimpleMailMessage simpleMailMessage) { if (mimeMessage == null) { this.simpleMailMessage = simpleMailMessage; } } /** * 构造复杂邮件,可以添加附近,图片,等等 * @param mimeMessage */ public MailRunner(MimeMessage mimeMessage) { if (simpleMailMessage == null) { this.mimeMessage = mimeMessage; } } /** * 该方法将在线程池中的线程中执行 */ public void run() { try { if (simpleMailMessage != null) { javaMailSender.send(this.simpleMailMessage); } else if (mimeMessage != null) { javaMailSender.send(this.mimeMessage); } } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("logger something here", e); } } } } }
MailService中的EmailEntity是对邮件的抽象(我只使用了失血模型,事实上我们也可以让这个EmailEntity来实现Runnable接口,这样Service中的内部类就可以去掉了,同时service中的大部分代码就要搬到EmailEntity及其父类里了,大家更倾向于怎么做呢?),代码如下:
/** * 该类是对邮件的抽象,邮件有哪些属性,这个类就有哪些属性 显然这个只是一个例子, * 这个例子中附带mimemessage发送所需的附件或者图片(如果有的话) * 需要使用的同学自己扩展 * * @author 张荣华(ahuaxuan) * @version $Id$ */ public class EmailEntity { String to; String subject; String text; //邮件附件 Map<String, String> attachment = new HashMap<String, String>(); //邮件图片 Map<String, String> img = new HashMap<String, String>(); //这里省去大段的getter和setter方法 }
接下来就是在spring的配置文件中配置这些类了,我相信对熟悉spring的人来说这不是什么大问题:
<beans> <bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl" autowire="byName"> <property name="host" value="${mail.host}"/> <property name="username" value="${mail.username}"/> <property name="password" value="${mail.password}"/> </bean> <bean id="easyMailExecutorPool" class="org.zhangronghua.easymail.EasyMailExecutorPool" autowire="byName"> <property name="poolSize"> <value>5</value> </property> </bean> <bean id="easyMailService" class="org.zhangronghua.easymail.EasyMailServieImpl" autowire="byName"> <property name="from" value="${mail.default.from}"/> </bean> </beans>
经过这么一番折腾之后,一个邮件发送的雏形就完成了,接着需要什么样的邮件发送功能就可以随意往MailService里添加内容了, 而如果需要用模板来生成html格式的邮件真的需要看http://www.iteye.com/topic/71430这个贴了,无论你是想用velocity还是想用freemarker来做模板引擎,这个贴中的例子都是可以直接拿来使用的
总结,如果自己起线程来发送邮件是一个非常危险的事情,如果并发一高(比如超过20),服务器估计就快撑不住了,而如果使用jms来异步发送邮件,学习的曲线高,成本也高,我不建议为了一个小小的邮件发送就在项目中导入jms(之所以这样说是因为还有很多项目就是基于webservice的,那么使用jms来调度webservice是一个不错的选择),所以使用线程池来实现这个异步的功能既安全又简单,这个例子是开源的,大家可以在自己的项目中随意修改,随意封装。
要注意的是,concurrent在jdk5.0以上版本中才有,如果你使用的是1.4的jdk需要单独下载concurrent包。
作者:张荣华,未经作者同意不得随意转载!
评论
18 楼
cfyme
2012-07-04
public void generateMimeMailMessage(JavaMailSender javaMailSender, ExecutorService executorService) throws MessagingException {
super.javaMailSender = javaMailSender;
super.executorService = executorService;
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
有一个问题:
在上面这个方法中 我觉得最下面两行要改成
mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "utf-8");
不然父类中的mimeMessage永远是null
super.javaMailSender = javaMailSender;
super.executorService = executorService;
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
有一个问题:
在上面这个方法中 我觉得最下面两行要改成
mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "utf-8");
不然父类中的mimeMessage永远是null
17 楼
cfyme
2012-07-04
看了您的分享,学习了很多,有个问题,请问我按你重构后的 去运行,怎么也执行不到父类中RUN方法,不知道哪里出问题了,能把源代码发我一份吗,cfyme@163.com
16 楼
llin96
2007-12-15
作者已经写的很完整很详细了, 如果你不熟练spring就先去看看文档吧
15 楼
liuxinsudi
2007-10-11
能否把整个源代码让我拜读一下? wangfujunemail@163.com
14 楼
liuxinsudi
2007-10-11
能否把整个源代码让我拜读一下? wangfujunemail@163.com
13 楼
harrybit
2007-09-06
楼主能把完整的代码挂上来下载就更好了
12 楼
ahuaxuan
2007-08-24
maserkinger 写道
方法挺好,不过介绍得比较简单了.
而且按这么配置的话
easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage));
会出现空指针错误,建议楼主放个无错误的用法上来!
而且按这么配置的话
easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage));
会出现空指针错误,建议楼主放个无错误的用法上来!
稍微思考一下就知道你的问题处在easyMailExecutorPool没有注入到EasyMailServieImpl,或者easyMailExecutorPool的 public void afterPropertiesSet() throws Exception {
service = Executors.newFixedThreadPool(poolSize);
}
方法没有正确执行,稍微debug一下就知道了,我的代码都是经过测试的
11 楼
maserkinger
2007-08-22
方法挺好,不过介绍得比较简单了.
而且按这么配置的话
easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage));
会出现空指针错误,建议楼主放个无错误的用法上来!
而且按这么配置的话
easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage));
会出现空指针错误,建议楼主放个无错误的用法上来!
10 楼
sskhnje
2007-08-02
谢谢!
真是个好人.
能发一份源码给我吗?
谢谢啊!
sskhnje@mail.ynu.edu.cn
真是个好人.
能发一份源码给我吗?
谢谢啊!
sskhnje@mail.ynu.edu.cn
9 楼
downpour
2007-07-24
自己实现一个的成本也不小,不如扔到JMS里面,配一下就ok了。
不过这个池不错,可以成为范本了。简单耐用啊。
不过这个池不错,可以成为范本了。简单耐用啊。
8 楼
baibai326
2007-07-24
恩,谢谢啦。
呵呵,大侠就是大侠,还这么谦虚,我是没有先飞的笨鸟。o(∩_∩)o...
呵呵,大侠就是大侠,还这么谦虚,我是没有先飞的笨鸟。o(∩_∩)o...
7 楼
ahuaxuan
2007-07-24
baibai326 写道
楼主请教一个问题,
如果有在run()中
synchronized(this.simpleMailMessage){
javaMailSender.send(this.simpleMailMessage);
}
如果并发有很多,以你的经验大概会出现什么情况啊?
,想知道我的想法跟大侠之间差距有多少,所以问一问,谢谢回答,呵呵。
如果有在run()中
synchronized(this.simpleMailMessage){
javaMailSender.send(this.simpleMailMessage);
}
如果并发有很多,以你的经验大概会出现什么情况啊?
,想知道我的想法跟大侠之间差距有多少,所以问一问,谢谢回答,呵呵。
这里没有同步的问题,不需要synchronized,因为EmailEntity是一个实体类,每次请求都会创建一个呀,所以即使是并发,只要服务器有命这里就不会出现什么问题
ps:我不是什么大侠,只是刚起飞的菜鸟,呵呵
6 楼
baibai326
2007-07-24
楼主请教一个问题,
如果有在run()中
synchronized(this.simpleMailMessage){
javaMailSender.send(this.simpleMailMessage);
}
如果并发有很多,以你的经验大概会出现什么情况啊?
,想知道我的想法跟大侠之间差距有多少,所以问一问,谢谢回答,呵呵。
如果有在run()中
synchronized(this.simpleMailMessage){
javaMailSender.send(this.simpleMailMessage);
}
如果并发有很多,以你的经验大概会出现什么情况啊?
,想知道我的想法跟大侠之间差距有多少,所以问一问,谢谢回答,呵呵。
5 楼
maxima
2007-07-19
concurrent 使程序员不用关注系线程的管理,实现异步处理轻松不少.
4 楼
ahuaxuan
2007-07-13
jianfeng008cn 写道
jms concurrent jmx 这几种方案并不冲突,无所谓简单复杂吧
你说得对,这几种方案不冲突,所谓得简单和复杂只是针对使用而言。
popi 写道
有些标题党的感觉,
题名改为《用复杂方式解释简单内容》比较合适。
关键词:耗时操作,线程池,与spring无关
题名改为《用复杂方式解释简单内容》比较合适。
关键词:耗时操作,线程池,与spring无关
谢谢你的提醒,本人也比较反对标题党,可是我并不觉得文章的名字有什么不妥,本来就是在简单和复杂之间的选择。而用《复杂方式解释简单内容》在我眼里似乎更加标题党一些,但是本文的题目也确实没有能涵盖住内容,除了线程池,耗时操作,接触到设计模式,域模型等,这一点相信你也看出来了,人人都能写出能工作的代码,本文的一个目的就是想说明写代码不是只要能工作就可以了的。
spring是基础,就不用说了
3 楼
popi
2007-07-13
有些标题党的感觉,
题名改为《用复杂方式解释简单内容》比较合适。
关键词:耗时操作,线程池,与spring无关
题名改为《用复杂方式解释简单内容》比较合适。
关键词:耗时操作,线程池,与spring无关
2 楼
jianfeng008cn
2007-07-13
jms concurrent jmx 这几种方案并不冲突,无所谓简单复杂吧
1 楼
ahuaxuan
2007-07-12
昨天发的帖子说错了一个概念:上面例子中其实使用的是失血模型,我说成了贫血模型,在此更正一下,经过思考,我觉得对这个邮件的抽象用真正的贫血模型是比较合适的,也比失血模型更加的oo,而且代码我也已经重构过了,重构完之后发现最后的结果是整个就是一strategy+adapter,最后service中的方法变成了这个德行(service中的方法变成了策略的调用者)
方法都跑EmailEntity和其父类中去了,但是我没有办法在Entity中注入需要的service,只要作为参数传了进去,从整体上来看,整个easymail变得更加得面向对象了。这让我体会到贫血模型确实要比失血模型更oo
我们看看EmailEntity中得代码:
再看看其父类中方法,这个就是executor要执行得代码了:
public void sendMimeMessage(EmailEntity email) throws MessagingException { email.setFrom(from); email.generateMimeMailMessage(javaMailSender, easyMailExecutorPool.getService()); email.send(); }
方法都跑EmailEntity和其父类中去了,但是我没有办法在Entity中注入需要的service,只要作为参数传了进去,从整体上来看,整个easymail变得更加得面向对象了。这让我体会到贫血模型确实要比失血模型更oo
我们看看EmailEntity中得代码:
/** * 该类是对邮件的抽象,邮件有哪些属性,这个类就有哪些属性 显然这个只是一个例子, * 这个例子中附带mimemessage发送所需的附件或者图片(如果有的话) * 需要使用的同学自己扩展 * * @author 张荣华(ahuaxuan) * @since 2007-7-11 * @version $Id$ */ public class EmailEntity extends EmailRunner{ /** * 构造简单文本邮件 * @param simpleMailMessage */ public void generateSimpleMailMessage(JavaMailSender javaMailSender, ExecutorService executorService) { super.javaMailSender = javaMailSender; super.executorService = executorService; simpleMailMessage = new SimpleMailMessage(); simpleMailMessage.setTo(to); simpleMailMessage.setSubject(subject); simpleMailMessage.setText(text); simpleMailMessage.setFrom(from); } /** * 构造复杂邮件,可以添加附近,图片,等等 * @param mimeMessage * @throws MessagingException */ public void generateMimeMailMessage(JavaMailSender javaMailSender, ExecutorService executorService) throws MessagingException { super.javaMailSender = javaMailSender; super.executorService = executorService; MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message); helper.setTo(to); helper.setFrom(from); helper.setSubject(subject); super.addAttachmentOrImg(helper, attachment, true); super.addAttachmentOrImg(helper, img, false); //这里的text是html格式的, 可以使用模板引擎来生成html模板, velocity或者freemarker都可以做到 helper.setText(text); } /** * 发送邮件方法, 在这个方法调用之前必须调用 generateMimeMailMessage 或者 generateSimpleMailMessage, * @see EasyMailServiceImpl#sendMimeMessage(EmailEntity) * @see EasyMailServiceImpl#sendMessage(EmailEntity) */ public void send() { if(super.javaMailSender != null && super.executorService != null){ super.executorService.execute(this); } } }
再看看其父类中方法,这个就是executor要执行得代码了:
/** * 该方法将在线程池中的线程中执行 */ public void run() { try { if (simpleMailMessage != null) { javaMailSender.send(this.simpleMailMessage); } else if (mimeMessage != null) { javaMailSender.send(this.mimeMessage); } } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("logger something here", e); } } }
发表评论
-
过滤字符的性能调优?挤一挤还是有的
2010-05-29 05:54 3624/* *auth ... -
Master-Slave,Spring,Hibernate,故事曲折离奇,情结跌宕起伏
2009-02-05 13:49 8732/** *作者:张荣华 *日期 ... -
弃成见,反省,并重新认识struts.i18n.encoding
2008-12-24 15:42 3917[size=medium]之前和大家讨论了struts2.0中 ... -
关键字:查询,事务,粒度
2008-08-22 17:05 5164[size=medium]/** *作者: ... -
看看mina和memcached的联姻(适合不同语言客户端,高并发?)
2008-07-21 17:06 8037[size=medium]/** * 作者:张荣华 * 日 ... -
如何解决mysql的master-slave模式中ReplicationDriver的使用问题
2008-06-19 18:23 8245/** * 作者:张荣华 * 日期:2008-6-19 ... -
别装了,难道你们不想把properties直接注入到object中去(spring-plugin)?
2008-04-09 18:01 3674[size=small]/** *作者:张荣华(ahuaxu ... -
用jamon来监控你的sql执行效率
2008-02-25 15:48 3735/** *作者:张荣华 *日期:2008-2-25 ... -
java同msn的通信,大家想想用途吧
2007-11-24 17:14 2540程序员的生活真是单调,除了编程还是编程,工作日 ... -
EAI企业应用集成场景及解决方案
2007-09-21 18:21 3165/** *作者:张荣华(ahuaxuan) *2007-9 ... -
quartz和应用的集群问题
2007-08-21 18:36 12839之前看到很多关于quartz的讨论,尤其是关于quar ... -
优化程序之前,可用Jamon来监测你的Spring应用
2007-08-14 18:14 8180/** *作者:张荣华(ahuaxuan) *2007-8-1 ... -
请问责任链真的是一种设计模式吗
2007-07-26 18:12 9467坛子上讨论设计模式的也挺多的,但是关于这个责任链模式还没有人提 ... -
把ActiveMQ的控制台整合到你的web程序中
2007-07-19 12:06 8885在使用ActiveMQ的时候把ActiveMQ的控制台整 ... -
设计模式之:解剖观察者模式
2007-07-17 16:12 6903[size=9] 论坛上很多人都 ... -
强强连手, 在模板中分页,看Freemarker和displaytag的结合
2007-07-09 09:22 6938/** *作者:张荣华(ahuaxuan) *2007-0 ... -
解惑:在spring+hibernate中,只读事务是如何被优化的。
2007-06-28 18:22 7634/** *作者:张荣华(ahuaxuan) *2007- ... -
让webwork零配置 第二章(实现)(实例已放出,大家可以下载运行)
2007-06-25 09:23 5734/** *作者:张荣华(ahuaxuan) *2007-0 ... -
让webwork2零配置,第一章(主贴再次更新)
2007-06-18 15:41 13445/** *作者:张荣华(ahuaxuan) *2007-0 ... -
Spring声明式事务管理源码解读之事务提交
2007-06-11 09:19 7295/** *作者:张荣华(ahuaxuan) *2007-0 ...
相关推荐
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
MMC整流器技术解析:基于Matlab的双闭环控制策略与环流抑制性能研究,Matlab下的MMC整流器技术文档:18个子模块,双闭环控制稳定直流电压,环流抑制与最近电平逼近调制,优化桥臂电流波形,高效并网运行。,MMC整流器(Matlab),技术文档 1.MMC工作在整流侧,子模块个数N=18,直流侧电压Udc=25.2kV,交流侧电压6.6kV 2.控制器采用双闭环控制,外环控制直流电压,采用PI调节器,电流内环采用PI+前馈解耦; 3.环流抑制采用PI控制,能够抑制环流二倍频分量; 4.采用最近电平逼近调制(NLM), 5.均压排序:电容电压排序采用冒泡排序,判断桥臂电流方向确定投入切除; 结果: 1.输出的直流电压能够稳定在25.2kV; 2.有功功率,无功功率稳态时波形稳定,有功功率为3.2MW,无功稳定在0Var; 3.网侧电压电流波形均为对称的三相电压和三相电流波形,网侧电流THD=1.47%<2%,符合并网要求; 4.环流抑制后桥臂电流的波形得到改善,桥臂电流THD由9.57%降至1.93%,环流波形也可以看到得到抑制; 5.电容电压能够稳定变化 ,工作点关键词:MMC
Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构,Simulink建模,MPPT最大功率点追踪,扰动观察法采用功率反馈方式,若ΔP>0,说明电压调整的方向正确,可以继续按原方向进行“干扰”;若ΔP<0,说明电压调整的方向错误,需要对“干扰”的方向进行改变。 ,Boost升压;光伏并网结构;Simulink建模;MPPT最大功率点追踪;扰动观察法;功率反馈;电压调整方向。,光伏并网结构中Boost升压MPPT控制策略的Simulink建模与功率反馈扰动观察法
STM32F103C8T6 USB寄存器开发详解(12)-键盘设备
科技活动人员数专指直接从事科技活动以及专门从事科技活动管理和为科技活动提供直接服务的人员数量
Matlab Simulink仿真探究Flyback反激式开关电源性能表现与优化策略,Matlab Simulink仿真探究Flyback反激式开关电源的工作机制,Matlab Simulimk仿真,Flyback反激式开关电源仿真 ,Matlab; Simulink仿真; Flyback反激式; 开关电源仿真,Matlab Simulink在Flyback反激式开关电源仿真中的应用
基于Comsol的埋地电缆电磁加热计算模型:深度解析温度场与电磁场分布学习资料与服务,COMSOL埋地电缆电磁加热计算模型:温度场与电磁场分布的解析与学习资源,comsol 埋地电缆电磁加热计算模型,可以得到埋地电缆温度场及电磁场分布,提供学习资料和服务, ,comsol;埋地电缆电磁加热计算模型;温度场分布;电磁场分布;学习资料;服务,Comsol埋地电缆电磁加热模型:温度场与电磁场分布学习资料及服务
1、文件内容:ibus-table-chinese-yong-1.4.6-3.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/ibus-table-chinese-yong-1.4.6-3.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊
基于51单片机protues仿真的汽车智能灯光控制系统设计(仿真图、源代码) 一、设计项目 根据本次设计的要求,设计出一款基于51单片机的自动切换远近光灯的设计。 技术条件与说明: 1. 设计硬件部分,中央处理器采用了STC89C51RC单片机; 2. 使用两个灯珠代表远近光灯,感光部分采用了光敏电阻,因为光敏电阻输出的是电压模拟信号,单片机不能直接处理模拟信号,所以经过ADC0832进行转化成数字信号; 3. 显示部分采用了LCD1602液晶,还增加按键部分电路,可以选择手自动切换远近光灯; 4. 用超声模块进行检测距离;
altermanager的企业微信告警服务
MyAgent测试版本在线下载
Comsol技术:可调BIC应用的二氧化钒VO2材料探索,Comsol模拟二氧化钒VO2的可调BIC特性研究,Comsol二氧化钒VO2可调BIC。 ,Comsol; 二氧化钒VO2; 可调BIC,Comsol二氧化钒VO2材料:可调BIC技术的关键应用
C++学生成绩管理系统源码
基于Matlab与Cplex的激励型需求响应模式:负荷转移与电价响应的差异化目标函数解析,基于Matlab与CPLEX的激励型需求响应负荷转移策略探索,激励型需求响应 matlab +cplex 激励型需求响应采用激励型需求响应方式对负荷进行转移,和电价响应模式不同,具体的目标函数如下 ,激励型需求响应; matlab + cplex; 负荷转移; 目标函数。,Matlab与Cplex结合的激励型需求响应模型及其负荷转移策略
scratch介绍(scratch说明).zip
内容概要:本文全面介绍了深度学习模型的概念、工作机制和发展历程,详细探讨了神经网络的构建和训练过程,包括反向传播算法和梯度下降方法。文中还列举了深度学习在图像识别、自然语言处理、医疗和金融等多个领域的应用实例,并讨论了当前面临的挑战,如数据依赖、计算资源需求、可解释性和对抗攻击等问题。最后,文章展望了未来的发展趋势,如与量子计算和区块链的融合,以及在更多领域的应用前景。 适合人群:对该领域有兴趣的技术人员、研究人员和学者,尤其适合那些希望深入了解深度学习原理和技术细节的读者。 使用场景及目标:①理解深度学习模型的基本原理和结构;②了解深度学习模型的具体应用案例;③掌握应对当前技术挑战的方向。 阅读建议:文章内容详尽丰富,读者应在阅读过程中注意理解各个关键技术的概念和原理,尤其是神经网络的构成及训练过程。同时也建议对比不同模型的特点及其在具体应用中的表现。
该文档提供了一个关于供应链管理系统开发的详细指南,重点介绍了项目安排、技术实现和框架搭建的相关内容。 文档分为以下几个关键部分: 项目安排:主要步骤包括搭建框架(1天),基础数据模块和权限管理(4天),以及应收应付和销售管理(5天)。 供应链概念:供应链系统的核心流程是通过采购商品放入仓库,并在销售时从仓库提取商品,涉及三个主要订单:采购订单、销售订单和调拨订单。 大数据的应用:介绍了数据挖掘、ETL(数据抽取)和BI(商业智能)在供应链管理中的应用。 技术实现:讲述了DAO(数据访问对象)的重用、服务层的重用、以及前端JS的继承机制、jQuery插件开发等技术细节。 系统框架搭建:包括Maven环境的配置、Web工程的创建、持久化类和映射文件的编写,以及Spring配置文件的实现。 DAO的需求和功能:供应链管理系统的各个模块都涉及分页查询、条件查询、删除、增加、修改操作等需求。 泛型的应用:通过示例说明了在Java语言中如何使用泛型来实现模块化和可扩展性。 文档非常技术导向,适合开发人员参考,用于构建供应链管理系统的架构和功能模块。
这份长达104页的手册由清华大学新闻与传播学院新媒体研究中心元宇宙文化实验室的余梦珑博士后及其团队精心编撰,内容详尽,覆盖了从基础概念、技术原理到实战案例的全方位指导。它不仅适合初学者快速了解DeepSeek的基本操作,也为有经验的用户提供了高级技巧和优化策略。
主题说明: 1、将mxtheme目录放置根目录 | 将mxpro目录放置template文件夹中 2、苹果cms后台-系统-网站参数配置-网站模板-选择mxpro 模板目录填写html 3、网站模板选择好之后一定要先访问前台,然后再进入后台设置 4、主题后台地址: MXTU MAX图图主题,/admin.php/admin/mxpro/mxproset admin.php改成你登录后台的xxx.php 5、首页幻灯片设置视频推荐9,自行后台设置 6、追剧周表在视频数据中,节目周期添加周一至周日自行添加,格式:一,二,三,四,五,六,日
运行GUI版本,可二开