埋点:结合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;

posted @ 2018-11-29 18:14  天马行空郭  阅读(1083)  评论(0编辑  收藏  举报