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开发者中得到很好的普及。