客户业务唯一不变的是总在变。
客户和客户之间有80%是一样的,只有20%的不同。应对这20%,如果在源代码里改,会带来一个显著的问题:动过的部分和原始不一了,原始部分无非升级了。
比较好的方式是这80%封装为产品层,可以独立升级。其他20%通过扩展机制实现。这个扩展机制不要动产品层的代码。
完成这个机制的核心就是切片编程中@Around。@Around有很多用法,只掌握一招就足够,那就是execution。
假设产品的功能函数在org.qlm.mdm包下,类名为hrServiceImpl,函数为addPerson。
@Aspect // 声明为切面类
@Component // 交给 Spring 容器管理
public class HRAspect {
@Around("execution(* org.qlm.mdm.hrServiceImpl.addPerson(..))")
public Object aroundUserInfo(ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 目标方法执行前的逻辑
System.out.println("目标方法调用前,获取参数:" + joinPoint.getArgs()[0]);
long startTime = System.currentTimeMillis();
Object result = null;
try {
// 2. 执行目标方法(核心步骤,决定是否调用目标方法)
result = joinPoint.proceed();
// 3. 目标方法执行后的逻辑(无异常时)
long endTime = System.currentTimeMillis();
System.out.println("目标方法执行完成,耗时:" + (endTime - startTime) + "ms,返回结果:" + result);
} catch (Throwable e) {
// 4. 目标方法抛出异常时的逻辑
System.out.println("目标方法执行出错:" + e.getMessage());
throw e; // 可选:抛出异常,让上层感知
}
return result; // 返回目标方法的结果(可修改)
}
}
这样就在不动原始代码,甚至不需要原始代码的情况下扩展了功能(例如只有jar包)。但是有如下先决条件:
1、工程里需要有如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、被增强的 hrServiceImpl必须是 Spring 容器中的 Bean(即添加 @Service/@Component 等注解),不能手动 new 实例。
3、切面类和目标类必须在 Spring 扫描范围内。