在创建了一个maven管理的SpringBoot项目的前提下。
1.导入依赖坐标
AspectJ依赖,AspectJ是一个易用的功能强大的AOP框架
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
web应用起步依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
用于Junit单元测试的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2.定义自定义注解
import java.lang.annotation.*;
@Inherited // 可继承,不是必须的
@Target({ElementType.METHOD,ElementType.PARAMETER}) // 可以用于方法和参数上
@Retention(RetentionPolicy.RUNTIME) // 注解存活周期到运行时
public @interface Log {
}
3.常规定义3层代码 ,应有如下:
controller 表现层
service + serviceImpl 业务层
mapper/dao 数据持久层
这里简单写个service + serviceImpl 业务层的代码,表现层和数据持久层就不写了,用测试类来测试。
public interface TService {
public void save();
public void update();
}
import com.example.annotation.Log;
import com.example.com.example.service.TService;
import org.springframework.stereotype.Service;
@Service
public class TServiceImpl implements TService {
@Override
@Log
public void save() {
System.out.println("TService .......... save runing");
}
@Override
public void update() {
System.out.println("TService .......... update runing");
}
}
测试类
import com.example.com.example.service.TService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Autowired
private TService tService;
@Test
void a() {
tService.save();
}
@Test
void b() {
tService.update();
}
}
4.打上自定义注解
要求:注解要打在业务层的实现类方法上(ServiceImpl)或者表现层方法上(controller),打在其他上没用。
5.编写切面类(通知类)
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
@Aspect
@Component
public class AspectJ {
// @annotation用在定义连接点时,对连接点进行限制,只拦截指定的方法
@Pointcut("@annotation(com.example.annotation.Log)")
public void pc() {}
@Around("pc()")
public Object testpro(ProceedingJoinPoint pjp) throws Throwable {
// 注意的是,实际中,日志功能不能影响原有的方法的执行,可以开启另一个线程执行,或使用try/catch
try {
Signature signature = pjp.getSignature();
System.out.println(signature);
// 获取类名
String declaringTypeName = signature.getDeclaringTypeName();
System.out.println(declaringTypeName);
// 获取方法
String name = signature.getName();
System.out.println(name);
// 当前时间
Date now = new Date();
String currentTime = now.toLocaleString();
// 日志文件名
String filePath = "D:\\UserArea\\MyDocument\\a.txt";
// 要写入的信息
String data = declaringTypeName + name + " >>>>>>>>>>>> " + currentTime;
logRecord(filePath,data);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 必须执行的代码
// 原始方法执行,将结果返回
Object proceed = pjp.proceed();
return proceed;
}
}
// 日志持久化到文件,这个功能可以单独拆出来写个工具类
public void logRecord(String file,String data) throws IOException {
// new FileWriter(file,true) 写入为追加模式
BufferedWriter bw = new BufferedWriter(new FileWriter(file,true));
bw.write(data);
bw.newLine();
bw.close();
}
}
6.执行单元测试,测试a方法,成功后将在指定的路径 filePath 下产生a.txt文件,并写入指定的信息。
执行完可以打开路径下,看看生成的日志文件。