zoukankan      html  css  js  c++  java
  • 埋点:结合AOP以及消息队列

    配置(这个埋点的事务到底怎么弄,一直都没有配成功):

        <!-- execution(* com.sf.pmp.http.controller.AgntSignUpController.*(..))" -->
        <!-- 第一个*表示任意返回值;表示这个类;第二个*表示这个类下面的任意方法; (..)表示任意类型和参数-->
        <!-- 只要切点满足上面的条件,就会触发切面aspect(类),以及那个方法method(配置在通知那里) -->
        
        <bean id="agntLogHandler" class="com.sf.pmp.agnt.aop.AgntLogHandler"/>  <!-- (1)你想进行切面的是哪个类呢 -->
        
        <aop:config proxy-target-class="true">
        
            <!-- <aop:advisor advice-ref="txAdvice" pointcut="(execution(* com.sf.pmp.*.service.*.*(..)) or execution(* com.sf.pmp.*.controller..*.*(..)))"  /> -->
            <!-- <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.sf.pmp.*.*.*.*(..))"  /> -->
            <!-- <aop:advisor advice-ref="txAdvice" pointcut-ref="agntLogPointcut"  /> -->
            
            <!-- aspect:切面是通知和切点的集合,通知和切点共同定义了切面的全部功能——它是什么,在何时何处完成其功能。 -->
            <aop:aspect ref="agntLogHandler">   <!-- ref:指向bean标签中的id,因为id代表了哪个类了嘛 -->  
                <aop:pointcut id="agntLogPointcut" expression="execution(* com.sf.pmp.*.*.*.*(..)) and @annotation(agntLog)"/> <!-- 切入点,哪里切入,哪里触发执行 -->
                <aop:around pointcut-ref="agntLogPointcut" method="doAudit"/>  
            </aop:aspect>
            
        </aop:config>
    
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                  <tx:method name="check*" read-only="true"/>
                <tx:method name="is*" read-only="true"/>
                <tx:method name="find*" read-only="true"/>
                <tx:method name="*" isolation="DEFAULT" rollback-for="java.lang.Exception"/>
            </tx:attributes>
        </tx:advice>

    应用:

        @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;

  • 相关阅读:
    Codeforces 1129D Isolation dp + 分块 (看题解)
    Codeforces 1129C Morse Code dp
    bzoj 4119 后缀数组 + 并查集
    Codeforces 204E Little Elephant and Strings 后缀数组 + 并查集
    HDU
    HDU 6125 Free from square dp (看题解)
    Codeforces 913F Strongly Connected Tournament dp(看题解)
    Codeforces 1187F Expected Square Beauty (看题解)
    读《大道至简》第五章有感
    第六周课后作业
  • 原文地址:https://www.cnblogs.com/ericguoxiaofeng/p/10007523.html
Copyright © 2011-2022 走看看