最近在研究Springboot切面編程,碰到一個莫名其妙的問題,aop怎么都不起作用。自定義的注解使用到了aop,卻是有效的。
網(wǎng)上查找了幾個小時, 各種方式都試了(使用的是InteliJ IDEA編輯器)。
首先確認了pom.xml文件里是載入了aop的

其次,確認了切面類是沒有問題的,
package com.jeealfa.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class AopLog {
? ? private Logger log = LoggerFactory.getLogger(this.getClass());
? ? //線程局部變量,用于解決多線程中相同變量的訪問沖突問題
? ? ThreadLocal<Long> startTime = new ThreadLocal<>();
? ? @Pointcut("execution(* com.jeealfa.controller..*.*(..))")
? ? public void aopWebLog() {
? ? }
? ? @Before("aopWebLog()")
? ? public void doBefore(JoinPoint joinPoint) throws Throwable {
? ? ? ? startTime.set(System.currentTimeMillis());
? ? ? ? //接手到請求,記錄請求內(nèi)容
? ? ? ? ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
? ? ? ? HttpServletRequest request = attributes.getRequest();
? ? ? ? log.info("URL:" + request.getRequestURI().toString());
? ? ? ? log.info("HTTP Method:" + request.getMethod());
? ? ? ? log.info("IP:" + request.getRemoteAddr());
? ? ? ? log.info("類的方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
? ? ? ? log.info("參數(shù):" + request.getQueryString());
? ? ? ? System.out.println(request.getRequestURI().toString());
? ? }
}
再次,根據(jù)網(wǎng)上查的資料在啟動類加了注解,且aspect文件夾與JeealfaBootApplication處于平級
package com.jeealfa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass=true)
@ComponentScan({"com.jeealfa.*"})
public class JeealfaBootApplication {
public static void main(String[] args) {
SpringApplication.run(JeealfaBootApplication.class, args);
}
}
實際@SpringBootApplication包含了@CompentScan
另外,HelloController類hello方法如下
package com.jeealfa.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@RestController
@Slf4j
public class HelloController {
? ? @GetMapping("/hello")
? ? public String hello(){ return "hello world"; }
}
網(wǎng)上各種方法都試了, aop就是始終不起作用。 運行 /hello時,AopLog里的doBefore方法始終沒有運行。并且發(fā)現(xiàn)一個奇怪現(xiàn)象,其他文件修改,springboot的熱啟動都會自動更新啟動,修改這個切面類時,卻無反應。
不過最終經(jīng)過多次折騰終于發(fā)現(xiàn)了問題所在。
在創(chuàng)建這個切面類時,直接選擇了 Aspect, 見下圖

創(chuàng)建了之后, 然后在把aspect修改為class,

修改為class后,左邊最前面的A標會自動變成C標,這樣就跟從Java Class創(chuàng)建的切面類看起來一模一樣,但就是不起作用。
正確的做法: 通過Java Class創(chuàng)建aspect類,然后加上 @Aspect和@Component注解。 我試了從Java Class創(chuàng)建aspect類,把之前無效的代碼完整拷貝到這個新建的文件里,就生效了。至于上面那種創(chuàng)建aspect類為何會導致無效的內(nèi)在原因,還不清楚,有知情的朋友請留言回復。 雖然兩種創(chuàng)建方式不同,但最終代碼呈現(xiàn)完全是一樣的,就是一個有用一個無用。