1.爲什麼要使用自定義註解?
使用Annotation之前(甚至在使用之後),XML被廣泛的應用於描述元數據。
假如你想爲應用設置很多的常量或參數,這種情況下,XML是一個很好的選擇,因爲它不會同特定的代碼相連。如果你想把某個方法聲明爲服務,那麼使用Annotation會更好一些,因爲這種情況下需要註解和方法緊密耦合起來。
Spring爲我們提供了面向切面編程的思想,我們就可以自己使用自定義註解解決一些問題。
2.自定義註解使用場景
打日誌、分析代碼執行時間、權限控制、事務處理、訪問頻率控制、異常處理等等。
Note:就和普通的註解實現的功能一樣
2.1 自定義註解實現日誌記錄
一、寫一個自定義註解
註解中包括配置方法所在模塊名稱,以及功能名稱,當然我們在註解裏可以自定義。
import java.lang.annotation.Documented;
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)
@Documented
public @interface Log {
/** 模塊 */
String title() default "";
/** 功能 */
String action() default "";
}
二、建切面類
切面類裏面定義好切點配置,以及所有的需要實現的通知方法。
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component("logAspect")
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
// 配置織入點
@Pointcut("@annotation(com.test.aspact.Log)")
public void logPointCut() {
}
/**
* 前置通知 用於攔截操作,在方法返回後執行
* @param joinPoint 切點
*/
@AfterReturning(pointcut = "logPointCut()")
public void doBefore(JoinPoint joinPoint) {
handleLog(joinPoint, null);
}
/**
* 攔截異常操作,有異常時執行
*
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfter(JoinPoint joinPoint, Exception e) {
handleLog(joinPoint, e);
}
private void handleLog(JoinPoint joinPoint, Exception e) {
try {
// 獲得註解
Log controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null) {
return;
}
// 獲得方法名稱
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String action = controllerLog.action();
String title = controllerLog.title();
//打印日誌,如有需要還可以存入數據庫
log.info(">>>>>>>>>>>>>模塊名稱:{}",title);
log.info(">>>>>>>>>>>>>操作名稱:{}",action);
log.info(">>>>>>>>>>>>>類名:{}",className);
log.info(">>>>>>>>>>>>>方法名:{}",methodName);
} catch (Exception exp) {
// 記錄本地異常日誌
log.error("==前置通知異常==");
log.error("異常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 是否存在註解,如果存在就獲取
*/
private static Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
}
三、spring.xml配置
在spring的配置文件中,開啓註解的掃描,開啓切面掃描。
<context:component-scan base-package="com.test.**"/>
<mvc:annotation-driven />
<aop:aspectj-autoproxy />
<aop:config proxy-target-class="true"></aop:config>
四、測試Controller
@Controller
public class HelloController {
private static final Logger log = LoggerFactory.getLogger(HelloController.class);
@RequestMapping("/hello")
//對應的自定義註解,當方法上寫這個註解時,就會進入切面類中
@Log(title="哈嘍模塊",action="say哈嘍")
public String sayHello() {
log.info("HelloController sayHello:{}","hello world!");
return "hello";
}
}
測試結果:
輸入網址http://localhost/test-demo/hello,進入hello.jsp
看結果可知,先輸出了方法裏的日誌,在返回之後進入了切面方法,打印一出了自定義註解的信息,以及方法具體信息。
原文出處:https://blog.csdn.net/weixin_42184707/article/details/80348103