AOP和拦截器
AOP和拦截器的总结(之前学过,重新巩固一下)
AOP
1、简介:面向切面编程,一种编程范式,在不惊动原始设计的基础上为其进行功能增强
2、核心概念:
- 连接点 (JoinPoint) :你要执行的原始操作方法
- 切入点 (Pointcut):你要追加功能的原始操作方法
- 通知 (Advice):追加功能的方法,依托的类叫通知类
- 切面 (Aspect):将通知与切入点连接到一块
3、入门案例
-
导入坐标
# 切面的坐标 aop的坐标包含在了spring-boot-starter里的context坐标内 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.19</version> </dependency>
-
开启切面,在启动类上加上
@EnableAspectJAutoProxy
-
定义连接点
@Override public void update() { System.out.println(System.currentTimeMillis()); System.out.println("update ...."); } @Override public void save() { System.out.println("save ..."); }
-
设置切入点 和 切面
@Component // 设置bean让spring管控 @Aspect // 表示这个用切面的注解 public class MyAdvice { // 设置切入点 就是 com.example.mapper.BookMapper包内的返回类型为 void save()方法 @Pointcut("execution(void com.example.mapper.BookMapper.save())") public void pt(){} // 设置切面 表示关系为在方法执行之前实行切面方法 @Before("pt()") public void myAdvice(){ System.out.println(System.currentTimeMillis()); } }
-
测试方法
@Autowired private BookMapper bookMapper; @Test void contextLoads() { bookMapper.save(); }
4、AOP工作流程
Spring容器启动 --> 读取所有切面配置中的切入点(必须是切面中的切点,不然创建切点都不用吗?) --> 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
- 匹配失败,创建对象 --> 获取bean,调用方法并执行,完成操作
- 匹配成功,创建原始对象 (目标对象) 的代理对象 --> 根据代理对象的运行模式运行原始方法和增强内容,完成操作 (也就是说,aop增强是靠代理对象来实现的)
5、AOP切入点表达式 (很长的这一段 @Pointcut("execution(void com.example.mapper.BookMapper.save())")
)
-
切入点表达式标准格式:动作关键字 ( 访问修饰符 返回值 包名.类/接口名.方法名 (参数) 异常名)
-
通配符描述:
-
*
: 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
excution (public * com.freshman.*.UserService.find* (*))
匹配com.freshman包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法 -
..
: 多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
execution (public User com..UserService.findById (..))
匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法
-
+
:专用于匹配子类类型
execution(* *..*Service+.*(..))
匹配任意业务层接口,即业务层中所有类中的方法
-
6、AOP通知类型
注解 | 概述 |
---|---|
@Before | 前置执行 |
@After | 后置执行 |
@Around | 环绕执行 |
@AfterReturing | 返回后执行 |
@AfterThrowing | 异常后执行 |
// 环绕执行的特殊操作
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("around before ...");
// 表示对原始操作的调用
Object returnNum = pjp.proceed();
System.out.println("around after ...");
// 原来方法的返回值
return returnNum;
}
7、AOP获取数据
@Around("pt()")
public Object myAdvice(ProceedingJoinPoint point) throws Throwable {
System.out.println(System.currentTimeMillis());
// 获取签名信息,也就是原始方法的所属类和方法名
Signature signature = point.getSignature();
System.out.println(signature.getDeclaringTypeName());
// 获取参数
Object[] args = point.getArgs();
System.out.println(Arrays.toString(args));
// 获取返回值,这里可以得到参数后修改参数
Object proceed = point.proceed(args);
System.out.println(System.currentTimeMillis());
return proceed;
}
8、Spring事务 (mysql引擎是MyISAM,不支持事务,要改成InnoDB)
-
作用:在数据层或业务层保障一系列的数据库操作同成功、同失败
-
事务的一般流程
-
开启事务:在启动类上 加上
@EnableTransactionManagement
-
在要使用事务的方法上加上
@Transactional
-
设置事务管理器 (事务管理器要根据实现技术进行选择,mybatis框架使用的是JDBC事务)
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager manager = new DataSourceTransactionManager(); manager.setDataSource(dataSource); return manager; }
-
-
事务角色
- 事务管理员:发起事务方,在spring中通常指代业务层开启事务的方法
- 事务协调员:加入事务方,在spring中通常指代数据层方法。
-
事务相关配置
-
属性 作用 示例 readonly 设置事务是否为只读事务 readOnly = true 只读事务 timeout 设置事务超时时间 timeout = -1 永不超时 roolbackFor 设置事务回滚异常(class) roolbackFor = (NullPointException.class) roolbackForClassName 设置事务回滚异常(String) 同上,格式为字符串 notRollbackFor 设置事务不回滚异常(class) notRollbackFor = (NullPointException.class) noRollbackForClassName 设置事务不回滚异常(String) 同上,格式为字符串 propagation 设置事务传播行为 @Transactional(propagation = Propagation.REQUIRES_NEW)新开一个事务,不用加入到事务管理员内
9、异常处理器
-
开启异常处理器
@RestControllerAdvice public class MyExceptionAdvice{
-
设置处理的异常
@ExceptionHandler(Exception.class) public void doException(Exception exception){ // 这里对异常进行处理 }
拦截器
1、定义拦截器
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2、配置拦截器
@Configuration
public class WebMvc implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
// 通常用于加载静态资源
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 访问路径 项目路径
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
// 加载拦截器
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 表示拦截的路径
registry.addInterceptor(myInterceptor).addPathPatterns("/books","/books/*");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通