基于Spring aop写的一个简单的耗时监控

前言:毕业后应该有一两年没有好好的更新博客了,回头看看自己这一年,似乎少了太多的沉淀了。让自己做一个爱分享的人,好的知识点拿出来和大家一起分享,一起学习。

背景: 在做项目的时候,大家肯定都遇到对一些对方法,模块耗时的监控,为了方便性能的监控,问题的定位等。如果每一个方法里都加上

...
Stopwatch watch = Stopwatch.createStarted();
...
watch.elapsed(TimeUnit.MILLISECONDS)
...

 类似的代码肯定没问题,但是就会显得代码特别的冗余。正好近期看了点spring-aop的相关数据,就想到做一个对方法的切面监控方法耗时,同时利用一个简单的注解,可以达到代码简洁化。

1、定义注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PerfMonitor {

    /**
     * 基本描述,可不设置,默认为空
     * @return
     */
    String desc() default "";
}

2、定义切面

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

import com.google.common.base.Stopwatch;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

public class PerfAspect {
    private Logger logger = Logger.getLogger(PerfAspect.class);
    /**
     * 耗时,spring线程问题,防止不同线程之间出现数据影响
     */
    private ThreadLocal<Stopwatch> watch = new ThreadLocal<>();

    /**
     * 进入方法埋点
     */
    public void before() {
        // 设置进入时间
        watch.set(Stopwatch.createStarted());
    }

    /**
     * 结束方法埋点
     * @param point
     */
    public void after(JoinPoint point) {
        Class c = point.getTarget().getClass();
        Signature signature = point.getSignature();
        StringBuilder sb = new StringBuilder();
        String desc = getAnnotationDesc(point);
        if (desc != null && desc != "") {
            sb.append(desc);
        } else {
            sb.append(c.getSimpleName()).append(".").append(signature.getName());
        }
        sb.append(",cost[").append(watch.get().elapsed(TimeUnit.MILLISECONDS)).append("]ms");
        logger.info(sb.toString())
    }

    /**
     * 获取注解描述信息
     * @param joinPoint
     * @return
     */
    private String getAnnotationDesc(JoinPoint joinPoint) {
        Method method = getJoinPointMethod(joinPoint);
        PerfMonitor perfMonitor = method.getAnnotation(PerfMonitor.class);
        return perfMonitor.desc();
    }

    /**
     * 计算接入点监控方法
     * @param joinPoint
     * @return
     */
    private Method getJoinPointMethod(JoinPoint joinPoint) {
        Class c = joinPoint.getTarget().getClass();
        Signature signature = joinPoint.getSignature();
        if (c != null && c.getMethods() != null) {
            for (Method method : c.getMethods()) {
                if (method.getName() == signature.getName()) {
                    return method;
                }
            }
        }
        return null;
    }

}    

3、在方法上打上该注解

public class Student implements Person {

    /**
     * logger
     */
    private Logger logger = Logger.getLogger(Student.class);

    @PerfMonitor(desc = "student eat perf")
    public void eat(String food) {  
        logger.info("student eat " + food);
    }
}
 

4、spring xml配置

    <bean id="student" class="com.common.util.test.Student"/><!--性能监控点-->
    <bean id="perfAspect" class="com.common.util.perfmonitor.PerfAspect"/>
    <!-- 开启aop -->
    <aop:aspectj-autoproxy/>
    <!-- aop配置 -->
    <aop:config>
        <!-- 连接点 -->
        <aop:pointcut id="pointCut" expression="@annotation(com.common.util.perfmonitor.PerfMonitor)"/>
        <aop:aspect ref="perfAspect">
            <aop:after method="after" pointcut-ref="pointCut"/>
            <aop:before method="before" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>

5、测试入口

public class Client {

  public static void main(String[] args)  {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.aop.xml");
    final Person person = (Person)ctx.getBean("student");
    ExecutorService executorService = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 100; i++) {
            executorService.execute(new Runnable() {
                public void run() {

                    person.eat("fish");
                }
            });

        }
  }
}

ps:说明一下,该工具使用时,第1、2两步需要写入到底层common层代码中。如果是基于osgi的应用,不同的bundle之间spring上下文可能是不通的,那么需要在使用这个注解的bundle中配置步骤4中的spring上下文(切记)。

原文地址:https://www.cnblogs.com/newpanderking/p/9108082.html

时间: 2024-11-02 23:32:31

基于Spring aop写的一个简单的耗时监控的相关文章

虚幻4,BP写了一个简单的三线跑酷工程

BP写了一个简单的三线跑酷 链接: http://pan.baidu.com/s/1jILE4V8 密码: 96ua

java写的一个简单学生管理系统[改进]

用Java写的一个简单学生管理系统 import java.util.*; public class student_cj {  public static void main(String[] args){      Scanner in=new Scanner(System.in);   System.out.print("请输入学生人数:");   int num=in.nextInt();//学生人数   String[] str=new String[num];//结合一行数

写了一个简单的CGI Server

之前看过一些开源程序的源码,也略微知道些Apache的CGI处理程序架构,于是用了一周时间,用C写了一个简单的CGI Server,代码算上头文件,一共1200行左右,难度中等偏上,小伙伴可以仔细看看,对于学生来说,拿来当简历,含金量还是足够的.如果把程序里所涉及的HTTP协议,Linux下POSIX编程等等搞清楚,我想找工作中肯定是有足够的竞争力的,当然我也只是皮毛而已,不再班门弄斧了,下面简单的说下程序流程吧,方便小伙伴们阅读. 程序源代码:戳我 在说程序流程之前,我先简单说下CGI吧,CG

用qt写的一个简单到不能在简单的上位机

学QT时,写的一个简单得不能再简单的串口上位机,用来控制单片机上的2个LED.假设一个是只有开和关的状态.一个可以调节亮度.上位机的界面如下图: 其中,波特率,数据位,停止位下拉值在设计师里面添加.剩下的功能,基本由代码实现.通信使用的协议也是随便写的.很简单和随意.图片是老弟手绘的. 下面贴代码 (*^__^*) #include "mainwindow.h" #include "ui_mainwindow.h" #include <QtSerialPort

写的一个简单定时器(非独立线程)

//Callback.h #ifndef __CALLBACK_H__ #define __CALLBACK_H__ typedef void (*T_CallBack)(void *); typedef struct { T_CallBack cb; void *obj; }ST_CallBack; int __NewTimer(void* obj, int interval, bool isloop, T_CallBack cb); void __DeleteTimer(int handle

写了一个简单可用的IOC

根据<架构探险从零开始写javaweb框架>内容写的一个简单的 IOC 学习记录    只说明了主要的类,从上到下执行的流程,需要分清主次,无法每个类都说明,只是把整个主线流程说清楚,避免陷入细节中.学习过程最大的收获,框架也是人写的,没学过感觉很神秘高端.现在看来大概率是,未知往往觉得是高不可攀.http://naotu.baidu.com/file/6c3da879a4495b6bd369f71dcb726f05?token=ed8c0d49d4ee7bbd 原文地址:https://ww

Spring cloud实战 从零开始一个简单搜索网站(一)

效果地址http://121.40.36.198:9080/web/ 本文从建站开始,就不跟别的顺序一样要怎么开始开始的,懂java就行 我会尽量讲的详细, 首先肯定是工具的选择 ,俗话说工欲善其事,必先利其器,Eclipse 和IDEA 都可以集成Spring 插件,不过最好还是用Spring Tool suite ,它有三个版本,看个人喜好,我比较偏向eclipse 安装完后 第一步 记得把maven 改成阿里云的 软件安装完后New - Spring start Project  然后填写

Spring cloud实战 从零开始一个简单搜索网站(三)

上文已经完成了一个简单的   浏览器 到 Client 到CSDN端的通路 我们的架构是每个博客网址为一个单独的组件, 这里为了方便直接先用CSDN 那个组件复制下 我这里改成 SDN 修改下 application.properties   端口记得改 eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/spring.application.name=sdnserver.port=8983 下面是TOMCAT   

浮动布局写了一个简单的页面

正在学习的路上...... 这两天写了一个比较简单的页面,主要使用了浮动和定位.左边的属于滚动页面,右边的list属于固定.先上图片: 主要使用了float:left/right. 1.下面是HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <link type="