Bootstrap

分布式之_多线程之指定线程运行服务器


ps: 以下转载自http://blog.csdn.net/hardworking0323/article/details/51123712


作者目的是让某个线程只在某台服务器下面执行,比如定时任务只有一台执行。其实也可以利用quartz的集群配置完成

转载目的 只是感觉作者这么实现蛮有意思的。。





appliction-frame.xml配置

[html]  view plain  copy
  1. <!-- 应用服务器启动时,启动相应的线程 -->  
  2.     <bean id="appThreadStart" class="com.shareinfo.commons.thread.AppThreadStart">  
  3.         <!-- 可在多台服务器上同时运行的后台线程 -->  
  4.         <property name="multipleThreadObjects">  
  5.             <list>  
  6.                 <value>com.shareinfo.commons.thread.multiple.MultipleCheckOnlineUser</value>  
  7.                 <value>com.shareinfo.commons.thread.multiple.MultipleInitProperties</value>  
  8.                 <value>com.shareinfo.commons.thread.multiple.MultipleLogOperation</value>  
  9.                 <value>com.shareinfo.commons.thread.multiple.MultipleLogUserLogin</value>  
  10.                 <value>com.shareinfo.commons.thread.multiple.MultipleCheckFixedScanOverdue</value>  
  11.             </list>  
  12.         </property>  
  13.         <!-- 只能在单台服务器上运行的后台线程 -->  
  14.         <property name="singleThreadObjects">  
  15.             <list>  
  16.                 <!--  
  17.                 <value>com.shareinfo.commons.thread.single.services.SingleSmsClient</value>  
  18.                 <value>com.shareinfo.commons.thread.single.services.SingleEmailClient</value>  
  19.                 -->  
  20.             </list>  
  21.         </property>  
  22.         <!-- 只能在单台服务器上运行的后台线程,在IP地址为这个的服务器上运行 -->  
  23.         <property name="singleIpAddress" value="192.168.1.163" />  
  24.     </bean>  
后台主线程,用于启动其他线程,这里使用Spring的InitializingBean的afterPropertiesSet()方法来初始化后台主线程,即web容器启动,取初始启动后台主线程

[java]  view plain  copy
  1. // 后台主线程,用于启动其他线程  
  2. @Log4j  
  3. public class AppThreadStart implements InitializingBean  
  4. {  
  5.     // 可在多台服务器上同时运行的后台线程  
  6.     @Setter  
  7.     private List multipleThreadObjects;  
  8.   
  9.     // 只能在单台服务器上运行的后台线程  
  10.     @Setter  
  11.     private List singleThreadObjects;  
  12.   
  13.     // 只能在单台服务器上运行的后台线程,在IP地址为这个的服务器上运行  
  14.     @Setter  
  15.     private String singleIpAddress;  
  16.   
  17.     public void afterPropertiesSet() throws Exception  
  18.     {  
  19.         if (CollectionUtils.isNotEmpty(multipleThreadObjects))  
  20.         {  
  21.             Iterator iterator = multipleThreadObjects.iterator();  
  22.             while (iterator.hasNext())  
  23.             {  
  24.                 Object object = iterator.next();  
  25.                 start(object);  
  26.             }  
  27.         }  
  28.   
  29.         String localHostAddress = NetworkUtils.localHostAddress();  
  30.   
  31.         StringBuffer message = new StringBuffer();  
  32.         message.append("LocalHostAddress: " + localHostAddress);  
  33.         message.append(", SingleMachineIpAddress: " + singleIpAddress);  
  34.         log.info(message.toString());  
  35.   
  36.         if (!StringUtils.equals(localHostAddress, singleIpAddress))  
  37.             return;  
  38.   
  39.         if (CollectionUtils.isNotEmpty(singleThreadObjects))  
  40.         {  
  41.             Iterator iterator = singleThreadObjects.iterator();  
  42.             while (iterator.hasNext())  
  43.             {  
  44.                 Object object = iterator.next();  
  45.                 start(object);  
  46.             }  
  47.         }  
  48.     }  
  49.   
  50.     private void start(Object object)  
  51.     {  
  52.         if (object == null)  
  53.             return;  
  54.   
  55.         if (!(object instanceof String))  
  56.             return;  
  57.   
  58.         String clazzName = (String)object;  
  59.         if (StringUtils.isEmpty(clazzName))  
  60.             return;  
  61.   
  62.         try  
  63.         {  
  64.             Object thread = Class.forName(clazzName).newInstance();  
  65.             if (!(thread instanceof Runnable))  
  66.                 return;  
  67.   
  68.             new Thread((Runnable)thread).start();  
  69.             log.info("Thread [" + clazzName + "] is starting...");  
  70.         }  
  71.         catch (ClassNotFoundException e)  
  72.         {  
  73.             log.warn(clazzName + " isn't fund !!");  
  74.         }  
  75.         catch (InstantiationException e)  
  76.         {  
  77.             log.warn("InstantiationException: [" + clazzName + "] " + e.getMessage());  
  78.         }  
  79.         catch (IllegalAccessException e)  
  80.         {  
  81.             log.warn("IllegalAccessException: [" + clazzName + "] " + e.getMessage());  
  82.         }  
  83.         catch (Exception e)  
  84.         {  
  85.             log.warn("Exception: [" + clazzName + "] " + e.getMessage());  
  86.         }  
  87.     }  
  88. }  

逾期定时扫描(多台服务器可运行):

[java]  view plain  copy
  1. /** 
  2.  * 定时检查逾期定时器是否执行成功 
  3.  * @ClassName: MultipleCheckFixedScanOverdue  
  4.  * @Description: TODO  
  5.  * @author xiaoqun.yi  [email protected] 
  6.  * @date 2015-9-1 下午02:36:37  
  7.  * @version V1.0 
  8.  */  
  9. public class MultipleCheckFixedScanOverdue extends AbstractThread {  
  10.   
  11.     private ITaskExecutionService taskExecutionService;  
  12.   
  13.     private ISequenceService sequenceService;  
  14.       
  15.     private NoticeTempToolProxy noticeTempToolProxy;  
  16.       
  17.     public void run() {  
  18.         while (isNullServiceBean()) {  
  19.             try {  
  20.                 if (taskExecutionService == null)  
  21.                     taskExecutionService = (ITaskExecutionService) SpringUtils.getBean("taskExecutionService");  
  22.                   
  23.                 if (sequenceService == null)  
  24.                     sequenceService = (ISequenceService) SpringUtils.getBean("sequenceService");  
  25.                   
  26.                 if (noticeTempToolProxy == null)  
  27.                     noticeTempToolProxy = (NoticeTempToolProxy) SpringUtils.getBean("noticeTempToolProxy");  
  28.                   
  29.             } catch (Exception e) {  
  30.                 e.printStackTrace();  
  31.             } finally {  
  32.                 sleepSeconds(10);  
  33.             }  
  34.         }  
  35.   
  36.         while (true) {  
  37.             try {  
  38.                 TaskExecutionQuery taskExecutionQuery= new TaskExecutionQuery();  
  39.                 taskExecutionQuery.setTaskType(TaskExecution.TaskType.overdueScan);  
  40.                 taskExecutionQuery.setStatus("SUCCESS");  
  41.                 taskExecutionQuery.setSmsFlag("N");  
  42.                 taskExecutionQuery.setEmailFlag("N");  
  43.                 Calendar cal=Calendar.getInstance();  
  44.                 int hour=cal.get(Calendar.HOUR_OF_DAY);  
  45.                 /**每天凌晨1点以后开始检查逾期定时器是否执行成功*/  
  46.                 if(hour>=1){  
  47.                     boolean overdueScanFlag=taskExecutionService.isExecutedDayTask(taskExecutionQuery);  
  48.                     if(!overdueScanFlag){  
  49.                         /**任务类型为逾期扫描检查*/  
  50.                         taskExecutionQuery.setTaskType(TaskExecution.TaskType.overdueScanCheck);  
  51.                         /**判断当天是否已经发送短信或者邮件*/  
  52.                         taskExecutionQuery.setSmsFlag("Y");  
  53.                         taskExecutionQuery.setEmailFlag("N");  
  54.                         boolean smsFlag=taskExecutionService.isExecutedDayTask(taskExecutionQuery);  
  55.                         taskExecutionQuery.setSmsFlag("N");  
  56.                         taskExecutionQuery.setEmailFlag("Y");  
  57.                         boolean emailFlag= taskExecutionService.isExecutedDayTask(taskExecutionQuery);  
  58.                         /**如果没有发送短信或邮件*/  
  59.                         if(!smsFlag||!emailFlag){  
  60.                             TaskExecution taskExecution=new TaskExecution();  
  61.                             taskExecution.setTaskType(TaskExecution.TaskType.overdueScanCheck);  
  62.                             taskExecution.setTaskName("逾期定时扫描检查执行情况");  
  63.                             taskExecution.setInsertBy("sys");//系统   
  64.                             if(!smsFlag){  
  65.                                 /**发送短信*/  
  66.                                 Map<String,Object> param=new HashMap<String, Object>();  
  67.                                 Map<String,Object> result=new HashMap<String, Object>();  
  68.                                 param.put("mobile""18684894397");  
  69.                                 param.put("smsContent""当天逾期定时器未成功执行,请手动执行并检查原因.");  
  70.                                 result=noticeTempToolProxy.sendSms(param);  
  71.                                 if(null!=result){  
  72.                                     Map<String,Object> statusResult=(Map<String, Object>) result.get("data");  
  73.                                     if(null!=statusResult&&statusResult.get("status").toString().equals("1")){  
  74.                                         taskExecution.setId(sequenceService.nextval(Sequence.SEQ_TASK_EXECUTION));  
  75.                                         taskExecution.setStatus("SUCCESS");  
  76.                                         taskExecution.setSmsFlag("Y");  
  77.                                         taskExecution.setEmailFlag("N");  
  78.                                         taskExecutionService.insert(taskExecution);  
  79.                                     }  
  80.                                 }  
  81.                             }  
  82.                             if(!emailFlag){  
  83.                                 /**发送邮件*/  
  84.                                 Map<String,Object> param=new HashMap<String, Object>();  
  85.                                 Map<String,Object> result=new HashMap<String, Object>();  
  86.                                 param.put("email""[email protected]");  
  87.                                 param.put("emailContent""当天逾期定时器未成功执行,请手动执行并检查原因.");  
  88.                                 result=noticeTempToolProxy.sendEmail(param);  
  89.                                 if(null!=result){  
  90.                                     Map<String,Object> statusResult=(Map<String, Object>) result.get("data");  
  91.                                     if(null!=statusResult&&statusResult.get("status").toString().equals("1")){  
  92.                                         taskExecution.setId(sequenceService.nextval(Sequence.SEQ_TASK_EXECUTION));  
  93.                                         taskExecution.setStatus("SUCCESS");  
  94.                                         taskExecution.setSmsFlag("N");  
  95.                                         taskExecution.setEmailFlag("Y");  
  96.                                         taskExecutionService.insert(taskExecution);  
  97.                                     }  
  98.                                 }  
  99.                                   
  100.                             }  
  101.                         }  
  102.                     }  
  103.                 }  
  104.             } catch (Exception e) {  
  105.                 e.printStackTrace();  
  106.             } finally {  
  107.                 sleepMinuts(10);  
  108.             }  
  109.         }  
  110.     }  
  111.   
  112.     /** 
  113.      * 检查Service Bean是否加载完毕 
  114.      */  
  115.     public boolean isNullServiceBean() {  
  116.         if (taskExecutionService == null)  
  117.             return true;  
  118.           
  119.         if (sequenceService == null)  
  120.             return true;  
  121.           
  122.         if (noticeTempToolProxy == null)  
  123.             return true;  
  124.           
  125.         return false;  
  126.     }  
  127.   
  128. }  

 邮件发送客户端(单台服务器运行):

[java]  view plain  copy
  1. public class SingleEmailClient extends AbstractThread  
  2. {  
  3.     private ILogEmailService logEmailService = null;  
  4.   
  5.     public void run()  
  6.     {  
  7.         while (isNullServiceBean())  
  8.         {  
  9.             try  
  10.             {  
  11.                 if (logEmailService == null)  
  12.                     logEmailService = (ILogEmailService)SpringUtils.getBean("logEmailService");  
  13.             }  
  14.             catch (Exception e)  
  15.             {  
  16.                 e.printStackTrace();  
  17.             }  
  18.             finally  
  19.             {  
  20.                 sleepSeconds(10);  
  21.             }  
  22.         }  
  23.   
  24.         // 查询短信列表中的进行发送  
  25.         while (true)  
  26.         {  
  27.             try  
  28.             {  
  29.                 send();  
  30.             }  
  31.             catch (Exception e)  
  32.             {  
  33.                 e.printStackTrace();  
  34.             }  
  35.             finally  
  36.             {  
  37.                 sleepMinuts(1);  
  38.             }  
  39.         }  
  40.     }  
  41.   
  42.     /** 
  43.      * 检查Service Bean是否加载完毕 
  44.      */  
  45.     public boolean isNullServiceBean()  
  46.     {  
  47.         if (logEmailService == null)  
  48.             return true;  
  49.   
  50.         return false;  
  51.     }  
  52.   
  53.     /** 
  54.      * 检查待发送的邮件,并发送 
  55.      */  
  56.     private void send()  
  57.     {  
  58.         LogEmailQuery query = new LogEmailQuery();  
  59.         query.setExpectSendTimeTo(DateUtils.currentTime("yyyy-MM-dd HH:mm:ss"));  
  60.   
  61.         List<LogEmail> emailList = logEmailService.selectList(query, new Page(1200));  
  62.         if (CollectionUtils.isEmpty(emailList))  
  63.             return;  
  64.   
  65.         List<String> successIdList = new ArrayList<String>();  
  66.         List<String> failIdList = new ArrayList<String>();  
  67.         for (LogEmail email : emailList)  
  68.         {  
  69.             if (NumberUtils.defaultInt(email.getSendTimes(), 0) >= 3)  
  70.             {  
  71.                 List<String> list = Arrays.asList(new String[] { String.valueOf(email.getId()) });  
  72.                 logEmailService.insertHis(list, IConstants.FAIL);  
  73.                 continue;  
  74.             }  
  75.   
  76.             String to = email.getMailTo();  
  77.             String subject = email.getSubject();  
  78.             String message = email.getMessage();  
  79.   
  80.             String smtp = email.getSmtp();  
  81.             String user = email.getAuthUser();  
  82.             String password = email.getAuthPassword();  
  83.             String nick = email.getNick();  
  84.             String from = email.getMailFrom();  
  85.   
  86.             EmailService emailService = new EmailService(smtp, user, password, nick, from, to);  
  87.             boolean isSuccess = emailService.send(subject, message);  
  88.             if (isSuccess)  
  89.                 successIdList.add(String.valueOf(email.getId()));  
  90.             else  
  91.                 failIdList.add(String.valueOf(email.getId()));  
  92.         }  
  93.   
  94.         if (CollectionUtils.isNotEmpty(successIdList))  
  95.             logEmailService.insertHis(successIdList, IConstants.SUCCESS);  
  96.   
  97.         if (CollectionUtils.isNotEmpty(failIdList))  
  98.             logEmailService.updateList(failIdList, IConstants.FAIL);  
  99.     }  
  100. }  

类似的一篇


 

分布式_指定方法在指定的服务器运行


  1. public class ClusterUtils {  
  2.       
  3.     private static Log log = LogFactory.getLog(ClusterUtils.class);  
  4.       
  5.     /** 
  6.      * 存储服务器已授权的可执行方法(applicationContext-frame.xml中配置) 
  7.      */  
  8.     private static Map<String, String> authorityMap;  
  9.       
  10.     public static void setAuthorityMap(Map<String, String> authorityMap) {  
  11.         ClusterUtils.authorityMap = authorityMap;  
  12.     }  
  13.   
  14.     /** 
  15.      * 判断当前服务器是否有权限执行当前方法(true:有权限) 
  16.      * (applicationContext-frame.xml中配置) 
  17.      * @Title: hasExecAuthority 
  18.      * @Description:  
  19.      * @author baolin.liu  
  20.      * @date 2015-8-31 下午04:12:09 
  21.      * @return     
  22.      * @return boolean 
  23.      */  
  24.     public static boolean hasExecAuthority() {  
  25.         StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();  
  26.         String key = stackTraces[2].getClassName() + "." + stackTraces[2].getMethodName();  
  27.         String localHostAddress = NetworkUtils.localHostAddress();  
  28.   
  29.         if (authorityMap.containsKey(key)) {  
  30.             String values = authorityMap.get(key);  
  31.             if (values != null && !values.contains(localHostAddress)) {  
  32.                 log.info("当前服务器放弃执行:" + key + " 当前服务器ip[" + localHostAddress + "]" + " 目标服务器ip[" + values + "]");  
  33.                 return false;  
  34.             }  
  35.         }  
  36.   
  37.         log.info("当前服务器允许执行:" + key + " 当前服务器ip[" + localHostAddress + "]");  
  38.         return true;  
  39.     }  
  40.       
  41. }  

调用执行方法前先判断服务器是否有权限

[java]  view plain  copy
  1. @Transactional  
  2. @Service  
  3. public class FixedScanOverdueService implements IFixedScanOverdueService {  
  4.     //日志  
  5.     private Log log = LogFactory.getLog(FixedScanOverdueService.class);  
  6.     @Resource  
  7.     private IProjectRepayPlanDao projectRepayPlanDao;  
  8.     @Resource  
  9.     private IProjectDao projectDao;  
  10.     @Resource  
  11.     private IPlanZyEqInteEqPrinciService planZyEqInteEqPrinciService ;  
  12.       
  13.     @Resource  
  14.     private ITaskExecutionDao taskExecutionDao;  
  15.       
  16.     @Resource  
  17.     private ISequenceService sequenceService;  
  18.       
  19.     /**定时逾期扫描*/  
  20.     public boolean process(String userId) {  
  21.         /** 指定服务器运行的方法 **/  
  22.         if(!ClusterUtils.hasExecAuthority()){  
  23.             return false;  
  24.         }  
  25.           
  26.         log.info("******逾期扫描定时器任务启动开始******");  
  27.         TaskExecution taskExecution=new TaskExecution();  
  28.         try{  
  29.             taskExecution.setId(sequenceService.nextval(Sequence.SEQ_TASK_EXECUTION));  
  30.             taskExecution.setTaskType(TaskExecution.TaskType.overdueScan);  
  31.             taskExecution.setTaskName("逾期定时扫描");  
  32.             taskExecution.setInsertBy(userId);  
  33.             taskExecution.setSmsFlag("N");  
  34.             taskExecution.setEmailFlag("N");  
  35.             /**1.取出逾期列表数据*/  
  36.             List<ProjectRepayPlan> planlist= projectRepayPlanDao.getProjectRepayOverdueList(nullnull);  
  37.             /**取出逾期的项目列表数据*/  
  38.             List<Long> projectList=getProjectIdList(planlist);  
  39.             /**还款逾期插入集合数据*/  
  40.             List<ProjectRepayPlan>  overdueList=projectRepayPlanDao.getProjectRepayOverdueInsertList(nullnull);  
  41.             /**2.计算当期逾期罚息*/  
  42.             planlist=computeYqMoney(null,planlist);  
  43.             /**3.计算当期应还金额**/  
  44.             planlist=planZyEqInteEqPrinciService.step50(null,planlist);  
  45.             /**4.计算当期结清罚息*/  
  46.             planlist=computeJqYqMoneyList(planlist);  
  47.             /**5.计算当结清金额 */  
  48.             planlist=planZyEqInteEqPrinciService.step60(null,planlist);  
  49.             /**6.剩余实际应还金额(实际应还金额 - 实还金额) */  
  50.             planlist=computeSyMoney(planlist);  
  51.             /**7.更新还款计划中的逾期天数,逾期罚息,应还金额,结清罚息,当期结清金额,剩余实际应还金额*/  
  52.             if(null!=planlist&&planlist.size()>0){  
  53.                 projectRepayPlanDao.batchUpdateOverdueRepayPlan(planlist);  
  54.             }  
  55.             /**8.更新项目逾期流程处理*/  
  56.             if(null!=projectList&&projectList.size()>0){  
  57.                  projectDao.batchUpdateProjectStatus(projectList,ChainStorePropertyLoanStatusEnum.OVERDUE.toString());  
  58.             }  
  59.             /**9.批量增加还款逾期数据*/  
  60.             if(null!=overdueList&&overdueList.size()>0){  
  61.                 projectRepayPlanDao.batchInsertRepayOverdue(overdueList);  
  62.             }  
  63.             taskExecution.setStatus("SUCCESS");  
  64.             log.info("******逾期扫定时器任务启动完成******");  
  65.         }catch(Exception e){  
  66.             taskExecution.setStatus("FAIL");  
  67.             taskExecution.setRemark("逾期扫描定时任务执行失败:"+e.getMessage());  
  68.             log.info("******逾期扫定时器任务出现异常******");  
  69.             log.error("", e);  
  70.             throw new RuntimeException("逾期定时器执行失败");  
  71.         }finally{  
  72.             taskExecutionDao.insert(taskExecution);  
  73.         }  
  74.         return true;  
  75.     }  

appliaction-frame.xml中配置

[html]  view plain  copy
  1. <!-- 集群环境配置 -->  
  2.     <bean class="com.shareinfo.commons.utils.ClusterUtils">  
  3.         <!-- 配置某方法只能在指定的服务器中调用 -->  
  4.         <property name="authorityMap">  
  5.             <map>  
  6.                 <entry key="com.shareinfo.customer.service.impl.FixedScanOverdueService.process" value="192.168.1.100" />  
  7.             </map>  
  8.         </property>  
  9.     </bean>  
  10.     <!-- END 集群环境配置 -->  

 集群工具类:

[java]  view plain  copy
  1. public class ClusterUtils {  
  2.       
  3.     private static Log log = LogFactory.getLog(ClusterUtils.class);  
  4.       
  5.     /** 
  6.      * 存储服务器已授权的可执行方法(applicationContext-frame.xml中配置) 
  7.      */  
  8.     private static Map<String, String> authorityMap;  
  9.       
  10.     public static void setAuthorityMap(Map<String, String> authorityMap) {  
  11.         ClusterUtils.authorityMap = authorityMap;  
  12.     }  
  13.   
  14.     /** 
  15.      * 判断当前服务器是否有权限执行当前方法(true:有权限) 
  16.      * (applicationContext-frame.xml中配置) 
  17.      * @Title: hasExecAuthority 
  18.      * @Description:  
  19.      * @author baolin.liu  
  20.      * @date 2015-8-31 下午04:12:09 
  21.      * @return     
  22.      * @return boolean 
  23.      */  
  24.     public static boolean hasExecAuthority() {  
  25.         StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();  
  26.         String key = stackTraces[2].getClassName() + "." + stackTraces[2].getMethodName();  
  27.         String localHostAddress = NetworkUtils.localHostAddress();  
  28.   
  29.         if (authorityMap.containsKey(key)) {  
  30.             String values = authorityMap.get(key);  
  31.             if (values != null && !values.contains(localHostAddress)) {  
  32.                 log.info("当前服务器放弃执行:" + key + " 当前服务器ip[" + localHostAddress + "]" + " 目标服务器ip[" + values + "]");  
  33.                 return false;  
  34.             }  
  35.         }  
  36.   
  37.         log.info("当前服务器允许执行:" + key + " 当前服务器ip[" + localHostAddress + "]");  
  38.         return true;  
  39.     }  
  40.       
  41. }  


;