首页 > 其他分享 >spring

spring

时间:2022-10-23 23:01:37浏览次数:45  
标签:事务 缓存 对象 spring beanName Bean Spring

Bean的生命周期

BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean。

1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

2)利用依赖注入完成 Bean 中所有属性值的配置注入。

3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。

8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

10)如果在 <bean> 中指定了该 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 <bean> 中指定了该 Bean 的作用范围为 scope="prototype",则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

三级缓存问题

getBean()==>doGetBean()==>createBean()==>doCreateBean()

创建Bean的部分源码如下

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    ...
    @Override
    @Nullable
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //1.先从一级缓存中获取,获取到直接返回
        Object singletonObject = this.singletonObjects.get(beanName);
        //2.如果获取不到或对象正在创建,就到二级缓存中去获取,获取到直接返回
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                //3.如果仍获取不到,且允许 singletonFactories(allowEarlyCurrentlyInCreation())通过 getObject()获取。
                //就到三级缓存中用 getObject() 获取。
                //获取到就从 singletonFactories中移出,且放进 earlySingletonObjects。
                //(即从三级缓存移动到二级缓存)
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }
    ...
    public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
    protected boolean isActuallyInCreation(String beanName) {
        return isSingletonCurrentlyInCreation(beanName);
    }
    ...
}

三级缓存的源码

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    ...
    // 从上至下 分表代表这“三级缓存”
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
    ...
    
    /** Names of beans that are currently in creation. */
    // 这个缓存也十分重要:它表示bean创建过程中都会在里面呆着~
    // 它在Bean开始创建时放值,创建完成时会将其移出~
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    /** Names of beans that have already been created at least once. */
    // 当这个Bean被创建完成后,会标记为这个 注意:这里是set集合 不会重复
    // 至少被创建了一次的  都会放进这里~~~~
    private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}

singletonsCurrentlyInCreation:

在实例化之前存入,添加到singletonObjects之后删除,用于判断bean对象是否正在创建

alreadyCreated:

Bean被创建完成后,会进入,表示Bean被创建过至少一次

一级缓存:singletonObject = ConcurrentHashMap<>(256)

存放以及初始化完成后的单例对象或者代理对象(如果对象需要被代理),可以直接使用的Bean

二级缓存:earlySingletonObject = HashMap<>(16)

存放出现循环依赖后被创建的代理对象(保证单例)或者普通对象(没有经过完整生命周期的bean)

三级缓存:singletonFactories = HashMap<>(16)

在实例化对象之后,属性注入之前会将对象放入singletonFactories,用于打破循环

为什么要包装一个ObjectFactory对象?

如果创建的Bean有对应的aop代理,那其他对象注入时,注入的应该是对应的代理对象;「但是Spring无法提前知道这个对象是不是有循环依赖的情况」,而正常情况下(没有循环依赖情况),Spring都是在对象初始化后才创建对应的代理。这时候Spring有两个选择:

  • 不管有没有循环依赖,实例化后就直接创建好代理对象,并将代理对象放入缓存,出现循环依赖时,其他对象直接就可以取到代理对象并注入(只需要2级缓存,singletonObjects和earlySingletonObjects即可)
  • 不提前创建好代理对象,在出现循环依赖被其他对象注入时,才提前生成代理对象(此时只完成了实例化)。这样在没有循环依赖的情况下,Bean还是在初始化完成才生成代理对象(需要3级缓存)

所以3级缓存的作用

  • 为了正常情况下,代理对象能在初始化完成后生成,而不用提前生成
  • 在对象需要被代理的时候提前生成代理对象,如果有其他bean对象需要这个普通对象时就将代理对象注入属性,否则如果注入的属性是普通对象的话,而被注入的类对象的引用指向的是一个普通对象,代理逻辑就不会执行

Spring事务管理

Spring提供上层接口PlatformTransactionManager,然后通过其实现类来做事务(Mybatis使用DateSourceTransactionManager,Hibernate使用HibernateTransactionManager),底层都是使用AOP完成

通过AOP实现,在代理对象里面获取connection,然后存入ThreadLocal,在执行super的方法,super去ThreadLocal获取代理对象存入的connection,保证拿到的是同一个connection,在决定是否抛异常和回滚

编程式事务

在代码里面声明,先开启事务,执行事务,是否提交事务

声明式事务

基于注解

基于xml

传播特性(propagation)

PROPAGATION_REQUIRED:

如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。(required需要,没有新建,有加入)

PROPAGATION_SUPPORTS:

支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。(supports支持,有则加入,没有就不管了,非事务运行)

PROPAGATION_MANDATORY:

支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。(mandatory强制性,有则加入,没有异常)

PROPAGATION_REQUIRES_NEW:

创建新事务,无论当前存不存在事务,都创建新事务。(requires_new需要新的,不管有没有,直接创建新事务)

PROPAGATION_NOT_SUPPORTED:

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(not supported不支持事务,存在就挂起)

PROPAGATION_NEVER:

以非事务方式执行,如果当前存在事务,则抛出异常。(never不支持事务,存在就异常)

PROPAGATION_NESTED:

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。(nested存在就在嵌套的执行,没有就找是否存在外面的事务,有则加入,没有则新建)

 

.

标签:事务,缓存,对象,spring,beanName,Bean,Spring
From: https://www.cnblogs.com/happy12123/p/16813337.html

相关文章

  • SpringBoot启动过程(一)
    1,创建SpringApplication实例1.1设置WebApplicationType(应用类型)目前有三种类型,SERVLET或者REACTIVE或者NONE判断是根据某些特定的类是否存在来判断的,具体推断方法为deduceF......
  • SpringBoot项目整合Mybatis时Mapper.xml文件的存放位置
    SpringBoot项目整合Mybatis时Mapper.xml文件的存放位置目录:方式一:放在与Mapper接口同级目录方式二:在resources创建Mapper接口同名文件夹用来存放Mapper.xml文件方式三:......
  • SpringMVC框架详解
    简述SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring FrameWork的后续产品,已经融合在SpringWebFlow里面。Spring......
  • 23、ssm整合回顾-spring层
    1、spring-dao.xml<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XM......
  • SpringBoot中https的配置
    配置#https://help.aliyun.com/document_detail/365559.html#HTTPS协议默认端口号为443,需要使用其他端口时,您可以在此处自定义。server.port=8002#https://docs.ora......
  • SpringBoot(九) - Swagger
    1、依赖<!--swagger核心--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.8.0</version></d......
  • springcloud学习记录day05--分布式搜索 elasticsearch
    分布式搜索-elsaticsearchelasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容,从而弥补MySQL在复杂搜索上的短板......
  • Spring —— bean实例化
    bean实例化bean本质上就是对象,创建bean使用构造方法完成(反射)    构造方法(常用)      静态工厂*      实例工厂*      FactoryBean(实用)......
  • Spring —— bean配置
    基础配置    别名配置  作用范围配置    适合交给容器进行管理的bean  (复用性的对象,无需重复创建的对象)表现层对象业务层对象数据层对象工具对象......
  • Spring —— DI入门案例
    DI入门案例  思路分析:    1、基于IoC管理bean    2、Service中使用new形式创建的Dao对象是否保留(否)    3、Service中需要的Dao对象如何进入Service中?(提......