Spring AOP 的实现
环境搭建
坐标依赖引入 pom.xml
<!--引入spring环境-->
<!-- 添加Spring框架的核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!--Spring AOP-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
添加spring.xml的配置
添加命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 设置⾃动化扫描的范围 -->
<context:component-scan base-package="com.xxxx"/>
<!--开启AOP代理-->
<aop:aspectj-autoproxy/>
</beans>
注解实现
UserService.java
package com.xxxx.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void test(){
System.out.println("UserService...");
//int i= 1/0;
}
}
定义切面
package com.xxxx.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 定义切面(通过注解的方式)
* 设置注解:@Aspect
*
* 由切入点与通知的结合
*
* 定义切入点 Pointcut
* 规定需要拦截哪些方法,哪些方法需要被处理
* @PointCut("匹配规则")
*
* 定义通知
* 前置通知 @Before
* 返回通知 @AfterReturning
* 异常通知 @AfterThrowing
* 最终通知 @After
* 环绕通知 @Around
*
*/
@Component//将对象交给IOC容器维护
@Aspect//表示当前是一个切面类
public class LogCut {
/**
* 切⼊点:
* 匹配规则。规定什么⽅法被拦截、需要处理什么⽅法
* 定义切⼊点
* @Pointcut("匹配规则")
*
* Aop 切⼊点表达式简介
* 1. 执⾏任意公共⽅法:
* execution(public *(..))
* 2. 执⾏任意的set⽅法
* execution(* set*(..))
* 3. 执⾏com.xxxx.service包下任意类的任意⽅法
* execution(* com.xxxx.service.*.*(..))
* 4. 执⾏com.xxxx.service 包 以及⼦包下任意类的任意⽅法
* execution(* com.xxxx.service..*.*(..))
*
* 注:表达式中的第⼀个* 代表的是⽅法的修饰范围
* 可选值:private、protected、public (* 表示所有范围)
*/
@Pointcut("execution (* com.xxxx.service..*.*(..) )")
public void cut(){}
/**
* 定义前置通知
* 在方法执行前执行的通知
*/
@Before(value = "cut()")
public void before(){
System.out.println("前置通知...在方法执行前执行的通知");
}
/**
* 定义返回通知
* 方法正常执行完后执行的通知
*/
@AfterReturning(value = "cut()")
public void afterReturning(){
System.out.println("返回通知...方法正常执行完后的通知");
}
/**
* 定义最终通知
* 方法执行结束后执行的通知(无论方法是否能够正常执行)
*/
@After(value = "cut()")
public void after(){
System.out.println("最终通知...方法执行结束执行的通知");
}
/**
* 定义异常通知
* 方法抛出异常时执行的通知
*/
@AfterThrowing(value = "cut()",throwing = "e")
public void afterThrowing(Exception e){
System.out.println("异常通知...方法抛出异常时执行的通知"+ " 异常原因:" + e.getMessage());
}
/**
* 声明环绕通知 并将通知应⽤到切⼊点上
* ⽅法执⾏前后 通过环绕通知定义相应处理
* 需要通过显式调⽤对应的⽅法,否则⽆法访问指定⽅法 (pjp.proceed();)
* @param pjp
* @return
*/
@Around(value = "cut()")
public Object around(ProceedingJoinPoint pjp) {
System.out.println("环绕通知---前置通知...");
Object object = null;
try {
//需要通过显式调⽤对应的⽅法,否则⽆法访问指定⽅法
object = pjp.proceed();
System.out.println(pjp.getTarget() + "======" + pjp.getSignature());
System.out.println("环绕通知---返回通知...");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("环绕通知---异常通知...");
}
System.out.println("环绕通知---最终通知...");
return object;
}
}
starter.java
package com.xxxx;
import com.xxxx.dao.UserDao;
import com.xxxx.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
//得到上下文环境
BeanFactory factory = new ClassPathXmlApplicationContext("spring.xml");
//得到bean对象
UserService userService = (UserService) factory.getBean("userService");
userService.test();
}
}