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);
}
}