当前位置: 首页 > news >正文

SpringBoot

1、Bean的生命周期:
(1)bean的创建步骤:创建过程主要依赖AbstractAutowireCapableBeanFactory类,销毁过程主要依赖DisposableBeanAdapter类。
Spring扫描配置文件、注解内容、类路径class文件获得BeanDefinition
BeanDefinition就绪后会读取 BeanDefinition 中所对应的class文件来加载类。
实例化阶段:使用BeanFactory根据BeanDefinition来实例化,得到原始
对象(未进行属性注入以及初始化的对象 这里简称为 原始对象)
属性注入阶段:对 Bean 的属性进行依赖注入 (这里就是发生循环依赖问题的环节)
如果 Bean 的某个方法有AOP操作,则需要根据原始对象生成代理对象。
最后把代理对象放入单例池(一级缓存singletonObjects)中
初始化:5步
ⅰ. 检查是否实现了Aware接口:BeanNameAware、BeanFactoryAware、BeanClassLoaderAware,分别获取Bean名字,加载器,factory的引用。
ⅱ. 调用BeanPostProcessor的前置处理方法:拓展点;修改Bean的名称属性,校验bean等。
ⅲ. 实现了ApplicationContextAware接口,会调用setApplicationContext方法
ⅳ. 实现了InitializingBean接口,会调用afterPropertiesSet()方进行初始化
ⅴ. 调用自定义的init-method方法
ⅵ. 调用BeanPostProcessor接口,注册AOP的动态代理对象

销毁:3步
注册bean对象销毁的回调函数
使用bean
desposable-bean方法
自定义的destroy-method

检查Aware:如果bean实现了BeanNameAware、BeanClassLoaderAware等接口,Spring容器就会在initializeBean方法中调用
调用BeanPostProcessor的前置处理方法:例如修改Bean的状态
调用InitializingBean的afterPropertiesSet方法:
调用自定义的init-method方法:可以在xml文件中指定Bean的初始化方法
调用BeanPostProcessor的后置处理方法:
注册Destruction回调:为Bean注册一个销毁回调,在容器关闭的时候可以及时清理资源
Bean准备就绪:
调用DisposableBean的destroy方法
调用自定义的destroy-method
(1)创建前准备:从上下文解析并查找Bean的有关拓展的实现
(2)创建实例化:通过反射创建对象
(3)依赖注入:把bean依赖的对象注入
(4)容器缓存:将bean保存到IOC容器当中
(5)销毁实例:应用上下文被关闭之后就销毁bean,或者调用destroy-method
2、Spring事务
程序能否支持事务管理取决于数据库是否支持事务,如果用MYSQL那可以支持事务,如果用的是Myisam不支持事务。
(1)编程式事务管理
手动管理事务,比较灵活
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {try {// ....  业务代码} catch (Exception e){//回滚transactionStatus.setRollbackOnly();}}});

}
@Autowired
private PlatformTransactionManager transactionManager;

public void testTransaction() {

TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
// .... 业务代码
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}
(2)声明式事务管理
加@Transactional注解
(3)事务管理接口
PlatformTransactionManager:
事务管理器接口,用于管理事务的,具体实现是由JDBC、JAC平台做实现。
接口中三个方法:getTransaction、commit、rollback
TransactionDefination:
定义了事务的五个方便的基本属性:
隔离级别:
和MYSQL的隔离级别相一致。
默认、读未提交、读已提交、可重复读、串行化。
传播行为:
事务传播行为是用来描述由某一个事务传播行为修饰的方法被嵌套入另一个方法时事务是如何传播的。
有如下七种属性:
TransactionDefinition.PROPAGATION_REQUIRED:
如果外部方法没有开启事务,则内部被修饰的方法会新开自己的事务。
如果外部方法和内部方法都是required,则二者属于一个事务。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:
内部方法单独创建一个新事务,把当前外部方法的事务挂起。如果内部方法被requies new修饰,则会单独开一个事务,外部方法回滚不影响内部方法。而内部方法回滚,外部方法也会跟着回滚。
TransactionDefinition.PROPAGATION_NESTED
在外部方法开启事务的情况下,则在嵌套事务内运行。
如果外部方法无事务,则内部方法单独开启一个事务,与 PROPAGATION_REQUIRED 类似。
TransactionDefinition.PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制的)
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
回滚规则:
定义了哪些异常会导致事务会回滚,@Transactional(rollbackFor=Exception.class)
默认运行时异常、Error都会回滚,但是受检异常不会回滚。
是否只读:
是否为只读事务(不进行写操作)。如果给事务加上注解的时候,事务内的所有sql在MYSQL中都会被放到一个事务中(而不是一条sql单独开一个事务)。
如果一次只执行单条的sql语句就没必要开事务支持;
如果一次执行多条sql语句,例如报表查询、统计查询等。就需要开事务,保证线程安全。
事务超时:
一个事务允许的最长执行时间。
TransactionStatus:
定义了事务状态:
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事务
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
(4)事务与AOP
Spring是使用AOP的动态代理来实现事务管理的。代理对象是在BeanpostProcessor的后置处理方法里面生成的。
如果一个类或者一个public 方法被标注了@Transactional的话,Spring容器在启动的时候就会为它创建一个代理类。在调用这个方法的时候实际上调用的是TransactioanInterceptor的invoke( )方法。
它的作用就是在目标方法开始前向MYSQL发送开启事务的指令来开启事务(START TRANSACTION),执行过程中碰到异常回滚事务(rollback),执行结束提交事务(commit)。
如果是编程式事务就得在catch块中手动回滚事务,status.rollback()。
(5)AOP自调用的问题
如果一个方法被标记@Transactional注解的话,事务管理器只会在被其他类方法调用时生效,类内的方法调用会导致事务失效。
解决办法:从AOP上下文里面显式的拿到代理对象去调这个被事务修饰的方法。
(5)注意事项
底层用的数据库需要支持事务!
注解只能加在public方法上
不能在类内调用事务管理的方法
需要设置事务传播和回滚属性
被注解的方法所在的类必须被Spring管理,因为事务基于AOP!
(6)事务失效场景:
代理失效:AOP失效了,导致事务也失效;@Transactional加在非public修饰的方法上,例如private方法只能在当前对象中的其他方法调用,这种情况是用this来调用的,不会走代理,所以会失效;同一个类中方法调用;static、final方法;bean没有给Spring管理,压根没有代理对象
@Transactional注解使用错误:传播属性错误(NOT_SUPPORTED)、回滚属性错误(@Transacotion(rollbackFor=RuntimeException.class)就只会在运行时异常回滚)
异常被catch,无法回滚
多线程下使用@Transacotional注解导致事务失效,因为基于注解的事务管理是使用ThreadLocal来存储事务上下文的,而多线程的情况下,每个线程都有自己的事务上下文副本,这个时候处理不了多线程事务。
数据库不支持事务

3、Spring如何解决bean的循环依赖问题
依赖的类型:自身依赖、多个实例之间依赖

4、Spring如何定义bean?
1、使用xml文件定义Bean
2、@Configuration+@Bean注解
● @Configration 注解:声明当前类是一个配置类,相当于 Spring 中的一个 XML 文件,启动的时候就会扫描这个配置类。
● 然后需要在resource目录下面META-INF目录里面有spring factories文件,在这个文件里加上配置类的路径。
● @Bean 注解:作用在方法上,声明当前方法的返回值是一个 Bean
Spring容器启动的时候会扫描@Configuratrion注解并加载
3、使用@Component、@Service、@Repository、@Controller、@Mapper、@MapperScan注解
4、使用@Import注解去快速导入一个或者多个类,有三种导入方式
5、使用@ComponentScan注解扫描
5、@DubboService,可以把一个类的实例创建出来放到 IOC里面等远程调用。
在Spring 应用启动过程中,Dubbo通过自定义的BeanDefinitionRegistryPost
Processor和BeanFactoryPostProcessor来扫描配置的包路径,识别出带有
@DubboService)注解的类。这些处理器解析注解中的属性(如接口类、版本号、超
时时间等),并基于这些信息创建Spring的BeanDefinition
5、SpringBoot的三种扫描并加载Bean的方式
1、默认的扫描路径:标注了@SpringBootApplication的启动类路径及下面的子包
2、@ComponentScan("com.example.xxx"),指定要扫描的路径
3、@Import({xxx.class}),指定要加载的类
普通类:@Import("xxx.class")
ImportSelector的实现类:重写selectimport方法,返回值就是一个String数组
ImportBeanDefinationRegister的实现类:手动向IOC容器注册
6、Spring的IOC
定义:IOC就是控制反转,对象创建和管理都交给IOC容器,要用的时候直接从IOC拿就行。
优点:不用关心Bean的使用细节、Spring的bean默认是单例的,不会创建多个bean浪费资源
IOC的理解:
1、反射:
2、依赖注入:构造函数、setter、注解三种方法注入,管理程序组件之间的 依赖关系。
3、设计模式-工厂模式:使用BeanFactory或者ApplicationContext管理Bean的生命周期。把对象控制劝交给容器管理。
如何实现:
1.从配置元数据中获取要Dl的业务POJO(这里的配置元数据包括xml,注解,configuration类等)
2.将业务POJO形成BeanDefinition注入到SpringContainer中
3.使用方通过ApplicationContext从SpringContainer直接获取即可。如下图所示:
//创建ioc容器,扫描包及其子包下中带有可以注册为bean的注解
ApplicationContext applicationcontext = new AnnotationConfigApplicationContext("cn.example.spring,ioc");
/从容器中获取bean
Bean bean = applicationcontext.getBean(Bean.class);
//使用bean的方法
bean.use();

7、Spring的@Configration注解可以不写吗?写不写有什么区别?
@Configration 注解底层也是一个@Component注解,直接用也没问题。
但是如果我在配置类的方法里面多次调用另一个方法,那么另一个方法会多次创建bean,破坏了单例性。
而@Configration 就会创建配置类的CGLIB动态代理,在要创建bean的时候直接从IOC容器里面找,保证单例性。
8、自动配置@Auto-Configuration 和自动装配@Autowire
自动配置:基于引入的依赖jar包,对SpringBoot应用进行自动配置,可以做到开箱即用。
自动装配:就是依赖注入,从IOC容器注入Bean
配置类:
广义配置类: 被@Component直接或间接修饰的类
狭义的配置类:被@Configuration修饰的类
举例:Redis的自动配置: 1、pom.xml文件引入依赖 2、在application.yml文件里配置redis的连接信息 3、直接依赖注入redisTemplate即可
9、SpringBoot的启动流程
SpringApplication.run() 启动!!!
1、创建IOC容器,也就是applicationContext
2、加载主类
3、递归的加载所有配置类,这些配置类可以是主类同包下,也可以是其他包(用@ComponentScan)
从源配置类出发根据@ComponentScan和@Import出发一直往下递归扫描@Scan和@Import注解
@ComponentScan是扫描对应路径下的被@Component修饰的配置类
@Import是显式地直接加载配置类,支持导入:
普通类:@Import("xxx.class")
ImportSelector的实现类:重写selectimport方法,返回值就是一个String数组
ImportBeanDefinationRegister的实现类:手动向IOC容器注册
4、实例化所有的Bean,进行依赖注入和自动装配
5、启动web服务器

10、Spring自动装配的原理:
(1)对于@SpringBootApplication注解,包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan,三个关键注解。
(2)自动装配就依赖于@ComponentScan注解与@EnableAutoConfiguration注解里的@Import注解。
其中@ComponentScan默认扫描SpringBootApplication所在路径以及路径下的子类。
其中@EnableAutoConfiguration注解下包含了
@Import(AutoConfigurationImportSelector.class)来实现自动装配。
执行SpringApplication.run( )方法后就会执行AutoConfigurationImportSelector下的selectorImports方法,这个方法使用SpringFactories机制加载配置文件,使用Classloader获取META-INF/Spring.factories配置文件,然后筛选其中以EnableConfiguration的全限定名为key的所有value,这些value就是符合条件的自动配置类的全限定名,最后再根据@Conditional注解进行过滤,只有满足条件的类才会被加载到SpringIOC容器当中。
然后基于JavaSPI机制和SpringFactories机制实现自动装配功能

@Conditional:只有满足一定条件才会注册Bean到IOC容器里面

11、如何自定义一个Starter?
1、首先添加依赖SpringBoot
2、创建一个moudle,搭建MVC框架
3、新建一个自动配置类,加上@Configuration注解,
根据@ConditionalOn...来条件化地配置Bean(例如@ConditionalOnMissingBean,在没有Bean的时候才提供默认实现),
根据@ConfigurationProperties来配置属性

4、创建配置文件:
Spring2 :resource->META-INF->spring.factories
Spring3:resource->META-INF-> xxx.AutoConfigration.imports
在文件里添加自动配置类的全类名,保证到时候可以扫描到。
5、在maven生命周期里面clean和inatsll到本地maven仓库里面。
6、在另一个项目里添加starter依赖,之后就可以进行依赖注入了。
12、Spring的AOP
定义:AOP即为面向切面编程,也是一种AOP思想(是OOP的补充,OOP是面向对象的,AOP是面向切面的),把公共逻辑抽象出来
AOP的使用:日志收集、权限校验
基本概念:
切面:切入点+通知
切入点:被增强的方法
切入点表达式:
1、execution根据访问修饰符、返回值、包名、类名、方法名
@Around("execution(...)")
2、基于注解标记
@Around("@annotation(注解的全限定名)")
通知:抽取出来的公共逻辑,对目标的方法进行增强
通知类型:环绕通知、前置通知、后置通知、返回后通知、异常后通知
织入:把切面和业务逻辑连接起来,创建一个代理对象,织入可以在编译时和运行时,编译时就是静态代理,运行时就是动态代理
AOP实现流程:
AOP是在Bean实例化结束之后的初始化的后置处理阶段通过反射创建一个代理对象,具体有两种代理模式:
基于JDK的动态代理:只能代理实现了接口的类,java.lang.reflect.Proxy
基于CGLIB动态代理:可以代理没实现接口的类
AOP失效场景:
static、final方法调用
类的方法调用私有方法
类内方法的自调用
内部类方法调用

13、Spring的依赖注入
1、字段注入:@Autowired、@Resource
@Autowired可以注入List、Map、Set、数组,可以使用@Autowired(required=false),来处理找不到匹配的bean时就注入null。
二者的区别:
@Autowired是先byType再byName,而@Resource恰好相反
@Autowired可以作用在 构造函数、字段、setter方法上,而@Resource不能作用在构造函数上
@Autowired是Spring提供的,@Resource是JDK官方提供的。
字段注入出现的循环依赖可以通过spring三级缓存解决(单例+非构造函数注入)
2、构造函数注入:
Spring官方推荐注入方法:因为构造函数注入的Bean对象一定是final类型的,确保安全性,并且可以确保非null,此外可以直接通过构造器传入mock对象。
单一职责原则:依赖注入都在构造函数里,如果构造函数臃肿也在变相提醒我们可能违背单一职责原则,需要进行代码重构。
不存在NPE问题:基于字段注入可能出现NPE问题

构造器注入存在的问题:无法解决循环依赖问题,可以加@Lazy注解解决

@RequiredArgsConstructor:将要注入的对象标注为final,会自动生成构造函数注入。
3、setter方法注入:对象创建之后调用该方法进行依赖注入
14、Spring的Aware接口
Aware是一种回调接口,让bean向容器表明需要某种依赖,容器会调用这个接口,这叫做回调比如说:bean可以实现ApplicationContextAware接口,接口回调的时候会传入applicationcontext(IOC)对象。
15、Spring的设计模式
享元模式、不可变模式
16、Spring解决循环依赖
情形一:使用构造方法进行依赖注入(Spring无法解决):
@Component
public class ServiceA {
private final ServiceB serviceB;

// 构造方法注入
public ServiceA(ServiceB serviceB) {this.serviceB = serviceB;
}

}
@Component
public class ServiceB {
private final ServiceA serviceA;

// 构造方法注入
public ServiceB(ServiceA serviceA) {this.serviceA = serviceA;
}

}
构造方法需要一次性将所有的入参全部注入,所以会产生循环依赖
解决方案一:
@Component
public class ServiceA {
private ServiceB serviceB;
// 改用 setter 注入
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
解决方案二:
@Component
public class ServiceA {
private final ServiceB serviceB;

public ServiceA(@Lazy ServiceB serviceB) {   // 关键:@Lazythis.serviceB = serviceB;
}

}
情形二:通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题

一级缓存:singletonObjects---ConcurrentHashMap。存储的是完整的bean单例对象。
二级缓存:earlysingletonObjects---ConcurrentHashMap。存储的是半成品bean。
主要用于处理循环依赖。
三级缓存:singletonFactories--Hashmap。存储的是单例bean的创建工厂beanfactory。调用getObject()获得bean

spring解决循环依赖的前提:
相互依赖的bean是单例、依赖注入的方式不能是构造函数注入。
解决循环依赖的方思路:
在单例bean的循环依赖问题上,可以采用通过对象的提前暴露解决循环依赖,如果一个bean依赖另一个bean,就会提前暴露另一个bean的半成品对象实例给当前bean去绕过循环依赖。因为单例的创建和初始化只会发生一次,这种依赖关系不会变化,所以可以提前暴露。
但是如果是原型对象,它就可以创建并修改多次,这就不能提前暴露去解决循环依赖问题。
解决循环依赖的具体流程:先去getBean ServiceA ,发现一级缓存没有完整Bean,二级缓存没有半成品Bean,就把ServiceA 的factory加入三级缓存,然后调用Bean Factory来初始化Bean,发现要注入ServiceB,就依次去一级缓存、二级缓存找,发现没有就把ServiceB的BeanFactory加入三级缓存,然后初始化ServiceB,发现它要依赖ServiceA,就去依次检查一级、二级缓存里有没有,如果没有就在三级缓存里调用ServiceA的Factory初始化A,得到一个半成品放到二级缓存,这里就提前暴露了ServiceA,ServiceB就注入ServiceA的半成品完成初始化,放入一级缓存,然后ServiceA注入ServiceB完成初始化,放入一级缓存。
不能解决构造函数注入产生的循环依赖,因为实例化的过程中构造函数是最先被调用的,此时对象还没完成实例化,没法直接注入一个半成品。那么这个时候可以改成字段注入或者setter注入,或者使用@Lazy注解解决。
17、Spring中Bean的作用域
使用@Scope注解来设置Bean的作用域
1、单例Singleton:每个IOC容器里都只有一个,这种情况如果bean中有共享变量,则为有状态的bean,就会有线程安全问题。
如何解决呢:用Prototype作用域、加锁、用并发包的工具类对共享变量处理。
2、原型Prototype:每次请求都会创建一个新的 ,这种情况没有线程安全问题
3、请求Request:每次请求创建一个
4、会话Session:每次会话创建一个
5、应用Application:ServeletContext的生命周期里面创建一个
18、@Schedule注解执行定时任务
在项目中定时任务用于:task任务兜底
@Scheduled(fixrate=5000)隔5秒
@Scheduled(cron=“0 0 0 * *”) //秒 分 时 日 月 ,这里就是每天0点0时0分执行
19、@Autowired注解的底层原理
大体步骤:先根据type查找、再根据name查找。
先根据bean类型到IOC容器查找符合条件的bean list,依次根据@Qualifier(指定bean的名称)、@Primary(加载主bean)、@Priority(bean上加这个注解,注解中的值表示优先级,值越低优先级越高)。
在此期间如果有且只有一个bean就返回,如果没找到就根据@Autowired注解中requied属性(true即为“不能为空”,false可以为空)来决定没找到的时候是抛异常还是返回null。

多个类型相同的bean冲突如何解决:使用@Qualifier和@Primary来指定名称或者主bean。
23、MVC设计
MVC模式:
模型:处理业务的核心逻辑,主要是crud
视图:显示数据
控制器:视图和模型之间的交互逻辑,主要是调用下游的接口处理。
MVC思想:将应用程序的表示和处理通过控制器分开,提升代码可读性与复用性。
三层架构:表示层、业务逻辑层、数据访问层
24、Spring的Bean一定是线程安全的吗?
https://cloud.tencent.com/developer/article/1743283

http://www.hskmm.com/?act=detail&tid=9564

相关文章:

  • Redis笔记
  • MYSQL 笔记
  • Java笔记
  • 分布式 笔记
  • Windows Server 2019 中文版、英文版下载 (2025 年 9 月更新)
  • Windows Server 2016 中文版、英文版下载 (2025 年 9 月更新)
  • Windows Server 2025 中文版、英文版下载 (2025 年 9 月更新)
  • 美联储降息 25 个基点,这事儿跟我们有多大关系?
  • Windows Server 2022 中文版、英文版下载 (2025 年 9 月更新)
  • 袋鼠云跻身榜单2025中国Data+AI创新企业榜Top15,入选“2025中国隐形独角兽500强”榜单等多项荣誉
  • k8s系列--前世今生
  • excel文本改为数据格式
  • 面向对象初步接触-学生信息管理系统
  • Numpy高维数组的索引()
  • 详细介绍:jQuery 操作指南:从 DOM 操作到 AJAX
  • 一个 Blazor/WinForm 开发者的 WPF 学习记:通往 Avalonia 的那条路
  • VulkanAPI细节梳理2
  • React 状态丢失:组件 key 用错引发的渲染异常 - 指南
  • 快速实现 Excel 表格转 SVG:Java 教程 - E
  • 绕过文件上传限制实现客户端路径遍历漏洞利用的技术解析
  • 事件总线之初步学习
  • Markdown Day04
  • C++中类的内存存储
  • PyTorch 优化器(Optimizer)
  • 实用指南:域名市场中,如何确认域名的价值
  • 初步了解Neo4j
  • 多模态和语音 AI 年度收官大会,把握 2026 技术风向标!
  • 做题
  • 解码C语言函数
  • SchemaStore