江苏建设标准网站,徐州招聘网,我和你99谁做的网站,服务器做网站FTP必要性大吗测试项目结构: 目前是测试两个日志记录和 代码的性能测试 后面如果有其他的应用场景了在添加.其实一中就包括了二,但是没事,多练一遍
1. 日志记录
比如说对service层中的所有增加,删除,修改方法添加日志, 记录内容包括操作的时间 操作的方法, 方法的参数, 方法所在的类, 方法…测试项目结构: 目前是测试两个日志记录和 代码的性能测试 后面如果有其他的应用场景了在添加.其实一中就包括了二,但是没事,多练一遍
1. 日志记录
比如说对service层中的所有增加,删除,修改方法添加日志, 记录内容包括操作的时间 操作的方法, 方法的参数, 方法所在的类, 方法执行的时间. 等进行日志记录.后面可以把数据存到数据库中,也可以把数据存到日志文件中这里就简单的做一个演示,直接输出到控制台了.
对于AOP有两种方式可以实现, 由于注解较为灵活,所以这里就使用注解的方式来实现.如果不太会使用注解的方式,可以看一下我之前的笔记.
SpringAop中的五种常见的通知的注解及annotation 切入点表达式_yfs1024的博客-CSDN博客
第一步: 定义注解
这里因为是对方法切入,所以创建了一个MethodLog注解
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.METHOD)
public interface MethodLog {
}第二步: 在对应的方法上添加注解 这里是对Service层所以就加到Service上了
类如下: 其中包括增删改查, 因为我们要求的是对增删改进行日志记录,所以就把注解加到增删改的方法上即可
Service
public class EmployeeServiceImpl implements EmployeeService {OverrideMethodLogpublic void insertEmployee(Employee employee) {System.out.println(新增);}OverrideMethodLogpublic void deleteEmployee(Long EmployeeId) {System.out.println(删除);}Overridepublic ListEmployee list() {ArrayListEmployee employees new ArrayList();employees.add(new Employee());return employees;}OverrideMethodLogpublic void updateEmployee(Employee employee) {System.out.println(更新员工信息);}
}第三步: 定义切面 定义切入点, 定义通知
Aspect
Component
Slf4j
public class MyAspect {// 定义切入点 对那些方法进行切入// com.yfs1024.service任意子包下的任意类中任意参数,任意返回值 并且 使用MethodLog注解的方法Pointcut(execution(* com.yfs1024.service..*.*(..)) annotation(com.yfs1024.annocation.MethodLog))public void pointCutForMethodLog() {}// 定义通知 做什么Around(pointCutForMethodLog())public Object methodLog(ProceedingJoinPoint joinPoint) throws Throwable {//操作时间LocalDateTime operateTime LocalDateTime.now();//操作类名String className joinPoint.getTarget().getClass().getName();//操作方法名String methodName joinPoint.getSignature().getName();//操作方法参数Object[] args joinPoint.getArgs();String methodParams Arrays.toString(args);long begin System.currentTimeMillis();// 为了防止时间太短,睡会Thread.sleep(3);//调用原始目标方法运行Object result joinPoint.proceed();long end System.currentTimeMillis();//操作耗时Long costTime end - begin;log.info(方法操作时间{},方法所在类{},方法名{},方法的参数{},方法执行耗时 {},operateTime,className,methodName,methodParams,costTime);
// 注意一定要返回return result;}}第四步: 测试
在测试类中进行测试, 注意因为我们使用了Spring的注解所以一定要在测试类上加上SpringBootTest 默认会加但是还是要注意一下.
测试方法如下:
SpringBootTest
class SpringAopApplicationTests {Autowiredprivate EmployeeService employeeService;Testvoid methodLog() {Employee employee new Employee();employeeService.insertEmployee(employee);employeeService.deleteEmployee(10001L);employeeService.list();employeeService.updateEmployee(employee);}
}控制台结果: 嗯,真香 其实想想如果使用动态代理让我们自己写应该也能写出来这样的效果. 在之前的笔记中也有记录感兴趣的话可以看一下,在笔记的最后的案例中
试着让动态代理变得通俗易懂通过三个案例_yfs1024的博客-CSDN博客
2. 性能测试. 需求: 现在有两个工具包, 分别是AliyunOssUtils 和 AliyunOssUtilsOld ,我们现在要通过AOP来对这两个工具包进行测试 你可能会问,就两个我还用AOP? 没错确实麻烦,但是这里就是举个例子. 后面如果多个的话我们只需要,修改切入点即可.
依然是上面的四步
第一步: 定义注解
// 性能测试日志记录
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.METHOD)
public interface PTLog {
}第二步: 在对应的方法上添加注解 (也可以添加到,类上,但是其实还是执行方法的时候记录,因为有多个吗. 也可以是接口上,这样接口的实现类的所有的方法就都被切入了)
AliyunOssUtils
Component
public class AliyunOssUtils {/*** 公共方法* throws InterruptedException*/PTLogpublic void load(MultipartFile multipartFile) throws InterruptedException {Thread.sleep(10);}
}
AliyunOssUtilsOld
Component
public class AliyunOssUtilsOld {/*** 公共方法* throws InterruptedException*/PTLogpublic void load(MultipartFile multipartFile) throws InterruptedException {Thread.sleep(10);}
}第三步: 定义切面 定义切入点, 定义通知
Aspect
Component
Slf4j
public class MyAspect { // com.yfs1024.utils任意子包下的任意类中任意参数,任意返回值 并且 使用PTLog注解的方法Pointcut(execution(* com.yfs1024.utils..*.*(..)) annotation(com.yfs1024.annocation.PTLog))public void pointCutForPTLog() {}Around(pointCutForPTLog())public Object ptLog(ProceedingJoinPoint joinPoint) throws Throwable {String className joinPoint.getTarget().getClass().getName();long begin System.currentTimeMillis();
// 为了防止时间太短,睡会Thread.sleep(3);//调用原始目标方法运行Object result joinPoint.proceed();long end System.currentTimeMillis();Long costTime end - begin;log.info({}类中方法执行耗时{},className,costTime);return result;}
}第四步: 测试
SpringBootTest
class SpringAopApplicationTests {
// 这里因为测试用, 所以上面的工具类上就加了Component注解, 一般不加哈,其实也可以通过一个配置类配合Bean注入到容器这里懒了,嘿Autowiredprivate AliyunOssUtils aliyunOssUtils;Autowiredprivate AliyunOssUtilsOld aliyunOssUtilsOld;Testvoid myPTLog() throws InterruptedException {aliyunOssUtils.load();aliyunOssUtilsOld.load();}
}
控制台结果: 3.公共字段的填充
首先介绍一下什么是公共字段的填充, 我们在对数据进行更新操作的时候,或者插入操作的时候往往都需要记录一下操作的时间, 基本所有的表都会有这两个字段,即 更新日期, 创建日期, 另外我们的每张表还需要记录创建该条记录的人是谁,以及修改这条记录的是谁,等这些就叫做公共字段. 对于不同的表可能要求不同视情况而定, 可见我们对于公共字段的操作往往是在 对数据库的更新操作和插入操作. 所以我们可以定义一个枚举来表示这两个操作,以供后期的使用.
第0步:
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT
}第一步: 定义注解
Target({ElementType.METHOD})
Retention(RetentionPolicy.RUNTIME)
Documented
public interface AutoFill {OperationType value() default OperationType.INSERT; // 设置枚举的参数,默认为插入操作
}第二步: 在对应的方法上添加注解 这个时候就该想了, 我们把这些注解添在哪里合适? 答案是Mapper层, 因为Mapper层是和数据库交互的最后一个步骤, 我不管你之前怎么处理,知道在插入数据库之前把公共字段填充即可 代码如下:
Mapper
public interface EmployeeMapper {/*** 根据用户名查询员工** param username* return*/Select(select * from employee where username #{username})Employee getByUsername(String username);/*** param employee*/
// Options(useGeneratedKeys true,keyProperty id)AutoFill()void insertEmployee(Employee employee);/*** 根据条件查询用户列表** param employee* return*/PageEmployee select(Employee employee);/*** 更新员工信息*/AutoFill(OperationType.UPDATE)void updateEmployee(Employee employee);
}此时对插入和更新操作添加注解:
第三步: 定义切面 定义切入点, 定义通知 此时AOP的强大就体现的淋漓尽致 Component
Aspect
Slf4j
public class AutoFillAspect {// 设置通知的连接点所在的位置Pointcut(execution(* com.sky.mapper.*.*(..)) annotation(com.sky.annocation.AutoFill))public void insertOrUpdateCommonsMeg() {}// 当前切入位置是mapper层,所以是在方法执行之前,即Service层执行之后,再给公共的属性赋值Before(insertOrUpdateCommonsMeg())public void beforeAutoFillCommonsField(JoinPoint joinPoint) throws Exception {
// 获取连接点的方法对象Object[] args joinPoint.getArgs();
// 判断如果不为空,再执行操作,如果为空直接返回if (args null || args.length 0) {return;}
// 此时就可以获取参数列表中的第一个对象,即为当前需要添加数据的对象Object NowMethodObject args[0];Class? obj NowMethodObject.getClass();
// 判断当前的方法是Insert还是Update那些方法进行切入MethodSignature signature (MethodSignature) joinPoint.getSignature();AutoFill annotation signature.getMethod().getAnnotation(AutoFill.class);
// 获取当前的注解对象,通过value值进行判断if (annotation.value() OperationType.INSERT) {
// 获取创建时间方法这个对象Method setCreateTime obj.getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
// 获取设置创建者id的方法对象Method setCreateUser obj.getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
// 调用传入参数setCreateTime.invoke(NowMethodObject, LocalDateTime.now());setCreateUser.invoke(NowMethodObject, BaseContext.getCurrentId());}
// 其次我要知道对谁切入Method setUpdateTime obj.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
// 获取设置创建者id的方法对象Method setUpdateTUser obj.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
// 调用传入参数setUpdateTime.invoke(NowMethodObject, LocalDateTime.now());setUpdateTUser.invoke(NowMethodObject, BaseContext.getCurrentId());}
}第四步: 测试
此时运行SpringBoot项目,进行更新和插入操作, 此时我们就可以看到数据库中的数据已经自动的填充进去