AOP和拦截器

AOP和拦截器的总结(之前学过,重新巩固一下)

AOP

1、简介:面向切面编程,一种编程范式,在不惊动原始设计的基础上为其进行功能增强

2、核心概念:

  1. 连接点 (JoinPoint) :你要执行的原始操作方法
  2. 切入点 (Pointcut):你要追加功能的原始操作方法
  3. 通知 (Advice):追加功能的方法,依托的类叫通知类
  4. 切面 (Aspect):将通知与切入点连接到一块
  5. image-20230112133100876

3、入门案例

  1. 导入坐标

    # 切面的坐标 aop的坐标包含在了spring-boot-starter里的context坐标内 
    <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.19</version>
    </dependency>
    
  2. 开启切面,在启动类上加上 @EnableAspectJAutoProxy

  3. 定义连接点

     @Override
      public void update() {
            System.out.println(System.currentTimeMillis());
            System.out.println("update ....");
        }
    
        @Override
        public void save() {
            System.out.println("save ...");
        }
    
  4. 设置切入点 和 切面

    @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());
        }
    }
    
  5. 测试方法

    @Autowired
        private BookMapper bookMapper;
    
        @Test
        void contextLoads() {
            bookMapper.save();
        }
    

    image-20230112140242891

4、AOP工作流程

Spring容器启动 --> 读取所有切面配置中的切入点(必须是切面中的切点,不然创建切点都不用吗?) --> 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

  • 匹配失败,创建对象 --> 获取bean,调用方法并执行,完成操作
  • 匹配成功,创建原始对象 (目标对象) 的代理对象 --> 根据代理对象的运行模式运行原始方法和增强内容,完成操作 (也就是说,aop增强是靠代理对象来实现的)
    image-20230112142456074

5、AOP切入点表达式 (很长的这一段 @Pointcut("execution(void com.example.mapper.BookMapper.save())") )

  1. 切入点表达式标准格式:动作关键字 ( 访问修饰符 返回值 包名.类/接口名.方法名 (参数) 异常名)

  2. 通配符描述:

    • * : 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
      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)

  1. 作用:在数据层或业务层保障一系列的数据库操作同成功、同失败

  2. 事务的一般流程

    1. 开启事务:在启动类上 加上 @EnableTransactionManagement

    2. 在要使用事务的方法上加上 @Transactional

    3. 设置事务管理器 (事务管理器要根据实现技术进行选择,mybatis框架使用的是JDBC事务)

      @Bean
          public PlatformTransactionManager transactionManager(DataSource dataSource){
              DataSourceTransactionManager manager = new DataSourceTransactionManager();
              manager.setDataSource(dataSource);
              return manager;
          }
      
  3. 事务角色

    • 事务管理员:发起事务方,在spring中通常指代业务层开启事务的方法
    • 事务协调员:加入事务方,在spring中通常指代数据层方法。
  4. 事务相关配置

  5. 属性 作用 示例
    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、异常处理器

  1. 开启异常处理器

    @RestControllerAdvice
    public class MyExceptionAdvice{
    
  2. 设置处理的异常

    @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/*");
    }
}
posted @   Freshman0611  阅读(508)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示