ps: 以下转载自http://blog.csdn.net/hardworking0323/article/details/51123712
作者目的是让某个线程只在某台服务器下面执行,比如定时任务只有一台执行。其实也可以利用quartz的集群配置完成
转载目的 只是感觉作者这么实现蛮有意思的。。
appliction-frame.xml配置
- <!-- 应用服务器启动时,启动相应的线程 -->
- <bean id="appThreadStart" class="com.shareinfo.commons.thread.AppThreadStart">
- <!-- 可在多台服务器上同时运行的后台线程 -->
- <property name="multipleThreadObjects">
- <list>
- <value>com.shareinfo.commons.thread.multiple.MultipleCheckOnlineUser</value>
- <value>com.shareinfo.commons.thread.multiple.MultipleInitProperties</value>
- <value>com.shareinfo.commons.thread.multiple.MultipleLogOperation</value>
- <value>com.shareinfo.commons.thread.multiple.MultipleLogUserLogin</value>
- <value>com.shareinfo.commons.thread.multiple.MultipleCheckFixedScanOverdue</value>
- </list>
- </property>
- <!-- 只能在单台服务器上运行的后台线程 -->
- <property name="singleThreadObjects">
- <list>
- <!--
- <value>com.shareinfo.commons.thread.single.services.SingleSmsClient</value>
- <value>com.shareinfo.commons.thread.single.services.SingleEmailClient</value>
- -->
- </list>
- </property>
- <!-- 只能在单台服务器上运行的后台线程,在IP地址为这个的服务器上运行 -->
- <property name="singleIpAddress" value="192.168.1.163" />
- </bean>
- // 后台主线程,用于启动其他线程
- @Log4j
- public class AppThreadStart implements InitializingBean
- {
- // 可在多台服务器上同时运行的后台线程
- @Setter
- private List multipleThreadObjects;
- // 只能在单台服务器上运行的后台线程
- @Setter
- private List singleThreadObjects;
- // 只能在单台服务器上运行的后台线程,在IP地址为这个的服务器上运行
- @Setter
- private String singleIpAddress;
- public void afterPropertiesSet() throws Exception
- {
- if (CollectionUtils.isNotEmpty(multipleThreadObjects))
- {
- Iterator iterator = multipleThreadObjects.iterator();
- while (iterator.hasNext())
- {
- Object object = iterator.next();
- start(object);
- }
- }
- String localHostAddress = NetworkUtils.localHostAddress();
- StringBuffer message = new StringBuffer();
- message.append("LocalHostAddress: " + localHostAddress);
- message.append(", SingleMachineIpAddress: " + singleIpAddress);
- log.info(message.toString());
- if (!StringUtils.equals(localHostAddress, singleIpAddress))
- return;
- if (CollectionUtils.isNotEmpty(singleThreadObjects))
- {
- Iterator iterator = singleThreadObjects.iterator();
- while (iterator.hasNext())
- {
- Object object = iterator.next();
- start(object);
- }
- }
- }
- private void start(Object object)
- {
- if (object == null)
- return;
- if (!(object instanceof String))
- return;
- String clazzName = (String)object;
- if (StringUtils.isEmpty(clazzName))
- return;
- try
- {
- Object thread = Class.forName(clazzName).newInstance();
- if (!(thread instanceof Runnable))
- return;
- new Thread((Runnable)thread).start();
- log.info("Thread [" + clazzName + "] is starting...");
- }
- catch (ClassNotFoundException e)
- {
- log.warn(clazzName + " isn't fund !!");
- }
- catch (InstantiationException e)
- {
- log.warn("InstantiationException: [" + clazzName + "] " + e.getMessage());
- }
- catch (IllegalAccessException e)
- {
- log.warn("IllegalAccessException: [" + clazzName + "] " + e.getMessage());
- }
- catch (Exception e)
- {
- log.warn("Exception: [" + clazzName + "] " + e.getMessage());
- }
- }
- }
逾期定时扫描(多台服务器可运行):
- /**
- * 定时检查逾期定时器是否执行成功
- * @ClassName: MultipleCheckFixedScanOverdue
- * @Description: TODO
- * @author xiaoqun.yi [email protected]
- * @date 2015-9-1 下午02:36:37
- * @version V1.0
- */
- public class MultipleCheckFixedScanOverdue extends AbstractThread {
- private ITaskExecutionService taskExecutionService;
- private ISequenceService sequenceService;
- private NoticeTempToolProxy noticeTempToolProxy;
- public void run() {
- while (isNullServiceBean()) {
- try {
- if (taskExecutionService == null)
- taskExecutionService = (ITaskExecutionService) SpringUtils.getBean("taskExecutionService");
- if (sequenceService == null)
- sequenceService = (ISequenceService) SpringUtils.getBean("sequenceService");
- if (noticeTempToolProxy == null)
- noticeTempToolProxy = (NoticeTempToolProxy) SpringUtils.getBean("noticeTempToolProxy");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- sleepSeconds(10);
- }
- }
- while (true) {
- try {
- TaskExecutionQuery taskExecutionQuery= new TaskExecutionQuery();
- taskExecutionQuery.setTaskType(TaskExecution.TaskType.overdueScan);
- taskExecutionQuery.setStatus("SUCCESS");
- taskExecutionQuery.setSmsFlag("N");
- taskExecutionQuery.setEmailFlag("N");
- Calendar cal=Calendar.getInstance();
- int hour=cal.get(Calendar.HOUR_OF_DAY);
- /**每天凌晨1点以后开始检查逾期定时器是否执行成功*/
- if(hour>=1){
- boolean overdueScanFlag=taskExecutionService.isExecutedDayTask(taskExecutionQuery);
- if(!overdueScanFlag){
- /**任务类型为逾期扫描检查*/
- taskExecutionQuery.setTaskType(TaskExecution.TaskType.overdueScanCheck);
- /**判断当天是否已经发送短信或者邮件*/
- taskExecutionQuery.setSmsFlag("Y");
- taskExecutionQuery.setEmailFlag("N");
- boolean smsFlag=taskExecutionService.isExecutedDayTask(taskExecutionQuery);
- taskExecutionQuery.setSmsFlag("N");
- taskExecutionQuery.setEmailFlag("Y");
- boolean emailFlag= taskExecutionService.isExecutedDayTask(taskExecutionQuery);
- /**如果没有发送短信或邮件*/
- if(!smsFlag||!emailFlag){
- TaskExecution taskExecution=new TaskExecution();
- taskExecution.setTaskType(TaskExecution.TaskType.overdueScanCheck);
- taskExecution.setTaskName("逾期定时扫描检查执行情况");
- taskExecution.setInsertBy("sys");//系统
- if(!smsFlag){
- /**发送短信*/
- Map<String,Object> param=new HashMap<String, Object>();
- Map<String,Object> result=new HashMap<String, Object>();
- param.put("mobile", "18684894397");
- param.put("smsContent", "当天逾期定时器未成功执行,请手动执行并检查原因.");
- result=noticeTempToolProxy.sendSms(param);
- if(null!=result){
- Map<String,Object> statusResult=(Map<String, Object>) result.get("data");
- if(null!=statusResult&&statusResult.get("status").toString().equals("1")){
- taskExecution.setId(sequenceService.nextval(Sequence.SEQ_TASK_EXECUTION));
- taskExecution.setStatus("SUCCESS");
- taskExecution.setSmsFlag("Y");
- taskExecution.setEmailFlag("N");
- taskExecutionService.insert(taskExecution);
- }
- }
- }
- if(!emailFlag){
- /**发送邮件*/
- Map<String,Object> param=new HashMap<String, Object>();
- Map<String,Object> result=new HashMap<String, Object>();
- param.put("email", "[email protected]");
- param.put("emailContent", "当天逾期定时器未成功执行,请手动执行并检查原因.");
- result=noticeTempToolProxy.sendEmail(param);
- if(null!=result){
- Map<String,Object> statusResult=(Map<String, Object>) result.get("data");
- if(null!=statusResult&&statusResult.get("status").toString().equals("1")){
- taskExecution.setId(sequenceService.nextval(Sequence.SEQ_TASK_EXECUTION));
- taskExecution.setStatus("SUCCESS");
- taskExecution.setSmsFlag("N");
- taskExecution.setEmailFlag("Y");
- taskExecutionService.insert(taskExecution);
- }
- }
- }
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- sleepMinuts(10);
- }
- }
- }
- /**
- * 检查Service Bean是否加载完毕
- */
- public boolean isNullServiceBean() {
- if (taskExecutionService == null)
- return true;
- if (sequenceService == null)
- return true;
- if (noticeTempToolProxy == null)
- return true;
- return false;
- }
- }
邮件发送客户端(单台服务器运行):
- public class SingleEmailClient extends AbstractThread
- {
- private ILogEmailService logEmailService = null;
- public void run()
- {
- while (isNullServiceBean())
- {
- try
- {
- if (logEmailService == null)
- logEmailService = (ILogEmailService)SpringUtils.getBean("logEmailService");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- sleepSeconds(10);
- }
- }
- // 查询短信列表中的进行发送
- while (true)
- {
- try
- {
- send();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- sleepMinuts(1);
- }
- }
- }
- /**
- * 检查Service Bean是否加载完毕
- */
- public boolean isNullServiceBean()
- {
- if (logEmailService == null)
- return true;
- return false;
- }
- /**
- * 检查待发送的邮件,并发送
- */
- private void send()
- {
- LogEmailQuery query = new LogEmailQuery();
- query.setExpectSendTimeTo(DateUtils.currentTime("yyyy-MM-dd HH:mm:ss"));
- List<LogEmail> emailList = logEmailService.selectList(query, new Page(1, 200));
- if (CollectionUtils.isEmpty(emailList))
- return;
- List<String> successIdList = new ArrayList<String>();
- List<String> failIdList = new ArrayList<String>();
- for (LogEmail email : emailList)
- {
- if (NumberUtils.defaultInt(email.getSendTimes(), 0) >= 3)
- {
- List<String> list = Arrays.asList(new String[] { String.valueOf(email.getId()) });
- logEmailService.insertHis(list, IConstants.FAIL);
- continue;
- }
- String to = email.getMailTo();
- String subject = email.getSubject();
- String message = email.getMessage();
- String smtp = email.getSmtp();
- String user = email.getAuthUser();
- String password = email.getAuthPassword();
- String nick = email.getNick();
- String from = email.getMailFrom();
- EmailService emailService = new EmailService(smtp, user, password, nick, from, to);
- boolean isSuccess = emailService.send(subject, message);
- if (isSuccess)
- successIdList.add(String.valueOf(email.getId()));
- else
- failIdList.add(String.valueOf(email.getId()));
- }
- if (CollectionUtils.isNotEmpty(successIdList))
- logEmailService.insertHis(successIdList, IConstants.SUCCESS);
- if (CollectionUtils.isNotEmpty(failIdList))
- logEmailService.updateList(failIdList, IConstants.FAIL);
- }
- }
类似的一篇
- public class ClusterUtils {
- private static Log log = LogFactory.getLog(ClusterUtils.class);
- /**
- * 存储服务器已授权的可执行方法(applicationContext-frame.xml中配置)
- */
- private static Map<String, String> authorityMap;
- public static void setAuthorityMap(Map<String, String> authorityMap) {
- ClusterUtils.authorityMap = authorityMap;
- }
- /**
- * 判断当前服务器是否有权限执行当前方法(true:有权限)
- * (applicationContext-frame.xml中配置)
- * @Title: hasExecAuthority
- * @Description:
- * @author baolin.liu
- * @date 2015-8-31 下午04:12:09
- * @return
- * @return boolean
- */
- public static boolean hasExecAuthority() {
- StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
- String key = stackTraces[2].getClassName() + "." + stackTraces[2].getMethodName();
- String localHostAddress = NetworkUtils.localHostAddress();
- if (authorityMap.containsKey(key)) {
- String values = authorityMap.get(key);
- if (values != null && !values.contains(localHostAddress)) {
- log.info("当前服务器放弃执行:" + key + " 当前服务器ip[" + localHostAddress + "]" + " 目标服务器ip[" + values + "]");
- return false;
- }
- }
- log.info("当前服务器允许执行:" + key + " 当前服务器ip[" + localHostAddress + "]");
- return true;
- }
- }
调用执行方法前先判断服务器是否有权限
- @Transactional
- @Service
- public class FixedScanOverdueService implements IFixedScanOverdueService {
- //日志
- private Log log = LogFactory.getLog(FixedScanOverdueService.class);
- @Resource
- private IProjectRepayPlanDao projectRepayPlanDao;
- @Resource
- private IProjectDao projectDao;
- @Resource
- private IPlanZyEqInteEqPrinciService planZyEqInteEqPrinciService ;
- @Resource
- private ITaskExecutionDao taskExecutionDao;
- @Resource
- private ISequenceService sequenceService;
- /**定时逾期扫描*/
- public boolean process(String userId) {
- /** 指定服务器运行的方法 **/
- if(!ClusterUtils.hasExecAuthority()){
- return false;
- }
- log.info("******逾期扫描定时器任务启动开始******");
- TaskExecution taskExecution=new TaskExecution();
- try{
- taskExecution.setId(sequenceService.nextval(Sequence.SEQ_TASK_EXECUTION));
- taskExecution.setTaskType(TaskExecution.TaskType.overdueScan);
- taskExecution.setTaskName("逾期定时扫描");
- taskExecution.setInsertBy(userId);
- taskExecution.setSmsFlag("N");
- taskExecution.setEmailFlag("N");
- /**1.取出逾期列表数据*/
- List<ProjectRepayPlan> planlist= projectRepayPlanDao.getProjectRepayOverdueList(null, null);
- /**取出逾期的项目列表数据*/
- List<Long> projectList=getProjectIdList(planlist);
- /**还款逾期插入集合数据*/
- List<ProjectRepayPlan> overdueList=projectRepayPlanDao.getProjectRepayOverdueInsertList(null, null);
- /**2.计算当期逾期罚息*/
- planlist=computeYqMoney(null,planlist);
- /**3.计算当期应还金额**/
- planlist=planZyEqInteEqPrinciService.step50(null,planlist);
- /**4.计算当期结清罚息*/
- planlist=computeJqYqMoneyList(planlist);
- /**5.计算当结清金额 */
- planlist=planZyEqInteEqPrinciService.step60(null,planlist);
- /**6.剩余实际应还金额(实际应还金额 - 实还金额) */
- planlist=computeSyMoney(planlist);
- /**7.更新还款计划中的逾期天数,逾期罚息,应还金额,结清罚息,当期结清金额,剩余实际应还金额*/
- if(null!=planlist&&planlist.size()>0){
- projectRepayPlanDao.batchUpdateOverdueRepayPlan(planlist);
- }
- /**8.更新项目逾期流程处理*/
- if(null!=projectList&&projectList.size()>0){
- projectDao.batchUpdateProjectStatus(projectList,ChainStorePropertyLoanStatusEnum.OVERDUE.toString());
- }
- /**9.批量增加还款逾期数据*/
- if(null!=overdueList&&overdueList.size()>0){
- projectRepayPlanDao.batchInsertRepayOverdue(overdueList);
- }
- taskExecution.setStatus("SUCCESS");
- log.info("******逾期扫定时器任务启动完成******");
- }catch(Exception e){
- taskExecution.setStatus("FAIL");
- taskExecution.setRemark("逾期扫描定时任务执行失败:"+e.getMessage());
- log.info("******逾期扫定时器任务出现异常******");
- log.error("", e);
- throw new RuntimeException("逾期定时器执行失败");
- }finally{
- taskExecutionDao.insert(taskExecution);
- }
- return true;
- }
appliaction-frame.xml中配置
- <!-- 集群环境配置 -->
- <bean class="com.shareinfo.commons.utils.ClusterUtils">
- <!-- 配置某方法只能在指定的服务器中调用 -->
- <property name="authorityMap">
- <map>
- <entry key="com.shareinfo.customer.service.impl.FixedScanOverdueService.process" value="192.168.1.100" />
- </map>
- </property>
- </bean>
- <!-- END 集群环境配置 -->
集群工具类:
- public class ClusterUtils {
- private static Log log = LogFactory.getLog(ClusterUtils.class);
- /**
- * 存储服务器已授权的可执行方法(applicationContext-frame.xml中配置)
- */
- private static Map<String, String> authorityMap;
- public static void setAuthorityMap(Map<String, String> authorityMap) {
- ClusterUtils.authorityMap = authorityMap;
- }
- /**
- * 判断当前服务器是否有权限执行当前方法(true:有权限)
- * (applicationContext-frame.xml中配置)
- * @Title: hasExecAuthority
- * @Description:
- * @author baolin.liu
- * @date 2015-8-31 下午04:12:09
- * @return
- * @return boolean
- */
- public static boolean hasExecAuthority() {
- StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
- String key = stackTraces[2].getClassName() + "." + stackTraces[2].getMethodName();
- String localHostAddress = NetworkUtils.localHostAddress();
- if (authorityMap.containsKey(key)) {
- String values = authorityMap.get(key);
- if (values != null && !values.contains(localHostAddress)) {
- log.info("当前服务器放弃执行:" + key + " 当前服务器ip[" + localHostAddress + "]" + " 目标服务器ip[" + values + "]");
- return false;
- }
- }
- log.info("当前服务器允许执行:" + key + " 当前服务器ip[" + localHostAddress + "]");
- return true;
- }
- }