Spring

Spring

还不完全,不是从基础开始的,慢慢补充

IoC

Inversion of Control,控制反转

概念

  • Ioc是一种设计思想,将对象的创建和依赖关系的管理从程序代码中转移到容器(也就是Spring容器)中。
  • 简单类比来说,类似于做饭和点外卖的区别。

AOP

Aspect - Oriented Programming,面向切面编程

概念

  • AOP是一种编程范式,允许将横切关注点(如日志记录、事务管理、安全检查等)从业务逻辑中分离出来。在传统的面向对象编程中,这些横切关注点往往会分散在各个业务逻辑方法中,导致代码混乱难以维护。
  • 例如,在一个电商系统中,每次调用订单处理的业务方法都需要记录日志。没有AOP,可能需要再每个订单处理方法中添加日志记录代码。使用AOP后,可以将日志记录代码集中到一个切面(Aspect)中,然后通过配置来决定在哪些业务方法(切点,PointCut)执行前、执行后或者执行过程中(通知,Advice)来执行日志记录的操作。

切面、切点、通知

  • 切面
    一个模块化的横切关注点,包含了切点和通知。可以把切面想象成一个包含了特定功能(如日志记录功能的模块)。例如,一个日志记录切面包含了记录日志的通知和定义了哪些方法需要记录日志的切点。

  • 切点
    用于定义在哪些连接点上应用切面的通知。例如,可以定义一个切点为“所有以create开头的方法”,那么只要方法名符合这个规则,切面的通知就会在这些方法的相应位置执行。

  • 通知

    定义了切面在切点所指定的连接点上要执行的具体操作。主要有以下几种类型:

    • 前置通知:在目标方法执行之前执行。例如,在调用订单创建方法之前,可以在前置通知中进行权限检查。
    • 后置通知:在目标方法执行之后执行,无论方法是否抛出异常。可以用于清理资源等操作。
    • 返回通知:在目标方法正常返回后执行。比如可以在订单查询方法正常返回后记录查询结果。
    • 异常通知:在目标方法抛出异常后执行。例如,在订单处理方法抛出异常后,可以在异常通知中记录异常信息。
    • 环绕通知:环绕目标方法执行,可以在方法执行前后都进行操作,并且可以控制目标方法是否真正执行。比如在事务管理中,环绕通知可以控制事务的开启、提交和回滚。

注解

  1. @Aspect

    定义一个类为切面类,表名这个类包含了横切关注点的逻辑,如日志记录、事务管理等。

  2. @Before
    定义前置通知,即在目标方法执行之前执行切面中的方法。

  3. @After

    定义后置通知,在目标方法执行之后执行,无论目标方法是否抛出异常。

  4. @AterReturning

    定义返回通知,在目标方法正常返回后执行。

  5. @AfterThrowing
    定义异常通知,在目标方法抛出异常后执行。

  6. @Around
    定义环绕通知,环绕目标方法执行,可以在方法执行前后都进行操作,并且可以控制目标方法是否真正执行。

  7. @PointCut

    用于定义可复用的切点表达式。可以将复杂的切点表达式提取出来,在多个通知中重复使用。

    实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Aspect
    public class LoggingAspect {
    @Pointcut("execution(* com.example.service.UserService.*(..))")
    public void userServiceMethods() {}
    @Before("userServiceMethods()")
    public void logBefore() {
    System.out.println("Before method execution in UserService");
    }
    }
    • 首先通过@Pointcut定义了一个名为userServiceMethods的切点,表示UserService类中的所有方法。然后在@Before通知中可以直接引用这个切点,这样如果需要修改切点表达式,只需要在@Pointcut定义处修改,而不需要在每个通知中都修改。

bean自动装配

开启自动装配,只需要在xml配置文件<bean>中定义”autowire”

1
<bean id="customer" class="com.xxx.xxx.Customer" autowire=""/>

autowire属性五种装配方式

  • no-缺省情况下,自动配置是通过”ref”属性手动设定
    手动装配:以value或ref的方式明确指定属性值都是手动装配。
    需要通过’ref’属性来连接bean。

  • byName-根据bean的属性名称进行自动装配

    1
    2
    3
    Cutomer的属性名称是person, Spring会将bean id为person的bean通过setter方法进行自动装配
    <bean id="customer" class="com.xxx.xxx.Customer" autowire="byName"/>
    <bean id="person" class="com.xxx.xxx.Person"/>
  • byType-根据bean的类型名称进行自动装配

    1
    2
    3
    Cutomer的属性person的类型为Person Spring会将Person类型通过setter方法进行自动装配
    <bean id="customer" class="com.xxx.xxx.Customer" autowire="byType"/>
    <bean id="person" class="com.xxx.xxx.Person"/>
  • constructor-类似byType,不过是应用于构造器的参数。如果一个bean于构造器参数的类型相同,则进行自动装配,否则导致异常

    1
    2
    3
    Customer构造函数的参数person类型为Person,Spring会将Person类型通过构造方法进行自动装配
    <bean id="customer" class="com.xxx.xxx.Customer" autowire="constructor"/>
    <bean id="person class="com.xxx.xxx.Person"/>
  • autodetect-如果有默认的构造器,则通过constructor方式进行自动装配,否则使用byType方式进行自动装配

@Autowired自动装配bean,可以在字段、setter方法、构造函数上使用

SpringMVC工作流程

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet调用HandlerAdapter处理器适配器
  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫作后端控制器)
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户

image-20240604170420580

image-20240604171610045

SpringBoot自动配置原理

@import + @Configuration + Spring spi

自动配置类由各个starter提供,使用@Configuration @Bean定义配置类,放到META-INF/spring.factories下

使用Spring spi扫描META-INF/spring.factories下的配置类
使用@Import导入自动配置类
image-20240604172730738

如何理解starter?

使用spring + springmvc使用,如果需要引入mybatis等框架,需要到xml中定义mybatis需要的bean

starter就是定义一个starter的jar包,写一个@Configuration配置类、将这些bean定义在里面,然后在starter包的META-INF/spring.factories中写入该配置类,springboot会按照约定来加载该配置类

开发人员只需要将相应的starter包依赖进引用,进行相应的属性配置(使用默认配置时,不需要配置),就可以直接进行代码开发,使用对应的功能了,比如mybatis-spring-boot-starter,spring-boot-starter-redis

关于Tomcat

springboot已经内置了tomcat.jar,运行main方法时回去启动tomcat,并利用tomcat的spi机制加载springmvc

Bean的生命周期

  1. 实例化Bean

    • 两个容器
      • ApplicationContext 一次性载入所有容器
      • BeanFactory 延迟加载
    • 主要任务:将类实例化为对象
      • 调用对象的构造函数
      • 实例化后的对象会被封装在BeanWrapper中
  2. 设置对象属性(DI依赖注入):给对象属性赋值

  3. 处理Aware接口

    如果对象实现了Aware接口,此时就调用

    • BeanNameAware setBeanName
    • BeanClassLoader setBeanClassLoader
    • BeanFactoryAware setBeanFactory
    • ApplicationContextAware setApplicationContext
  4. BeanPostProcessor 前置处理

    • 实现了AOP,可以用这个接口实现一些前置处理
    • 调用的是 postProcessBeforeInitialization(Object obj, String s)方法
  5. InitializingBean 初始化Bean

  6. init-method

  7. BeanPostProcessor 后置处理

  8. Bean 可以使用了

  9. DisposableBean bean此时进入清理阶段,如果有什么处理,就实现这个接口,调用destory方法

  10. Destory-method