1.AOP术语图片
2.spring切面应用的无五种通知
前置通知@Before :在目标方法调用之前执行。
后置通知@After:在目标方法调用之后调用,此时不会关系方法的返回是什么。
返回通知@AfterReturning:在被调用方法成功之后调用。
异常通知@AfterThrowing:在被调用方法异常之后调用。
环绕通知@Around:在包裹了被通知的方法,可以实现以上的所有通知。
3.其他注解介绍
@Aspect :注明这是一个切面
@Pointcut:声明一个切点
4.切点的限制符
5.在spring中使用还需要在配置xml中添加命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" **xmlns:aop="http://www.springframework.org/schema/aop"**
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
**http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd**
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-lazy-init="true">
**<aop:aspectj-autoproxy proxy-target-class="true" />**
6.使用代码
package com.xyy.aspect;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AopLog extends LogAspect {
private Logger logger = LogManager.getLogger(AopLog.class.getName());
@Pointcut("execution(public * com.xyy.controller.*.*(..))")
public void recordControllerLog() {
}
@Pointcut("execution(public * com.xyy.serviceImpl.*.*(..))")
public void recordServiceImplLog() {
}
@Before("recordControllerLog()")
public void beforeController() throws Throwable {
logger.info("-----Controller---begin-----");
}
@Around("recordControllerLog()")
// @Around("execution(* com.xyy.controller.*.*(..))") //execution(* com.xyy.controller.**.*.*(..))<.** 表示controller下面还有包>
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("-----打印请求日志-----");
return super.logInController(joinPoint);
}
@After("recordControllerLog()")
public void afterController() throws Throwable {
logger.info("-----Controller---end-----");
}
@Before("recordServiceImplLog()")
public void beforeServiceImpl() throws Throwable {
logger.info("-----ServiceImpl---begin-----");
}
@After("recordServiceImplLog()")
public void afterServiceImpl() throws Throwable {
logger.info("-----ServiceImpl---end-----");
}
}
2.0版本
package com.xyy.springboot.configuration;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
* springboot自动开启aop
*/
@Aspect
@Component
public class BaseLogAspect {
private static final Logger log = LoggerFactory.getLogger(BaseLogAspect.class);
/**
* execution:用于匹配方法执行的连接点;
* *:匹配任何数量字符;
..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
java.lang.String 匹配String类型;
java.*.String 匹配java包下的任何“一级子包”下的String类型;
如匹配java.lang.String,但不匹配java.lang.ss.String
java..* 匹配java包及任何子包下的任何类型;
如匹配java.lang.String、java.lang.annotation.Annotation
java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
java.lang.Number+ 匹配java.lang包下的任何Number的自类型;
如匹配java.lang.Integer,也匹配java.math.BigInteger
within:用于匹配指定类型内的方法执行;
this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
@within:用于匹配所有持有指定注解类型内的方法;
@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
@annotation:用于匹配当前执行方法持有指定注解的方法;
bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;
reference pointcut:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持。
*/
// 只能注释在方法上
@Pointcut("@annotation(com.xyy.springboot.configuration.BaseMethodLog)")
// 注释在类上,使方法都应用
// @Pointcut("@within(com.xyy.springboot.configuration.BaseTypeLog)")
public void pointcut(){}
@Before("pointcut()")
public void logStart(JoinPoint joinPoint){
// 方法名称
String methodName = joinPoint.getSignature().getName();
// 方法参数
Object[] args = joinPoint.getArgs();
List<Object> list = Arrays.asList(args);
log.debug(methodName + "方法运行前,参数" + list.toString());
}
//如果是别的类调用这个切点,需要写全类名
//无论目标方法是否出现异常都会执行
@After("com.xyy.springboot.configuration.BaseLogAspect.pointcut()")
public void logEnd(JoinPoint joinPoint){
// 方法名称
String methodName = joinPoint.getSignature().getName();
log.debug(methodName + "方法运行后");
}
@AfterReturning(value = "pointcut()", returning = "result")
public void logReturn(JoinPoint joinPoint, Object result){
// 方法名称
String methodName = joinPoint.getSignature().getName();
if (null != result)
log.debug(methodName + "方法运行结束,结果" + result.toString());
else
log.debug(methodName + "方法运行结束");
}
@AfterThrowing(value = "pointcut()", throwing = "exception")
public void logReturn(JoinPoint joinPoint, Exception exception){
// 方法名称
String methodName = joinPoint.getSignature().getName();
log.debug(methodName + "方法运行异常", exception);
}
}