一滔驾、簡(jiǎn)述原生AspectJ優(yōu)勢(shì):
拓展織入方法范圍:
能夠?qū)?private 方法策严、本類內(nèi)部調(diào)用的其他方法進(jìn)行切面(spring-aop 無(wú)法做到)提高性能:
不用繼承、實(shí)現(xiàn)spring的代理類贮匕、攔截器往史,而是直接將代碼寫(xiě)入字節(jié)碼中,提高了運(yùn)行性能贝搁;
準(zhǔn)備:
- spring-instrument-5.0.7.RELEASE.jar
- aspectjweaver-1.8.13.jar
上述2個(gè)包用于和 aspectj 搭配使用吗氏,實(shí)現(xiàn)原生的 aspectj(性能高,功能全) - 將他們放到指定位置(VM 依賴于該位置)
下方【啟動(dòng)原生 AspectJ 的方式】是放入了微服務(wù)的 common 包的resources/tools/下(無(wú) main雷逆,作為 jar 依賴存在)
二弦讽、啟動(dòng)原生 AspectJ 的方式
- 在要使用的微服務(wù)模塊的配置類上:(盡量別在 common 包,否則其他人協(xié)同開(kāi)發(fā)膀哲,可能花很久排錯(cuò))
注釋:@EnableLoadTimeWeaving
說(shuō)明:當(dāng)要調(diào)用 spring 提供的相關(guān) aop 類如 @Async往产、@EnableTransactionManagement 時(shí),應(yīng)該要將 mode 設(shè)置為 AdviceMode.ASPECTJ某宪,才能使用原生 AspectJ仿村;
-
在 IDEA 中,啟動(dòng) JVM 時(shí)兴喂,增加 VM 選項(xiàng):
idea配置示意圖.png
-javaagent:common/src/main/resources/tools/aspectjweaver-1.8.13.jar\
-javaagent:common/src/main/resources/tools/spring-instrument-5.0.7.RELEASE.jar
三蔼囊、開(kāi)發(fā)
- 在項(xiàng)目 resources/META-INF/ 目錄下,新建或修改 aop.xml 文件衣迷,增加自定義切面類畏鼓、織入目標(biāo)的配置:
簡(jiǎn)單但完整的示例:
切面類:
package com.aspect;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
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.beans.factory.annotation.Value;
import java.lang.reflect.Method;
@Aspect
@AllArgsConstructor
@NoArgsConstructor
public class LogExecutiomTimeAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(com.aspect.LogExecutiomTimeAspect.class);
@Value("${logTimeAdvise.log.level:info}")
private String logLevel = "info";
@Pointcut("@annotation(com.annotation.LogExecutionTime)")
public void cut() {
}
@Around("cut()")
public Object doLogExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long beforeInMethod = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
Method method = getMethod(joinPoint);
String promptMsg = "==> 執(zhí)行方法[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "]耗時(shí):" + (System.currentTimeMillis() - beforeInMethod) + " ms";
switch (logLevel) {
case "debug":
LOGGER.debug(promptMsg);
break;
case "info":
LOGGER.info(promptMsg);
break;
case "warn":
LOGGER.warn(promptMsg);
break;
case "error":
LOGGER.error(promptMsg);
break;
default:
LOGGER.info(promptMsg);
break;
}
return proceed;
}
private Method getMethod(ProceedingJoinPoint joinPoint) {
return ((MethodSignature) joinPoint.getSignature()).getMethod();
}
}
注釋:
package com.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
aop 配置:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<!-- 無(wú)配置 -->
<!-- <weaver options="-showWeaveInfo">-->
<!-- 打印完整信息 -->
<weaver options="-showWeaveInfo -XnoInline -Xset:weaveJavaxPackages=true -Xlint:ignore -verbose -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
<!-- only weave classes in our application-specific packages -->
<include within="com..*"/>
</weaver>
<aspects>
<!-- 切面類 -->
<aspect name="com.aspect.LogExecutiomTimeAspect"/>
</aspects>
</aspectj>
說(shuō)明:可以放在 common 包,只要其他微服務(wù)沒(méi)有注釋@EnableLoadTimeWeaving壶谒,就不會(huì)啟用 aspectj 的 loadtime weaving云矫,自然也不會(huì)啟動(dòng)報(bào)錯(cuò)
參考資料:
- spring:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-using-aspectj
- Aspectj:參考spring文檔的相關(guān)鏈接