AOP
面向切面编程,日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,在不改变原有代码的情况下 , 去增加新的功能
名词
- 切面(Aspect):横切关注点 被模块化 的特殊对象。是一个类,提供API
- 通知(Advice):它是类中的方法
- 目标(Target):被一个或多个方面通知对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 连接点(JointPoint):被拦截到的方法
- 切入点(PointCut):代理对象执行方法时,通知执行的地点
- 织入(weaving) 把切面应用到目标对象 ,创建新的代理对象 的过程
依赖
<!-- AOP-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
execution()
是最常用的切点函数
("execution(* com.aop..*.*(..))")
1、execution(): 表达式主体
2、第一个*号:表示返回类型,*号表示所有的类型
3、.包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包
4、第二个*号:表示类名,号表示所有的类
5、.*(..):最后这个星号表示方法名,号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
@within
@Component
@Aspect
public class HttpAccessAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Around("@within(org.springframework.stereotype.Controller)" +
"|| @within(org.springframework.web.bind.annotation.RestController)")
public Object around(ProceedingJoinPoint point) throws Throwable {
// <1.1> 获取类名
String className = point.getTarget().getClass().getName();
// <1.2> 获取方法
String methodName = point.getSignature().getName();
// <1.3> 记录开始时间
long beginTime = System.currentTimeMillis();
// 记录返回结果
Object result = null;
Exception ex = null;
try {
// <2.1> 执行方法
result = point.proceed();
return result;
} catch (Exception e) {
// <2.2> 记录异常
ex = e;
throw e;
} finally {
// <3.1> 计算消耗时间
long costTime = System.currentTimeMillis() - beginTime;
// <3.2> 发生异常,则打印 ERROR 日志
if (ex != null) {
this.logger.error("[className: {}][methodName: {}][cost: {} ms][errorMessage: {}]",
className, methodName, point.getArgs(), ex.getMessage(), ex);
// <3.3> 正常执行,则打印 INFO 日志
} else {
this.logger.info("[className: {}][methodName: {}][cost: {} ms][args: {}][return: {}]",
className, methodName, costTime, point.getArgs(), result);
}
}
}
}
@within(org.springframework.stereotype.Controller // 所有Controller
@within(org.springframework.web.bind.annotation.RestController// 所有RestController
@within(org.springframework.stereotype.Service) // 所有@Service
@within(@org.springframework.stereotype.Service com.abc.*) // com.abc下所有@Service
@Pointcut
@Aspect
public class Logging {
@Pointcut("execution(* com.tutorialspoint.*.*(..))")
private void selectAll(){}
@Before("selectAll()")
public void beforeAdvice(){
System.out.println("Going to setup student profile.");
}
@After("selectAll()")
public void afterAdvice(){
System.out.println("Student profile has been setup.");
}
@AfterReturning(pointcut = "selectAll()", returning="retVal")
public void afterReturningAdvice(Object retVal){
System.out.println("Returning:" + retVal.toString() );
}
@AfterThrowing(pointcut = "selectAll()", throwing = "ex")
public void AfterThrowingAdvice(IllegalArgumentException ex){
System.out.println("There has been an exception: " + ex.toString());
}
}
@annotation
@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(ElementType.METHOD)//作用于方法
public @interface MyAnnotation {
String methodName () default "";
}
@Aspect@Componentpublic class AspectTest { // 切面类中定义增强,pointcut连接点使用@annotation(xxx)进行定义
@Around(value = "@annotation(around)") //around 与 下面参数名around对应
public void processAuthority(ProceedingJoinPoint point, MyAnnotation around) throws Throwable{
System.out.println("ANNOTATION welcome"); System.out.println("ANNOTATION 调用方法:"+ around.methodName()); System.out.println("ANNOTATION 调用类:" + point.getSignature().getDeclaringTypeName()); System.out.println("ANNOTATION 调用类名" + point.getSignature().getDeclaringType().getSimpleName()); point.proceed(); //调用目标方法
System.out.println("ANNOTATION login success"); }}
@Controller
@RequestMapping("/hello")
public class AspectController {
@RequestMapping("/login/{name}")
@MyAnnotation(methodName = "login")
@ResponseBody
public String login(@PathVariable String name){
System.out.println("hello!"+name);
return "aspect ok";
}
}
ANNOTATION welcome
ANNOTATION 调用方法:login
ANNOTATION 调用类:com.example.demo.controller.AspectController
ANNOTATION 调用类名AspectController
hello!aaa
ANNOTATION login success
@Around的argNames
版权声明:本文为huang6chen6原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。