一、什么是LoadTimeWeaving
LoadTimeWeaving(LTW)是AOP的一种实现方式,它实现了将AOP代码编织到字节码级别,对已经加载过的字节码文件进行增强的目标。SpringFramework3.0之后引入了对LTW的支持,它的实现基于ASM字节码框架。
二、如何在SpringBoot中配置使用LTW技术实现AOP功能
-
引入相关依赖,例如可以使用下面的依赖:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
这里使用的是aspectjweaver依赖,该依赖中包含了aspectj-weaver.jar文件,就是用来支持LTW的核心库。 -
开启Spring Boot的LTW功能,在启动类中加入@EnableLoadTimeWeaving注解即可。完整示例:
```
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableLoadTimeWeaving;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableLoadTimeWeaving // 启用LTW功能
@EnableSpringConfigured // 启用SpringConfigured功能
@EnableAsync
@EnableTransactionManagement
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
- 编写切面类,在该类中定义切点和增强的方法,具体可以采用AspectJ语法进行编写。例如下面是一个示例代码:
```
package com.example.demo.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
@Before("execution(* com.example.demo.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
LOGGER.info("Start method:" + joinPoint.getSignature().getName());
}
@After("execution(* com.example.demo.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
LOGGER.info("End method:" + joinPoint.getSignature().getName());
}
}
```
这里定义了一个LogAspect类,它采用@Aspect注解标记,表示该类是切面类,同时还需要使用@Component注解将其注入到Spring容器中。在该类中定义了两个方法,一个在方法执行前打印日志,一个在方法执行后打印日志,它们的切点是所有com.example.demo.service包下的方法。
- 配置LTW的相关参数,例如下面是一个完整的配置示例:
-javaagent:D:\aspectjweaver-1.9.6.jar // 指定aspectjweaver.jar的路径
-Daj.weaving.verbose=false // 是否输出调试信息,默认false不输出
-Daj.showWeaveInfo=false // 是否开启编织信息,默认false不开启
-Daj.preProcess=true // 是否启用预处理,默认true启用
-Daj.cache=false // 是否开启缓存,默认false不开启
通过在启动时添加JVM参数,可以对LTW的行为进行调整。
三、实际使用LTW技术的两个示例
- 使用LTW技术对Spring Data JPA中的Repository实现方法进行切面编织。
在Spring Data JPA中,所有自定义Repository方法的实现都是由SpringDataJpaInvokerFactory$JpaQueryLookupStrategy.getExecutor去创建执行。这里可以利用它的切点是调用自定义了Repository方法,然后对它进行AOP拦截的操作。因此我们可以写一个切面类对它进行增强。
package com.example.demo.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class RepositoryAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryAspect.class);
// 以所有自定义的Repository接口为切点
@Pointcut("execution(* com.example.demo.repository.*.*(..))")
public void repositoryMethods() {}
// 方法返回后打印日志
@AfterReturning(pointcut = "repositoryMethods()")
public void afterRepositoryMethod(JoinPoint joinPoint) {
LOGGER.info(joinPoint.getSignature().toShortString() + " executed successfully.");
}
}
- 使用LTW技术对Spring Web中的请求处理方法进行切面编织。
在Spring Web中,所有的请求处理方法都可以使用 @RequestMapping、 @GetMapping、@PostMapping和 @PutMapping等注解来定义。这里可以利用这些注解来作为切点,并且对请求处理方法进行AOP拦截的操作。因此我们可以写一个切面类对它进行增强。
package com.example.demo.aspect;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
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;
@Aspect
@Component
public class WebRequestAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(WebRequestAspect.class);
// 以所有请求处理方法为切点
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) ||" +
"@annotation(org.springframework.web.bind.annotation.GetMapping) ||" +
"@annotation(org.springframework.web.bind.annotation.PostMapping) ||" +
"@annotation(org.springframework.web.bind.annotation.PutMapping)")
public void webRequestMethods() {}
// 方法执行前打印日志
@Before("webRequestMethods()")
public void logBefore(JoinPoint joinPoint) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
LOGGER.info("Request URL:" + request.getRequestURL().toString());
LOGGER.info("Request Method:" + request.getMethod());
LOGGER.info("Request IP:" + request.getRemoteAddr());
LOGGER.info("Request Class Method:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
LOGGER.info("Request Args:" + Arrays.toString(joinPoint.getArgs()));
}
// 方法返回后打印日志
@AfterReturning(returning = "response", pointcut = "webRequestMethods()")
public void logAfter(Object response) {
LOGGER.info("Response:" + response.toString());
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能 - Python技术站