目的
示例目标为:对所有service类中带有add开头的方法进行功能扩展。从而演示前置通知、后置通知、返回通知、异常通知、环绕通知具体在方法的什么时间点执行。
POM引用
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
前面说到了springaop和AspectJ的关系。所以在引入sprng-aspects时,连带着依赖了AspectJ的jar包,如下图:
注解方式实现
1. 引入依赖
<properties>
<spring.version>5.2.22.RELEASE</spring.version>
<lombok.version>1.18.26</lombok.version>
<junit.version>4.13.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
2. 准备要代理的类
public interface UserServcie {
/**
* 添加用户
*
* @param userId 用户id
* @param userName 用户名称
* @return 用户id
*/
int addUser(int userId, String userName);
}
@Service
@AllArgsConstructor
public class UserServiceImpl implements UserServcie {
private final UserMapper userMapper;
/**
* 添加用户
*
* @param userId 用户id
* @param userName 用户姓名
* @return 用户id
*/
public int addUser(int userId, String userName) {
return this.userMapper.insertUser(userId, userName);
}
}
public interface DeptService {
/**
* 添加部门
*
* @param deptId 部门id
* @param deptName 部门名称
* @return 部门id
*/
int addDept(int deptId, String deptName);
}
@Service
@AllArgsConstructor
public class DeptServiceImpl implements DeptService {
private final DeptMapper deptMapper;
/**
* 添加部门
*
* @param deptId 部门id
* @param deptName 部门名称
* @return 部门id
*/
public int addDept(int deptId, String deptName) {
int retDeptId = this.deptMapper.insertDept(deptId, deptName);
retDeptId = retDeptId / 0;
return retDeptId;
}
}
3. 切面方法
@Component
@Aspect
public class AddAspect {
/**
* 定义切点
*/
@Pointcut("execution(* com.mayuanfei.springaop.service..add*(..))")
public void addPointCut(){
}
/**
* 前置通知 切点方法执行前执行的功能
*
* @param joinPoint 切点对象,可以获取方法执行参数
*/
@Before("addPointCut()")
public void methodBefore(JoinPoint joinPoint) {
System.out.println("前置通知执行:" + joinPoint.getTarget().getClass());
}
/**
* 后置通知 方法执行后要增强的功能
*
* @param joinPoint 切点对象
*/
@After("addPointCut()")
public void methodAfter(JoinPoint joinPoint) {
System.out.println("后置通知执行:" + joinPoint.getTarget().getClass());
}
/**
* 返回通知:切点方法正常运行结束后增强的功能
* 如果方法运行过程中出现异常,则该功能不运行
*
* @param joinPoint 切点对象
* @param res res接收方法返回值,需要用returning指定返回值名称
*/
@AfterReturning( value = "addPointCut()",returning = "res")
public void methodAfterReturning(JoinPoint joinPoint,Object res){
System.out.println("返回通知执行:" + joinPoint.getTarget().getClass() + ", 返回结果:"+res);
}
/**
* 异常通知:切点方法出现异常时运行的增强功能
* 如果方法运行没有出现异常,则该功能不运行
*
* @param joinPoint 切点对象
* @param e 接收异常对象 需要通过throwing指定异常名称
*/
@AfterThrowing( value = "addPointCut()",throwing = "e")
public void methodAfterThrowing(JoinPoint joinPoint, Exception e){
System.out.println("异常通知执行:" + joinPoint.getTarget().getClass() + ", 异常信息:"+e.getMessage());
}
/**
* 环绕通知 在切点方法之前和之后都进行功能的增强
* 方法列表可以通过ProceedingJoinPoint获取执行的切点
* 通过proceedingJoinPoint.proceed()方法控制切点方法的执行位置
* 在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值
*
* @param proceedingJoinPoint 执行的切点
* @return 原方法返回的结果
* @throws Throwable 异常
*/
@Around("addPointCut()")
public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知方法前执行:" + proceedingJoinPoint.getTarget().getClass());
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕通知方法后执行:" + proceedingJoinPoint.getTarget().getClass());
return proceed;
}
}
4.测试方法
@Test
public void test1() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserServcie userServcie = context.getBean(UserServcie.class);
userServcie.addUser(111, "laoma111");
DeptService deptService = context.getBean(DeptService.class);
deptService.addDept(222, "dept222");
}
5.代码地址
gitee.com/mayuanfei/S… 下的SpringIoc06
XML方式实现
这里省略具体的类代码,仅仅展示xml配置的内容。因为xml方式的情况用的不太多,仅仅作为了解即可。
1.创建对象
<!-- 创建对象 -->
<bean id="userMapper" class="com.mayuanfei.springaop.dao.UserXmlMapper"/>
<bean id="deptMapper" class="com.mayuanfei.springaop.dao.DeptXmlMapper"/>
<bean id="userService" class="com.mayuanfei.springaop.service.impl.UserServiceXmlImpl">
<constructor-arg name="userMapper" ref="userMapper"/>
</bean>
<bean id="deptServcie" class="com.mayuanfei.springaop.service.impl.DeptServiceXmlImpl">
<constructor-arg name="deptMapper" ref="deptMapper"/>
</bean>
<bean id="addAspectXml" class="com.mayuanfei.springaop.aop.AddAspectXml"/>
2.AOP增强
<!-- aop增强 -->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointCutAdd" expression="execution(* com.mayuanfei.springaop.service..add*(..))"/>
<!-- 配置切面 -->
<aop:aspect ref="addAspectXml">
<!--增强作用在具体的方法上-->
<aop:before method="methodBefore" pointcut-ref="pointCutAdd"/>
<aop:after method="methodAfter" pointcut-ref="pointCutAdd"/>
<aop:around method="methodAround" pointcut-ref="pointCutAdd"/>
<aop:after-returning method="methodAfterReturning" pointcut-ref="pointCutAdd" returning="res"/>
<aop:after-throwing method="methodAfterThrowing" pointcut-ref="pointCutAdd" throwing="e"/>
</aop:aspect>
</aop:config>
3.代码地址
gitee.com/mayuanfei/S… 下的SpringIoc06