统计Controller、Service、Repository消耗时间

1、监控

package com.cloud.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

/**   
 * @Title: UserMonitor.java 
 * @ProjectName com.spring.pro.thread.pool
 * @Description:  
 * @author ybwei   
 * @date 2018年12月11日 上午10:44:36    
 */
@Aspect
@Component
public class MonitorAop {

    private static Logger logger = LoggerFactory.getLogger(MonitorAop.class);
    private ThreadLocal<StopWatch> t=new ThreadLocal<StopWatch>();

    @Pointcut("execution(* com.cloud.controller..*.*(..))")
    public void controllerPerformance() {
    }

    @Pointcut("execution(* com.cloud.serviceImpl..*.*(..))")
    public void servicePerformance() {
    }

    @Pointcut("execution(* com.cloud.mapper..*.*(..))")
    public void repositoryPerformance() {
    }

    @Before("controllerPerformance()")
    public void startWatch() {
    	StopWatch stopWatch = new StopWatch("controller");
    	t.set(stopWatch);
    }

    @After("controllerPerformance()")
    public void endWatch() {
        logger.info(t.get().prettyPrint());
        t.remove();;
    }

    @Around("servicePerformance() || repositoryPerformance() ")
    public Object watchPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("---------------------------");
        try {
            //如果是一层一层的,这里只能统计到到下一层需要的时间,因为返回值后没有统计,也就是说只能统计平行的调用
            if (t.get().isRunning()){
                t.get().stop();
            }
            t.get().start(joinPoint.getSignature().toString());
        } catch (IllegalStateException e) {
            logger.error("watch start error:",e);
        }

        Object proceed = joinPoint.proceed();

        try {
            if (t.get().isRunning()){
                t.get().stop();
            }
        } catch (IllegalStateException e) {
            logger.error("watch end error:",e);
        }

        return proceed;

    }

}

2、controller

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cloud.entity.User;
import com.cloud.service.UserService;

/**
 * @ClassName: UserController 
 * @Description:  
 * @author ybw 
 * @date 2017年4月14日 下午3:24:50 
 */
@RestController
@RequestMapping("/user")
public class UserController {

	private Logger logger=LoggerFactory.getLogger(getClass());
	@Resource(name="userService")
	private UserService userService=null;
	
	@GetMapping("/getUser")
	public User getUser(int id){
		User user=userService.getUser(id);
		logger.info("user:{}",user);
		return user;
	}
	
	
	/**
	 * @param id
	 * @return
	 * @author weiyb 
	 */
	@GetMapping("/getUser2")
	public ResponseEntity<User> getUser2(int id){
		User user=userService.getUser2(id);
		logger.info("user:{}",user);
		return new ResponseEntity<User>(user, HttpStatus.OK);
	}
}

3、service

package com.cloud.service;

import com.cloud.entity.User;

/**
 * @ClassName: UserService 
 * @Description:  
 * @author ybw 
 * @date 2017年4月10日 下午1:43:08 
 */
public interface UserService {

	/**
	 * @param id
	 * @return
	 */
	public User getUser(int id);

	public User getUser2(int id);
}
package com.cloud.serviceImpl;

import java.util.Random;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.cloud.entity.User;
import com.cloud.mapper.UserMapper;
import com.cloud.service.UserService;

/**
 * @ClassName: UserServiceImpl
 * @Description:
 * @author weiyb
 * @date 2017年6月19日 下午5:03:11
 */
@Component("userService")
public class UserServiceImpl implements UserService {

	@Autowired
	private UserMapper userMapper;

	@Override
	@Transactional
	public User getUser(int id) {
		User user = new User();
		user.setName("张三");
		user.setAge(12);
		userMapper.insert(user);
		return userMapper.selectByPrimaryKey(id);
	}

	@Override
	public User getUser2(int id) {
		Random r = new Random();
		User user = userMapper.selectByPrimaryKey(id);
		user.setName("张三2" + r.nextInt());
		user.setAge(r.nextInt());
		userMapper.updateByPrimaryKeySelective(user);
		return userMapper.selectByPrimaryKey(id);
	}

}

4、repository

package com.cloud.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.type.JdbcType;

import com.cloud.entity.User;
import com.cloud.entity.UserExample;

public interface UserMapper {
    /**
     *
     * @mbg.generated 2018-12-11
     */
    @SelectProvider(type=UserSqlProvider.class, method="countByExample")
    long countByExample(UserExample example);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @DeleteProvider(type=UserSqlProvider.class, method="deleteByExample")
    int deleteByExample(UserExample example);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @Delete({
        "delete from user",
        "where id = #{id,jdbcType=INTEGER}"
    })
    int deleteByPrimaryKey(Integer id);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @Insert({
        "insert into user (name, age)",
        "values (#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER})"
    })
    @Options(useGeneratedKeys=true,keyProperty="id")
    int insert(User record);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @InsertProvider(type=UserSqlProvider.class, method="insertSelective")
    @Options(useGeneratedKeys=true,keyProperty="id")
    int insertSelective(User record);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @SelectProvider(type=UserSqlProvider.class, method="selectByExample")
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
        @Result(column="age", property="age", jdbcType=JdbcType.INTEGER)
    })
    List<User> selectByExample(UserExample example);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @Select({
        "select",
        "id, name, age",
        "from user",
        "where id = #{id,jdbcType=INTEGER}"
    })
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
        @Result(column="age", property="age", jdbcType=JdbcType.INTEGER)
    })
    User selectByPrimaryKey(Integer id);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @UpdateProvider(type=UserSqlProvider.class, method="updateByExampleSelective")
    int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @UpdateProvider(type=UserSqlProvider.class, method="updateByExample")
    int updateByExample(@Param("record") User record, @Param("example") UserExample example);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @UpdateProvider(type=UserSqlProvider.class, method="updateByPrimaryKeySelective")
    int updateByPrimaryKeySelective(User record);

    /**
     *
     * @mbg.generated 2018-12-11
     */
    @Update({
        "update user",
        "set name = #{name,jdbcType=VARCHAR},",
          "age = #{age,jdbcType=INTEGER}",
        "where id = #{id,jdbcType=INTEGER}"
    })
    int updateByPrimaryKey(User record);
}

UserSqlProvider.java、UserExample、User省略。用mybatis-generator即可生成。

5、测试

package com.spring.pro.thread.api;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.cloud.ProviderApplication;

/**
 * @Title: ThreadApi.java
 * @ProjectName com.spring.pro.thread.pool
 * @Description:
 * @author ybwei
 * @date 2018年12月11日 下午12:16:27
 */
@RunWith(value = SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ProviderApplication.class)
public class ThreadApi {
	@Autowired
	private WebApplicationContext wac;
	private MockMvc mockMvc;

	@Before
	public void setUp() {
		mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
	}

	@Test
	public void testUsersConcurrent() throws Exception {

		ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
				new ArrayBlockingQueue<Runnable>(5));
		// 不能超过15
		for (int i = 0; i < 12; i++) {
			executor.execute(() -> {
				try {
					mockMvc.perform(MockMvcRequestBuilders.get("/user/getUser?id=1"))
							.andExpect(MockMvcResultMatchers.status().isOk());
					mockMvc.perform(MockMvcRequestBuilders.get("/user/getUser2?id=1"))
							.andExpect(MockMvcResultMatchers.status().isOk());
				} catch (Exception e) {
					e.printStackTrace();
				}
			});
		}

		// 等待其他线程执行,方便查看控制台打印结果
		TimeUnit.SECONDS.sleep(1000);
	}
}

6、注意

spring的controller是多线程的。当访问请求是高并发时,计数要保证每个线程都是独立,不会相互干扰,所以使用ThreadLocal。

6.1 ThreadLocal简介

ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。

使用这个工具类可以很简洁地编写出优美的多线程程序。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

6.2 ThreadLocal类接口

  • void set(T value)设置当前线程的线程局部变量的值。
  • public T get()该方法返回当前线程所对应的线程局部变量。
  • public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
  • protected T initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。

猜你喜欢

转载自blog.csdn.net/xixingzhe2/article/details/84953968