一、AOP(Aspect Orient Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程(OOP)的一种补充和完善。实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面理解为一个动态过程(在对象运行时动态进行功能扩展或控制对象执行)。
二、应用AOP所需要的相关概念
1.切面(aspect):横切面对象,一般用在扩展功能类说明上,借助@aspect声明。
2.切入点(pointcut):理解为if判断,满足条件即切入进行功能扩展,有如下四个种类:
(1)bean(bean的ID,spring容器管理的ID默认为类名首字母小写)------按对象匹配(粗粒度)
(2)within(包名.类名)------按类匹配(粗粒度)
(3)execution(返回值类型 包名.类名.方法名(参数列表))------按方法匹配(细粒度)
(4)@annotation(注解的类全名)------按注解匹配(细粒度)
其中execution有一种万能用法:execution(* 包名….(…))
3.通知(advice):spring中定义了五种通知类型,分别是:
(1)前置通知(@Before)
(2)后置通知 (@After)
(3)返回通知 (@AfterReturning)
(4)异常通知 (@AfterThrowing)
(5)环绕通知(@around)
4.连接点(joinpoint):一般指被拦截到的方法,当通知为环绕通知时,使用ProceedingJoinPoint
三、入门案例
首先我们在service层写入三个普通方法
package com.cy.pj.sys.service.impl;
import org.springframework.stereotype.Service;
import com.cy.pj.common.annotation.TestAnnotation;
@Service
public class TestService {
@TestAnnotation //此注解为自定义注解,采用@annotation方式进行功能扩展
public void method1() {
System.out.println("method1");
}
public void method2() {
System.out.println("method2");
}
public void method3() {
System.out.println("method3");
}
}
接下来我们进行功能业务扩展,在service层中的方法前后加入执行时间,以日志方式输出方法执行耗时时间。
package com.cy.pj.common.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Aspect
@Component
@Slf4j
public class TestAOP {
//@Pointcut("bean(testService)")
//@Pointcut("within(com.cy.pj.sys.service.impl.TestService)")
//@Pointcut("execution(* com.cy.pj.sys.service.impl..*.*(..))")
@Pointcut("@annotation(com.cy.pj.common.annotation.TestAnnotation)")
public void doPointcut() {}
@Around("doPointcut()")//环绕通知使用ProceedingJoinPoint
public Object testObject(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
log.info("start:"+start);
Object result;
try {
result = pjp.proceed();//执行被切入的原始方法
long end = System.currentTimeMillis();
log.info("end:"+end);
System.out.println("耗时:"+(end-start));
return result;
} catch (Throwable e) {
e.printStackTrace();
throw e;
}
}
}
采用注解的方式我们首先需要自定义注解,代码如下:
package com.cy.pj.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
//...
}
最终我们进行业务切面测试实现
package com.cy.pj.common.aspect;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.cy.pj.sys.service.impl.TestService;
@SpringBootTest
public class TestSpringAop{
@Autowired
private TestService ts;
@Test
public void test() {
ts.method1();
ts.method2();
ts.method3();
}
}
测试运行结果如下,运行结果为采用@annotation注解方式进行AOP业务扩展所得结果,method1方法执行扩展功能,如图所示。