当一个 service 执行的时间超过 3s,打印 error 级别的日志,当执行时间为 2s 至 3s,打印 warn 级别的日志,2s 以下打印 info 级别日志
在 foodie-dev 的 pom 文件添加 Spring AOP 的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
AOP 通知
- 前置通知:在方法调用之前执行
- 后置通知:在方法正常调用之后执行
- 环绕通知:在方法调用之前和之后,都分别可以执行的通知
- 异常通知:如果在方法调用过程中发生异常,则通知
- 最终通知:在方法调用之后执行
后置通知和最终通知区别:方法调用异常,后置通知不执行,最终通知执行,最终通知类似于 try-catch 中的 finally
在 foodie-dev-api 模块新建 com.imooc.aspect 包并创建 ServiceLogAspect 类
package com.imooc.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* Created by 92578 on 2020/8/22 11:19
**/
@Aspect
@Component
public class ServiceLogAspect {
public static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
/**
* 切面表达式:
* execution 代表所要执行的表达式主体
* 第一处 * 代表方法返回类型,* 代表所有类型
* 第二处 包名代表 aop 监控的类所在的包
* 第三处 .. 代表该包以及其子包下的所有类方法
* 第四处 * 代表类名,* 代表所有类
* 第五处 *(..) * 代表类中的方法名,(..) 表示方法中的任何参数
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* com.imooc.service.impl..*.*(..))")
public Object recordTimeLog(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("====== 开始执行 {}.{} ======",
joinPoint.getTarget().getClass(),
joinPoint.getSignature().getName());
// 记录开始时间
long begin = System.currentTimeMillis();
// 执行目标 service
Object result = joinPoint.proceed();
// 记录结束时间
long end = System.currentTimeMillis();
long takeTime = end - begin;
if (takeTime > 3000) {
logger.error("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
} else if (takeTime > 2000) {
logger.warn("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
} else {
logger.info("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
}
return result;
}
}
启动项目,打开浏览器,访问 http://localhost:8080/foodie-shop/register.html
输入用户名“i”,查看控制台,发现已经打印相关日志
在 foodie-dev-service 模块中的 UserServiceImpl 类添加线程睡眠代码,模拟超过 3s 后的场景
package com.imooc.service.impl;
import com.imooc.enums.Sex;
import com.imooc.mapper.UsersMapper;
import com.imooc.pojo.Users;
import com.imooc.pojo.bo.UserBO;
import com.imooc.service.UserService;
import com.imooc.utils.DateUtil;
import com.imooc.utils.MD5Utils;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import java.util.Date;
/**
* @author 92578
* @since 1.0
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UsersMapper usersMapper;
@Autowired
private Sid sid;
private static final String USER_FACE = "http://dp.gtimg.cn/discuzpic/0/discuz_x5_gamebbs_qq_com_forum_201306_19_1256219xc797y90heepdbh.jpg/0";
/**
* 判断用户名是否存在
*
* @param username 用户名
* @return 是否存在
*/
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public boolean queryUsernameIsExist(String username) {
Example userExample = new Example(Users.class);
Example.Criteria userCriteria = userExample.createCriteria();
userCriteria.andEqualTo("username", username);
Users result = usersMapper.selectOneByExample(userExample);
return result == null ? false : true;
}
/**
* 创建用户
*
* @param userBO
* @return
*/
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Users createUser(UserBO userBO) {
try {
Thread.sleep(3500);
} catch (InterruptedException e) {
e.printStackTrace();
}
String userId = sid.nextShort();
Users user = new Users();
user.setId(userId);
user.setUsername(userBO.getUsername());
try {
user.setPassword(MD5Utils.getMD5Str(userBO.getPassword()));
} catch (Exception e) {
e.printStackTrace();
}
// 默认用户昵称同用户名
user.setNickname(userBO.getUsername());
// 默认头像
user.setFace(USER_FACE);
// 默认生日
user.setBirthday(DateUtil.stringToDate("1900-01-01"));
// 默认性别为 保密
user.setSex(Sex.secret.type);
user.setCreatedTime(new Date());
user.setUpdatedTime(new Date());
usersMapper.insert(user);
return user;
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public Users queryUserForLogin(String username, String password) {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Example userExample = new Example(Users.class);
Example.Criteria userCriteria = userExample.createCriteria();
userCriteria.andEqualTo("username", username);
userCriteria.andEqualTo("password", password);
Users result = usersMapper.selectOneByExample(userExample);
return result;
}
}
重启项目,打开浏览器,访问 http://localhost:8080/foodie-shop/register.html
注册用户名“imooc123”,密码“123123”,点击“注册”,此时查看控制台,发现打印 error 级别日志
清空浏览器 cookie,访问 http://localhost:8080/foodie-shop/login.html 进行登录
输入用户名“imooc”,密码“123123”,点击“登录”,此时查看控制台,发现打印 warn 级别日志