Spring AOP拦截规则的两种定义方式
AOP的根本目的就是解耦,分开业务代码与系统共用代码,例如打印日志。
Spring支持AspectJ的注解式切面编程,主要包含4个部分,分别是
- 使用@Aspect声明切面
- 使用@After、@Before、@Around等定义建言
- 定义拦截规则,即切点,作为建言参数。使用@PointCut抽取为公共切点。
- 连接点JointPoint:符合拦截条件的位置
使用注解切面必须要引入Aspectj的依赖,否则会报创建Bean失败。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
使用注解定义拦截规则
定义一个注解,作为元数据,用于反射。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
使用注解
@Service
public class DemoAnnotationService {
@Action(name = "拦截add操作")
public void add() {
}
}
定义切面
@Component
@Aspect
public class LogAspect {
@Pointcut("@annotation(com.lzp.springboot.p1.aop.Action)")
public void annotationPointCut() {
}
@After("annotationPointCut()")
public void after(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Action annotation = method.getAnnotation(Action.class);
System.out.println("注解名:" + annotation.name());
}
}
使用execution定义拦截规则
使用execution就不需要自定义注解,需要指定扫描的包、类、方法。
@Service
public class DemoMethodService {
public void add() {
}
}
定义切面
@Component
@Aspect
public class LogAspect {
@Before("execution(* com.lzp.springboot.p1.aop.DemoMethodService.*(..))")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则:" + method.getName());
}
}
测试
开启Spring对AspectJ的支持,需要使用@EnableAspectJAutoProxy注解。
@Configuration
@ComponentScan("com.lzp.springboot.p1.aop")
@EnableAspectJAutoProxy
public class AopConfig {
}
测试
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
demoAnnotationService.add();
demoMethodService.add();
context.close();
}
}
一个打印Service执行时间的示例
@Aspect
@Component
public class ServiceLogAspect {
private static final Logger logger =
LoggerFactory.getLogger(ServiceLogAspect.class);
@Around("execution(* com.lzp.service.impl..*.*(..))")
public Object recordServiceTimeLog(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("====== 开始执行{}.{} ======",
joinPoint.getTarget().getClass(),
joinPoint.getSignature().getName());
long begin = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
logger.warn("====== 执行结束,耗时{}毫秒 ======", (end - begin));
return result;
}
}
|