IOC容器的初始化流程和getBean的流程
加载流程
ioc容器先加载xml文件,解析所有<bean>标签,并把每一个<bean>标签都封装成一个对象(beanDefination:仅仅是一个描述对象,记录这个类相关的信息),在解析完成后进行初始化,创建单例的bean存放在SinletonObjects中
getBean时
使用getBean(对象在ioc的名称),
先去单例对象集合SinletonObjects中找(找到直接返回对象),
如果没有就去beanDefination找
(找对应的对象的描述,根据scope的值
如果是多例:直接调用createBean(利用反射把对象创建返回)---》容器不会维护,每一次创建都是新的对象
如果是单例:利用反射把对象,创建后存储到单例集合(SinletonObjects)一份再返回对象)
都没有就报异常NoSuchBeanDefinationException,
IOC容器初始化流程
IOC容器getBean的具体流程
SpringBean的配置方式
xml文件形式(ClassPathXmlApplicationContext)
注解(AnnotationConfigApplicationContext)
基于Java类+配置注解的方式(@Configuration @Bean)
IOC容器Bean的作用域
依赖注入的三种方式
set注入
构造器注入
注解注入
Spring常用注解
- @ComponentScan 组件扫描,扫描指定包下的@Component @Controller @Repository
- @Controller 标记当前类为容器对象,代表 控制层 组件
- @Repository 标记当前类为容器对象,代表 持久层 组件
- @Service 标记当前类为容器对象,代表 服务层 组件
- @Component 标记当前类为容器对象,代表 组件
ps:@Controller @Repository @Service @Component 四个注解均代表组件的意思,@Controller @Repository @Service三个注解均继承了@Component,只是用来区分不同层级
- @Autowired 自动装配注解,默认按类型装配
- @Transactional 事务注解
- @Value 将配置文件中的值注入到指定字段中
- @Bean 配置bean对象,作用与<bean>标签一致
- @Configuration 标记当前java类是一个配置类
@Autowrite 和@Resoure 的区别
@Autowired:
按照类型去容器找 (spring提供的注解)
会存在问题,当容器中同类型的对象有多个时,会报错
而此时需要配合@Qualifier一起使用,改为根据bean名称去找
@Resoure :
按照bean名称去容器找 (JDK自带的注解)
而@Resoure 本身就是根据名称去找,自然不会存在上述问题
springBean同名的覆盖问题
可以在设置中设置不允许覆盖(此时如果有同名bean,会报错)
循环依赖问题
IOC容器默认解决 scope为单例的循环依赖问题(三级缓存)
springBean的生命周期
简化版
详细版(单例对象是十一步,多例对象9步(因为ioc容器不存储))
以运行以下方法为例
代码:
xml文件
运行过程示例
-
IOC容器利用反射调用对象无参构造创建新对象
-
通过set方法给对象设置属性
-
如果有需要,可以实现BeanNameAware来获得对象名称
-
如果有需要,可以实现ApplicationContextAware来获得容器,以此来获取容器中的bean对象,进行统一的处理
-
实现BeanPostProcessor的类称为统一Bran的后置处理器,先执行postProcessBeforeInitialization(可以统一在执行初始化之前的操作)
-
实现InitializingBean接口中的afterPropertiesSet方法可以在初始化后对我们的类做一些处理 例如缓存
-
执行自己配置的初始化方法
-
实现BeanPostProcessor的类称为统一Bran的后置处理器,执行postProcessAfterInitialization(可以统一在执行初始化之后的操作)
-
执行对象本身的业务方法
-
执行spring对象本身的销毁方法先执行(实现接口的方法)
-
自己配置的方法后执行
SpringAOP
简单理解
面向切面编程
实际应用场景
定义切面类
加上注解:@Aspect @Component
AOP工作原理
默认JDK,可切换CGLIB
Spring事务
spring事务的配置方式
springBoot事务
spring事务的隔离级别
spring事务的失效场景
- 数据库引擎不支持事务
- 没有被spring管理
- 方法不是public
- 自身调用问题--》方法a调用方法b,事务注解在方法b中
- 数据源未配置事务管理(现在springBoot默认配置,不会出现这个问题)
- 在传播行为中设置了不支持事务
- 异常被捕获了 (try {} catch{})
- 异常类型错误,默认捕获的是RuntimeException
--》解决办法:把异常捕获范围加大
Spring事务的传播行为(两个有事务的方法相互调用)
分类(七种):
PROPAGATION_REQUIRED
表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。( 如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_SUPPORTS
表示当前方法不必需要具有一个事务 上下文,但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION_MANDATORY
表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED
表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中 ,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation. required的一样
Spring中的事务设置可以设置传播行为,用来控制方法调用过程中事务的传播方式,包括:
- REQUIRED:表示当前方法必须运行在事务中,如果当前存在事务,则加入该事务,否则创建新的事务。
- SUPPORTS:表示当前方法不需要事务上下文,如果当前存在事务,则在该事务中执行,否则继续在非事务性上下文中执行。
- MANDATORY:表示该方法必须在事务中执行,如果当前存在事务,则在该事务中执行,否则抛出异常。
- REQUIRES_NEW:表示当前方法必须运行在它自己的事务中。如果当前存在事务,则挂起该事务,创建新的事务,执行完后再将挂起的事务恢复执行。
- NOT_SUPPORTED:表示该方法不应运行在事务上下文中,如果当前存在事务,则挂起该事务,执行完后再将挂起的事务恢复执行。
- NEVER:表示该方法不应该运行在事务上下文中,如果当前存在事务,则抛出异常。
- NESTED:表示该方法必须运行在它自己的嵌套式事务中,并且这个嵌套式事务是被外部事务所驱动的。
根据实际业务需求选择合适的传播行为可以更加灵活地处理事务,提高系统性能和代码健壮性。
常用的两种
PROPAGATION_REQUIRED
表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。( 如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
下图:方法a开启事务,调用方法b时出现异常,方法b跟着方法a回滚
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
下图:方法a开启事务,调用方法b时方法b新开事务,b完成后提交,此时出现异常,仅方法a回滚
以上均为个人见解,侵删
有不对的或者还有遗漏的欢迎各位大佬补充,致谢