spring

spring

两大核心: 控制反转IoC 和AOP

  1. 控制反转/依赖注入:对象不用自己找依赖,Spring容器自动"送货上门",实现松耦合。
  2. 面向切面编程:像切洋葱一样把通用功能(日志、事务)横向抽取,让核心业务更纯净。
  3. 数据访问支持:用统一的方式操作各种数据库,告别繁琐的JDBC代码和不同数据库的兼容问题。
  4. 声明式事务管理 :只需一个@Transactional注解,复杂的事务管理就像"开关"一样简单可控。
  5. 高度模块化设计:像乐高积木,需要什么拿什么,不必引入整个框架。
  6. 强大测试支持:专为测试而生,轻松模拟完整Spring环境进行单元和集成测试。

spring的八大模式

  1. 简单工厂模式:获取 bean 的时候可以通过简单工厂模式(静态工厂模式)来获取

  2. 工厂方法模式:FactoryBean是典型的工厂方法模式。在配置文件中通过factory-method属性来指定工厂方法,该方法是一个实例方法

  3. 单例模式:Spring用的是双重判断加锁的单例模式。

  4. 代理模式:aop就是使用了动态代理实现的

  5. 装饰器模式:javase中io流是非常典型的装饰器模式,Spring 使用装饰器来增强 Bean 的功能,如属性访问、类型转换等

  6. 观察者模式:spring容器生命周期管理,Spring 容器自己就是个"大主播",在启动、刷新、关闭这些关键节点时,会发布事件通知所有"粉丝"(内置监听器),让它们执行相应的处理逻辑

  7. 策略模式:事务策略,Spring 根据资源路径的前缀(classpath:file:http:)自动选择不同的加载策略

  8. 模板方法模式:Spring中的JdbcTemplate类就是一个模板类。它就是一个模板方法设计模式的体现。在模板类的模板方法execute中编写核心算法,具体的实现步骤在子类中完成

控制反转的理论

java 复制代码
//将对象的创建权交出去,将对象和对象之间关系的管理权交出去,由第三方容器来负责创建与维护

控制反转的常用方法(依赖注入3种)

java 复制代码
控制反转常见的实现方式:依赖注入(Dependency Injection,简称DI)

1.set方法注入(// 使用set方式注入,必须提供set方法,来给属性赋值)

2.构造方法注入

3.字段注入(底层通过反射机制 ,通过反射获取字段,创建对象)

OOD五大原则

  1. SRP :单一职责原则 一个类只干一件事
  2. OCP:开闭原则 不修改代码,只新增代码
  3. LSP :里氏替换 子类要能当父类使用,即使换了也不出错
  4. ISP : 接口隔离原则 接口要专一,不要强迫去实现用不到的方法
  5. DIP:依赖倒置原则 依赖抽象而不是具体,就是所谓的面向接口编程

spring的七大模块

bean的使用以及在配置文件里面的配置

  • id属性:代表对象的唯一标识。可以看做一个人的身份证号。
  • class属性:用来指定要创建的java对象的类名,这个类名必须是全限定类名(带包名)。
xml 复制代码
 <bean id="userBean" class="com.jkweilai.spring.bean.User"></bean>

创建对象时确实调用了无参数构造方法(底层创建的原理:通过反射,调用无参构造,如果不给无参构造,就会报错)

java 复制代码
// dom4j解析beans.xml文件,从中获取class的全限定类名
// 通过反射机制调用无参数构造方法创建对象
Class clazz = Class.forName("com.jkweilai.spring.bean.User");
Object obj = clazz.newInstance();

bean创建好之后 存在大map中了

xml 复制代码
 <bean id="userBean" class="com.jkweilai.spring.bean.User"/>

创建的对象,会有一个id,一个id对应一个对象,然后存在大map中。

当你想获取bean的时候,你就要从spring容器上下文里面去获取,通过id获取

java 复制代码
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml","spring.xml");
java 复制代码
Object userBean = applicationContext.getBean("userBean");

spring集成的日志是 logback日志框架

引入依赖:

xml 复制代码
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.14</version>
</dependency>

logback.xml配置文件,必须放在类的根路径下

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 定义日志输出格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>

    <!-- 控制台输出 Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 文件输出 Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志文件路径 -->
        <file>logs/application.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天归档 -->
            <fileNamePattern>logs/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 单个文件最大 100MB -->
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 保留 30 天的历史 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>

    <!-- 设置日志级别 -->
    <!-- Spring Framework 的日志级别 -->
    <logger name="org.springframework" level="INFO"/>
    <!-- 项目的包路径,设置为 DEBUG 以便调试 -->
    <logger name="com.jkweilai" level="DEBUG"/>

    <!-- 根日志配置 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

日志级别

  1. TRACE:最低级别,用于记录所有日志信息。
  2. DEBUG:用于记录调试信息,便于开发人员进行调试,但不适用于生产环境。
  3. INFO:用于记录生产环境下的信息,如启动信息、用户登录信息等。
  4. WARN:用于记录警告信息,表示程序可能出现潜在问题。
  5. ERROR:用于记录错误信息,表示程序已经出现错误,需要进行处理。
  6. FATAL:最高级别,用于记录致命错误信息,表示程序已经无法继续执行,需要进行紧急处理。
  7. OFF:关闭所有的日志记录。

如何使用日志框架

java 复制代码
//创建日志工厂
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);
//调用日志方法
logger.info("我是一条日志消息");

bean的作用域

  • singleton:默认的,单例。
  • prototype:原型。每调用一次getBean()方法则获取一个新的Bean对象。或每次注入的时候都是新对象。
  • request:一个请求对应一个Bean。仅限于在WEB应用中使用
  • session:一个会话对应一个Bean。仅限于在WEB应用中使用
  • application:一个应用对应一个Bean。仅限于在WEB应用中使用。
  • websocket:一个websocket生命周期对应一个Bean。仅限于在WEB应用中使用。
  • 自定义scope:几乎用不上,感兴趣的可以研究。

BeanFactory和FactoryBean的区别

Spring IoC容器的顶级对象,BeanFactory被翻译为"Bean工厂",在Spring的IoC容器中,"Bean工厂"负责创建Bean对象。

BeanFactory是工厂。(创建bean的)

FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。

Bean的生命周期

  • 第一步:实例化Bean
  • 第二步:Bean属性赋值
  • 第三步:初始化Bean
  • 第四步:使用Bean
  • 第五步:销毁Bean

spring解决循环依赖的机理

首先:

1.创建A,通过实例化,创建A对象,然后将A提前曝光,将他放在三级缓存里面

2.发现A头上有@Autowired属性B,然后,将B创建,然后也曝光出去,将B放在三级缓存中

3.因为你不确定 B的类型是什么 有可能是代理对象,或者原始对象,不确定啊!

所以放在三级缓存里面确定一下,然后在跑半成品bean里面去创建,最后创建好,就将成熟bean放一级缓存里面。

Spring 不能解决的循环依赖场景有哪些

  1. 构造器注入:因为构造器注入要求在实例化之时就必须提供完整的依赖对象,而那时Bean本身都还未创建,更无法提前曝光,所以无法解决。
  2. 原型Bean(Prototype):Spring不缓存原型Bean,每次都会重新创建,因此无法利用三级缓存机制。

声明Bean的注解,这个是声明bean

  • @Component(@Controller、@Service、@Repository这三个注解都是@Component注解的别名)

  • @Controller

  • @Service

  • @Repository

  • 控制器类上使用:Controller===》控制访问层

  • service类上使用:Service ===》业务逻辑层

  • dao类上使用:Repository===》mapper层 数据访问层

给属性赋值的四个,这个是声明属性

  • @Value ==》(简单类型)
  • @Autowired==》注入非简单类型默认根据类型装配,spring框架自己的
  • @Qualifier==》@Autowired注解,在@Qualifier注解中指定Bean名称
  • @Resource==》默认根据名字装配,然后根据类型装配,属于JDK扩展包

关于Configuration和ComponentScan和Bean

  1. @Configuration==》配置类,
  2. @ComponentScan==扫描@component的衍生注解,比如@service,@controller ,纳入ioc
  3. @Bean==》可以将自己new的对象,纳入ioc容器管理

面向切面编程AOP

AOP的优点:

  • 第一:代码复用性增强。
  • 第二:代码易维护。
  • 第三:使开发者更关注业务逻辑

AOP的七大术语:

  • 连接点 Joinpoint:程序执行过程中可以插入切面的具体位置(如方法执行前、方法正常返回后、方法抛出异常时、方法最终结束时等)
  • 切点 Pointcut切点本质上就是一个"位置表达式",用来精确指定在哪些连接点织入切面
  • 通知 Advice:在切点处执行的增强逻辑代码
  • 切面 Aspect:切点 + 通知
  • 织入 Weaving:将切面应用到目标对象的过程
  • 代理对象 Proxy:被增强后产生的对象
  • 目标对象 Target:原始的需要被增强的对象

切点表达式

访问控制权限修饰符:

  • 可选项。
  • 没写时会匹配所有访问权限的方法。
  • 写public就表示只包括公开的方法。

返回值类型:

  • 必填项。
  • * 表示返回值类型任意。

全限定类名:

  • 可选项。
  • 在类路径中,.. 表示当前包及其所有子包
  • 省略时表示所有的类。

方法名:

  • 必填项。
  • * 表示所有方法。
  • set* 表示所有的set方法。

形式参数列表:

  • 必填项
  • () - 无参数方法
  • (..) - 任意参数(0个或多个)
  • (*) - 恰好一个参数,类型任意
  • (String) - 恰好一个String类型参数
  • (String, *) - 恰好两个参数,第一个是String,第二个任意
  • (*, String) - 恰好两个参数,第二个是String,第一个任意

异常:

  • 可选项。
  • 省略时表示任意异常类型。
text 复制代码
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])
java 复制代码
execution(public * com.jkweilai.mall.service.*.delete*(..))
    
    ● public:只匹配public方法
● *:返回值类型任意
● com.jkweilai.mall.service.*:com.jkweilai.mall.service包下的直接子类(不包含子包)
● delete*:方法名以delete开头
● (..):参数任意(0个或多个)

使用Spring的AOP(注解的方式

基于AspectJ的AOP注解式开发

1.要目标类,以及目标方法

2.定义切面类,使用@Aspect,在方法上,写切点表达式,发通知,用@Before

3.将目标类 以及 切面类 都纳入ioc bean的管理,加入@Component

java 复制代码
// 切面类
@Aspect
@Component
@Order(1) //设置优先级
public class MyAspect {
    
    // 切点表达式
    @Before("execution(* com.jkweilai.spring.service.OrderService.*(..))")
    // 这就是需要增强的代码(通知)
    public void advice(){
        System.out.println("我是一个通知");
    }
}

通知类型

通知类型包括:

  • 前置通知:@Before 目标方法执行之前的通知
  • 后置通知:@After 目标方法不管是否成功结束,后置通知都会执行(即时有未捕获的异常)
  • 返回通知:@AfterReturning 目标方法成功执行返回后执行的通知(目标方法出现未捕获的异常时,不会执行)
  • 异常通知:@AfterThrowing 目标方法发生异常后执行的通知
  • 环绕通知:@Around 目标方法执行之前和之后都可添加通知,可以控制目标方法是否执行

执行顺序:

  • 正常执行:@Around前半 → @Before → 目标方法 → @AfterReturning → @After → @Around后半
  • 异常执行:@Around前半 → @Before → 目标方法 → @AfterThrowing → @After → @Around后半
  • **注意:**目标方法出现异常,并且最终异常没有捕获的话,@Around后半 不会执行。

理解:

around = Before + after ,但是多了,可以控制中间函数的

顺序:

普通:前置 ==》 执行 ==》发生异常 ==》后置也会执行

如果是环绕round的话:发生异常 ,后置就不会执行了

对于事务的处理

  • 在一个业务流程当中,通常需要多条DML(insert delete update)语句共同联合才能完成,这多条DML语句必须同时成功,或者同时失败,这样才能保证数据的安全。
  • 多条DML要么同时成功,要么同时失败,这叫做事务。

处理的过程

  • 第一步:开启事务 (start transaction)
  • 第二步:执行核心业务代码
  • 第三步:提交事务(如果核心业务处理过程中没有出现异常)(commit transaction)
  • 第四步:回滚事务(如果核心业务处理过程中出现异常)(rollback transaction)

事务的四个特性

  • A 原子性:事务是最小的工作单元,不可再分。
  • C 一致性:事务要求要么同时成功,要么同时失败。事务前和事务后的总量不变。
  • I 隔离性:事务和事务之间因为有隔离性,才可以保证互不干扰。
  • D 持久性:持久性是事务结束的标志。

spring实现对事务的方式(注解方式)

事务的传播行为 七种

  • REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行**【有就加入,没有就不管了】**
  • MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】**
  • REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起,挂起就是把当前事务暂停,等新事务完成后,再恢复继续执行】**
  • NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
  • NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
  • NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【当前有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。当前没有事务就和REQUIRED一样。嵌套事务的特点是:外层回滚会导致内层回滚】
    一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】**
  • REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起,挂起就是把当前事务暂停,等新事务完成后,再恢复继续执行】**
  • NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
  • NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
  • NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【当前有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。当前没有事务就和REQUIRED一样。嵌套事务的特点是:外层回滚会导致内层回滚】
相关推荐
草原印象17 小时前
Spring、SpringMVC、Mybatis框架整合实战视频课程
java·spring·mybatis
悟空码字17 小时前
刚刚,TRAE宣布,全量免费开放
后端·trae·solo
东百牧码人17 小时前
C# 雪花ID实现方案
后端
乌日尼乐17 小时前
【Java】IO流完全指南
java·后端
Java水解17 小时前
Spring Boot:Java开发的神奇加速器(二)
spring boot·后端
sunbin17 小时前
Eclipse 数据空间组件-最小化运行环境MVD_of_EDC-10
后端
问道飞鱼17 小时前
【Rust编程】Cargo 工具详解:从基础到高级的完整指南
开发语言·后端·rust·cargo
zhaokuner17 小时前
14-有界上下文-DDD领域驱动设计
java·开发语言·设计模式·架构
信码由缰17 小时前
停止编写Excel规格文档:企业级Java开发的Markdown先行方法
java·ai编程·markdown