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一样。嵌套事务的特点是:外层回滚会导致内层回滚】
相关推荐
㳺三才人子6 小时前
初探 Flask
后端·python·flask·html
星栈独行6 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Lei活在当下6 小时前
先用起来,再理解,关于协程Coroutine应该知道的事
android·java·jvm
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易7 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
tongluowan0077 小时前
以ReentrantLock为例解释AQS的工作流程
java·模板方法模式·aqs·reentrantlock
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl8 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
身如柳絮随风扬8 小时前
Java 项目打包与部署完全指南:JAR vs WAR,从构建到运行
java·firefox·jar
云烟成雨TD8 小时前
Spring AI Alibaba 1.x 系列【62】时光旅行(Time-Travel)
java·人工智能·spring