使用 Spring AOP,实现日志功能
注意:项目基于 SSM 框架。使用 AOP 织入,需要导入相关 maven 依赖包!
<!--spring-aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
项目简单结构:
1、首先编写 BeforeLog 类,表示方法执行前的 Log 输出。
其中,这个类实现了 MethodBeforeAdvice 接口。
package com.xxx.Log;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
// method :要执行的目标对象的方法
// args :参数
// target :目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("[Debug] " + target.getClass().getName() + " => " + method.getName());
}
}
2、编写 AfterLog 类,表示方法执行后的 Log 输出。
其中,这个类实现了 AfterReturningAdvice 接口。
package com.xxx.Log;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class AfterLog implements AfterReturningAdvice {
// method :要执行的目标对象的方法
// args :参数
// target :目标对象
// returnValue :返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("[Debug] " + target.getClass().getName() + " , "
+ method.getName() + " => " + returnValue);
}
}
3、编写一个简单的业务接口 MyService 和 实现类 MyServiceImpl 。
MyService
package com.xxx.service.My;
public interface MyService {
void add();
void delete();
void update();
void query();
}
MyServiceImpl
package com.xxx.service.My;
import org.springframework.stereotype.Service;
public class MyServiceImpl implements MyService {
public void add() {
System.out.println("增加 add");
}
public void delete() {
System.out.println("删除 delete");
}
public void update() {
System.out.println("更新 update");
}
public void query() {
System.out.println("查询 query");
}
}
4、在 spring-service.xml (配置文件)中进行配置,先将 spring aop 配置为,对指定的业务类 MyServiceImpl 进行日志输出。
<!-- 配置 AOP -->
<!--扫描 Log 下的包-->
<context:component-scan base-package="com.xxx.Log"/>
<!-- 使用原生的 Spring API 接口 -->
<aop:config>
<!-- 切入点:execution 表达式, execution(要执行的位置! * * * * *) -->
<!-- 对指定的业务类进行日志输出 -->
<aop:pointcut id="pointcut" expression="execution(* com.xxx.service.My.MyServiceImpl.*(..))"/>
<!-- 执行环绕增强! -->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut" />
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut" />
</aop:config>
5、利用 junit 进行测试。
MyTest
import com.xxx.service.My.MyService;
import com.xxx.service.My.MyServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
(SpringJUnit4ClassRunner.class)
(locations = {"classpath:applicationContext.xml"})
public class MyTest {
MyService myService;
public void add() {
myService.add();
}
public void delete() {
myService.delete();
}
public void update() {
myService.update();
}
public void query() {
myService.query();
}
}
测试结果
对单个业务利用 Spring Aop 进行日志输出,测试成功!
6、现在将范围调整到整个 Service 业务层,那么需要更改 spring-service.xml 配置。
<!-- 配置 AOP :需要导入 AOP 的约束 -->
<!--扫描 Log下的包-->
<context:component-scan base-package="com.xxx.Log"/>
<!-- 使用原生的 Spring API 接口 -->
<aop:config>
<!-- 切入点:execution 表达式, execution(要执行的位置! * * * * *) -->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.xxx.service.My.MyServiceImpl.*(..))"/>-->
<!-- 根据自己业务类的位置来编写,根据层级 -->
<aop:pointcut id="pointcut" expression="execution(* com.xxx.service.*.*.*(..))"/>
<!-- 执行环绕增强! -->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut" />
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut" />
</aop:config>
7、对两个业务类都进行测试。
MyService 测试
测试别的业务,可以测试自己写的业务,我这里测试的是自己的 UserService 。
UserTest
import com.xxx.pojo.User;
import com.xxx.service.User.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
(SpringJUnit4ClassRunner.class)
(locations = {"classpath:applicationContext.xml"})
public class UserTest {
UserService userService;
public void test1() {
List<User> userList = userService.selectAll();
userList.forEach(System.out::println);
}
}
UserService 测试
测试成功!