Spring统一功能+SpringAOP

什么是拦截器

类似于门口的保安,用来做用户的验证,他是Spring提供的核心功能之一,用来拦截用户的请求

目标方法执行前,要做的事情。(要去实现这个接口)

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
     log.info("登录拦截器校验");

目标方法执行后,要做的事情

@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("目标方法执行后");

    }

描写拦截的内容,拦截的规则

 @Override
    public void addInterceptors(InterceptorRegistry registry) {
//add路径,exclude排除什么我们不去拦截        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login")
                .excludePathPatterns(excludePath);//**表示会给所有方法添加拦截器
    }

源码了解:DispatcherServlet

先初始化,有一个init(),再会去进行一些组件的初始化,然后会回调一个dodispatch,会检查有没有一些文件,

initHandlerMappings(会找到所有的HandlerBean,找到他想要的Bean,他会拿到一个处理器

(类似@RequestMapping拿到这个处理器就会获得一个映射),initHandlerAdapter(根据url,来找到处理器,然后再去找到适配器,适配器来使用处理器,再去执行一个拦截器,然后执行具体的方法,Controller,后续继续执行拦截器代码

slf4j:门面模式

Spring用了什么模式:适配器模式,代理模式,单例模式,门面模式(对其统一进行封装)。


SpringAOP

AOP面向切面编程:

切面使某一类特定问题,,也可以理解为面向特定方法编程

比如登录校验就是一类特定问题,登录校验拦截器,对登录校验这类问题统一处理,AOP是一种思想,对某一类事物的集中处理

比如计时这个操作

long start=System.currentTimeMillis();
  long end=System.currentTimeMillis();
    log.info(""+(end-start)+"ms")

OOP面向对象编程

两个处理的维度不同

假如说对于所有方法的打印耗时时间

只是应用了@Aspectj的注解,但是是spring自己实现的,aspectj是一个第三方的

好处:代码无侵入,不修改原始的业务方法,就可以对原始的业务方法进行功能的增强或者功能的改变,减少了重复代码,提升了开发效率,维护方便

package com.example.demo.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
@Slf4j
@Aspect     //表示一个切面类
@Component
public class TimeAspect {
    //作用域,以及作用方式
    @Around("execution(* com.example.demo.demos.book.controller.*.*(..))")
    //这个方法的对象表示是作用目标
    public  Object timeCost(ProceedingJoinPoint joinPoint) throws Throwable {
        long start=System.currentTimeMillis();
        //让目标方法执行
        Object result=joinPoint.proceed();
        long end=System.currentTimeMillis();
        log.info(joinPoint.getSignature()+"消耗时间"+(end-start)+"ms");
        return  result;
    }
}

切点:其中表达式成为切点@Around("execution(* com.example.de

mo.demos.book.controller.*.*(..))"),用来告诉程序对哪些方法进行功能增强

连接点:目标方法ProceedingJoinPoint joinPoint,切面要去作用的方法。

AOP概念

切点:高二五班学生(那个Controller)

连接点:小张,小李,小王(在图书管理系统中是我们的方法,就是连接点)

通知:具体的逻辑,要去做什么处理

AOP: 对一类事情的几种处理

通知:具体的逻辑,要做什么处理(xxx具体要干什么,下面的一整串代码叫通知)

切面:切点+通知(全部代码叫切面(不包括导包啥的),一个类有多个切面。

测试五大方法

@Around:环绕通知,在目标方法的前后,都被执行

@Before:前置通知,通知方法,在目标方法前执行

@After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行

@AfterReturning:返回后通知,此直接标注的通知方法在目标方法后被执行,有异常不会执行

@AfterThrowing:异常后通知,此注解标注的通知方法发生异常后执行

package com.example.aopdemo.demos.web;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect          //表示这是一个切面类
@Component
public class AspectDemo {
//方法的作用域,以及作用方式
    @Before("execution(* com.example.aopdemo.demos.web.controller..*.*(..))")
    public  void  doBefore(){
        log.info("执行AspectDemo before");
    }

    @After("execution(* com.example.aopdemo.demos.web.controller..*.*(..))")
    public  void doAfter(){
        log.info("执行AspectDemo after");
    }

    @AfterReturning("execution(* com.example.aopdemo.demos.web.controller..*.*(..))")
    public  void doAfterReturning(){
        log.info("执行AspectDemo afterReturning");
    }
    @AfterThrowing("execution(* com.example.aopdemo.demos.web.controller..*.*(..))")
    public  void doAfterThrowing(){
        log.info("执行AspectDemo afterThrowing...");
    }

方法的作用域,以及作用方式
    @Around("execution(* com.example.aopdemo.demos.web.controller..*.*(..))")

    //Around表示的是方法前后,是必须要返回结果的
    public  Object doAround(ProceedingJoinPoint joinPoint  目标方法) throws Throwable {       //方法执行前
        log.info("执行AspectDemo Around前");
//执行目标方法。
        Object result=joinPoint.proceed();
//方法执行后。
        log.info("执行AspectDemo doAround 后");
        return result;
    }



}

运行结果的顺序,先是Around,再是before,后面的是先执行after再是Around

当发生异常的时候,不执行AfterReturning,也不执行Around方法后的逻辑

切点的学习

切点表达式:

1.execution(根据方法的签名来匹配)

2.@annotation(根据注释匹配)

如何把切点提出来定义(代码更加优雅)

@Target({ElementType.METHOD})//表示我们的注解可以应用到哪里
@Target({ElementType.TYPE})//用于描述类,接口或者enum声明
@Target({ElementType.PARAMETER})//描述参数
@Target({ElementType.TYPE_USE})//可以标注任意类型
@Retention(RetentionPolicy.RUNTIME) //注解的生命周期
@Retention(RetentionPolicy.SOURCE)//此注解存在源代码中,如同slf4j,编译成字节码会被丢弃
@Retention(RetentionPolicy.CLASS)//编译时注解,存在于源代码和字节码中,但是运行时候会被丢弃

​​​​​​​

AOP实现方式

1.基于注解@Aspect

2.基于自定义注解

3.基于Spring API(通过xml方式,少见)

4.基于代理来实现(更久远,更笨,不推荐)

​​​​​​​

AOP回顾:一种思想,对一类事物的集中处理

统一功能:就是AOP的一种实现

切点:其中表达式成为切点@Around("execution(* com.example.demo.demos.book.controller.*.*(..))"),用来告诉程序对哪些方法进行功能增强

通知:具体做什么事情

切面=切点+通知

AOP(常考,但是相对用的少,例如:多线程)的实现方式有几种:

代理模式:

AOP常见实现方式:

1.Spring AOP

2.aspectj

Spring使用了aspectj的注解,自己进行了实现

Spring AOP原理:基于动态代理来实现的:

(租客通过房屋中介->找到房东)

切点

代理模式:

静态:(给学生提供服务之前,先分配一个老师,进行答疑,别的同学问,我再给他分配一个老师。

动态:(不提前分配,学生问的问题类型,进行分配老师)

静态代理:在程序运行前,代理对象已经对目标对象进行空步骤对预执行代码

动态代理两种常见实现方式(基于反射)

JDK动态代理只能代理接口,不能代理类。

CGIB动态代理接口和类,都能被代理。

一般问题

SpringAOP如何实现的基于动态代理实现的)->动态代理是怎么实现的Spring动态代理基于JDK,CGlib)->Spring使用的是哪个呢两个都用了)->什么时候用JDK,什么时候使用CGlibSpringboot2.x开始默认使用CGLIB代理,我们可以通过spring.aop.proxy-target-class=false 设置JDK代理)->JDK和CGlib的区别

JDK动态代理只能代理接口,不能代理类。

CGIB动态代理接口和类,都能被代理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗哥不是甜妹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值