1. 程式人生 > >埋點:結合AOP以及訊息佇列

埋點:結合AOP以及訊息佇列

配置:

    <bean id="agntLogHandler" class="com.sf.pmp.agnt.aop.AgntLogHandler"/>  <!-- (1)你想進行切面的是哪個類呢 -->
    <aop:config proxy-target-class="true">
        <!-- id:指向哪個類;expression:(2)execution:滿足expression中的方法呼叫之後,就會去進行切面操作,類似於觸發了切面;(3)@annotation:應該是什麼註解  -->
        <aop:aspect ref="agntLogHandler">   <!-- ref:指向bean標籤中的id -->   <!-- aspect:切面,指類 -->
            <aop:pointcut id="agntLogPointcut" expression="execution(public * *(..)) and @annotation(agntLog)"/> 
            <aop:around pointcut-ref="agntLogPointcut" method="doAudit"/>  <!-- (4)應該是類中的什麼方法     pointcut-ref:指向pointcut標籤中的id  pointcut:切入點,指方法-->
        </aop:aspect>
    </aop:config>

應用:

    @RequestMapping("list")
    @Action(description="檢視佣金基數配置表分頁列表")
    @AgntLog(moudel="代理招投標管理-基礎配置",operateMenu="佣金基數配置",description="查詢")   // 在這裡哦
    public ModelAndView list(HttpServletRequest request,HttpServletResponse response) throws Exception
    {    
        List<AgntCommissionBase> list=agntCommissionBaseService.getAll(new
QueryFilter(request,"agntCommissionBaseItem")); ModelAndView mv=this.getAutoView().addObject("agntCommissionBaseList",list); return mv; }

 

 切面以及切點:

public class AgntLogHandler {
    private Log logger = LogFactory.getLog(AgntLogHandler.class);
    @Resource 
    
private AgntLogSwitchService agntLogSwitchService; private static AgntWorkQueue wq = new AgntWorkQueue(10); /** * 執行日誌系統記錄 * @param point 橫切點 * @param action 註解 * @throws Throwable */ public Object doAudit(ProceedingJoinPoint point,AgntLog agntLog) throws Throwable { // 入口就是在這裡哦 //如果方法上沒有註解@Action,返回 if (agntLog == null) { return point.proceed(); } //執行物件是否有異常 Throwable throwable = null; //執行結果 String result = "SUCCESS"; //執行物件返回值 Object returnVal = null; String optErrorMsg = null; try { returnVal = point.proceed(); } catch (Throwable t) { throwable = t; optErrorMsg = ExceptionUtils.getStackTrace(throwable); result = "ECXEPTION"; } //日誌記錄 doLog(point,agntLog, result,returnVal,optErrorMsg); //如果執行物件有異常,則丟擲原有異常 if(null != throwable) { throw throwable; } return returnVal; } /** * @param point 橫切點 * @param annotation 註解 * @param async 是否非同步 * @param rtnValue 返回值 */ private void doLog(ProceedingJoinPoint point, AgntLog annotation, String result, Object rtnValue,String optErrorMsg){ //類、類Action Class<?> targetClass = point.getTarget().getClass(); // (java.lang.Class<T>) class com.sf.pmp.agnt.controller.conf.AgntCommissionBaseController try { //歸屬模組(選單) String modelType = annotation.operateMenu(); // 佣金基數配置(跟註釋那裡是一樣的,注意留意註釋) //模組日誌開關(關閉則返回) if(!isOwnerModelLogOpen(modelType)){ return; } //執行的方法 // point.getTarget().getClass().getName():(java.lang.String) com.sf.pmp.agnt.controller.conf.AgntCommissionBaseController // point.getSignature().getName() : (java.lang.String) list // exeMethod:com.sf.pmp.agnt.controller.conf.AgntCommissionBaseController.list( StringBuffer exeMethod = new StringBuffer(targetClass.getName()).append(".").append(point.getSignature().getName()).append("("); Object[] methodArgs = point.getArgs(); if(methodArgs != null && methodArgs.length > 0) { for(Object obj : methodArgs) { exeMethod.append(obj == null?"null":obj.getClass().getName()).append(","); } exeMethod.delete(exeMethod.length()-1, exeMethod.length()); } exeMethod.append(")"); // 日誌資訊封裝 AgntOptLog agntOptLog = new AgntOptLog(); agntOptLog.setOptId(UniqueIdUtil.genId()); agntOptLog.setOptModule(annotation.moudel());//歸屬模組 agntOptLog.setOptType(annotation.operateMenu());;//操作(型別)選單 agntOptLog.setOptSource(annotation.optSource()); agntOptLog.setOptTime(new Date());//操作時間 agntOptLog.setStatus(result);//操作結果 agntOptLog.setOptErrorMsg(optErrorMsg); agntOptLog.setOptDesc(annotation.description());//描述 SysUser curUser = ContextUtil.getCurrentUser(); if (curUser != null) { agntOptLog.setOptAccount(curUser.getAccount()); agntOptLog.setOptName(curUser.getFullname()); agntOptLog.setOrgid(ContextUtil.getCurrentOrgId());//操作使用者歸屬組織ID } HttpServletRequest request = RequestUtil.getHttpServletRequest(); if (request != null) { String fromIp=RequestUtil.getIpAddr(request); agntOptLog.setOptFromIp(fromIp); agntOptLog.setRequestUrl(request.getRequestURI()); } AgntLogHolder logHolder = new AgntLogHolder(); logHolder.setAgntOptLog(agntOptLog); doLogAsync(logHolder); } catch (Exception ex) { logger.error(ex.getMessage(), ex); } finally { SysAuditThreadLocalHolder.clearDetail(); // 看不懂,暫時先不管 SysAuditThreadLocalHolder.clearParameters();// 看不懂,暫時先不管 SysAuditThreadLocalHolder.clearResult();// 看不懂,暫時先不管 SysAuditThreadLocalHolder.clearShouldLog();// 看不懂,暫時先不管 } } private void doLogAsync(AgntLogHolder holder){ AgntLogExecutor logExecutor = new AgntLogExecutor(); logExecutor.setLogHolders(holder); wq.execute(logExecutor); // 佇列的執行方法 } /** * 判斷模組的日誌開關是否開啟 * @param ownermodel 模組 * @return */ synchronized private boolean isOwnerModelLogOpen(String ownermodel){ int status = 0; List<Map<String, Object>> agntLogSwitchs = agntLogSwitchService.getAllCache(); for(Map<String,Object> map : agntLogSwitchs){ if(map.containsKey(ownermodel)){ status = (Integer) map.get(ownermodel); } } return status == 1; } }

 

執行記錄日誌的任務作業

class AgntLogExecutor implements Runnable{
    private Log logger = LogFactory.getLog(AgntLogExecutor.class);
    private AgntLogHolder agntLogHolder;
    private AgntOptLogDao agntOptLogDao;


    public void setLogHolders(AgntLogHolder agntLogHolder) {
        this.agntLogHolder = agntLogHolder;
        this.agntOptLogDao = (AgntOptLogDao) AppUtil.getBean(AgntOptLogDao.class);
    }

    private void doLog() throws TemplateException, IOException{
        AgntOptLog agntOptLog = agntLogHolder.getAgntOptLog();
        String uriString = agntOptLog.getRequestUrl();
        uriString=uriString.toUpperCase();
        agntOptLogDao.insertAgntOptLog(agntOptLog);;
    }
    
    @Override
    public void run() {
        try {
            doLog();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
    
}

 

作業佇列

public class AgntWorkQueue{
    private final int nThreads;
    private final PoolWorker[] threads;
    LinkedList<Runnable> queue;
    
    public AgntWorkQueue(int nThreads){
        this.nThreads=nThreads;
        queue = new LinkedList<Runnable>();
        threads = new PoolWorker[nThreads];
        for(int i=0;i<this.nThreads;i++){
            threads[i] = new PoolWorker();
            threads[i].start();
        }
    }
    
    public void execute(Runnable r){
        synchronized (queue) {
            queue.addLast(r);
            queue.notify();
        }
    }
    
    private class PoolWorker extends Thread{
        private Log logger = LogFactory.getLog(PoolWorker.class);
        public void run(){
            Runnable r;
            while(true){
                synchronized (queue) {
                    while(queue.isEmpty()){
                        try {
                            queue.wait();
                        } catch (InterruptedException e) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                    r=(Runnable)queue.removeFirst();
                }
                try{
                    r.run();
                }catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }
}

 

 自定義日誌註解:

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)   
@Documented  
@Inherited 
public @interface AgntLog {
    /**
     * 操作選單
     * @return
     */
    public String operateMenu() default "";
    
    /**
     * 方法描述
     * @return
     */
    public String description() default "no description";
    
    /**
     * 歸屬模組
     * @return
     */
    public String moudel() default "" ; 
    /**
     * 日誌型別
     * @return
     */
    public String exectype() default "操作日誌";
    
    /**
     * 詳細資訊
     * @return
     */
    public String detail() default "";
    /**
     * 操作來源
     * @return
     */
    public String optSource() default "PC";
     
}

 

END;