spring bean三级缓存简介说明

欣喜 Spring 发布时间:2024-07-26 16:59:16 阅读数:594 1
下文笔者讲述spring bean三级缓存的简介说明

三级缓存简介

三级缓存指 bean创建时,三个存储容器的集合
singletonObjects、earlySingletonObjects 和 singletonFactories

Spring三级缓存功能

一、解决循环依赖问题:
      当一个Bean创建依赖于其他Bean创建时
	   就可能会出现循环依赖的问题
	   Spring 的三级缓存机制可以通过代理对象的方式来解决循环依赖问题。

二、确保单例模式:
       Spring默认使用单例模式来管理Bean
	    即同一个 Bean在应用程序的整个生命周期中只被创建一次
		而三级缓存机制可以确保单例模式的正确实现。

三、提高Spring 的性能:
     使用缓存可以提高Spring性能
	  由于使用缓存可避免重复创建Bean实例

四、解决AOP代理对象和目标对象名称冲突问题:
    在使用 AOP 的时候,
      如果将目标对象和代理对象都缓存在 singletonObjects 缓存中,
       就可能会出现两个对象名称相同的问题,这可能会导致一些奇怪的问题出现,比如说无法注入正确的对象。
       因此Spring 引入singletonFactories 缓存来解决这个问题。

Spring 三级缓存的实现原理

在 Spring 中,Bean 的创建过程可以分为以下几个阶段:

解析 BeanDefinition:读取配置文件或者注解等方式,将 BeanDefinition 解析成对象。

创建 Bean 实例:根据 BeanDefinition 中的信息,创建 Bean 实例,并进行属性注入和初始化等操作。

将 Bean 实例放入缓存:将创建好的 Bean 实例放入 Spring 的缓存中,以供后续使用。

在这个过程中,Spring 的三级缓存机制就发挥了重要的作用。下面我们来分别介绍三级缓存的作用和实现原理。
2.1 singletonObjects 缓存
singletonObjects 缓存是 Spring 中最常用的一个缓存
   用于存储已经创建好的 Bean 实例
    这个缓存是一个 ConcurrentHashMap 类型的对象
	 它将 Bean 的名称作为 key,将 Bean 实例作为 value。
    在使用 singletonObjects 缓存时,
	Spring 首先会从缓存中尝试获取 Bean 实例。
	 如果缓存中不存在对应的 Bean 实例,那么就会继续执行创建 Bean 实例的操作。
	 在创建 Bean 实例的过程中,如果发现当前 Bean 已经被创建了,则会从 singletonObjects 缓存中获取该 Bean 实例并返回。
    在默认情况下,singletonObjects 缓存的存储策略是“早期曝光”。也就是说,当 Bean 实例被创建后,
	就会被立即放入 singletonObjects 缓存中。这样可以确保在创建 Bean 实例时就能够获取到该实例的引用,避免了出现循环依赖问题。

2.2 earlySingletonObjects 缓存
    earlySingletonObjects 缓存是 Spring 中比较少用到的一个缓存
	  它的作用是存储“早期曝光”的 Bean 实例
	   也就是在创建 Bean 实例时尚未完成依赖注入的 Bean 实例。
    在创建 Bean 实例的过程中,
	 如果发现该 Bean 依赖于另外一个还未创建完成的 Bean,
	 那么就会将当前 Bean 实例放入 earlySingletonObjects 缓存中。
	 等到该依赖的 Bean 实例创建完成后,Spring 就会将 earlySingletonObjects 缓存中的 Bean 实例进行依赖注入,
	 并将其移动到 singletonObjects 缓存中。

2.3 singletonFactories 缓存
    singletonFactories 缓存是 Spring 中专门为解决 AOP 代理对象和目标对象名称冲突问题而设计的缓存。
	   在使用 AOP 的时候,
	     如果将目标对象和代理对象都缓存在 singletonObjects 缓存中,
		   就可能会出现两个对象名称相同的问题,这可能会导致一些奇怪的问题出现
		     如说无法注入正确的对象。
    为解决这个问题,Spring 引入了 singletonFactories 缓存。
	在创建代理对象时,Spring 首先会创建一个 ObjectFactory 对象,
	并将其放入 singletonFactories 缓存中。等到需要使用代理对象时,
	Spring 就会调用 ObjectFactory 的 getObject() 方法来创建代理对象,并将其放入 singletonObjects 缓存中。
例:
三级缓存示例

User 的 Bean,它依赖于另一个名为 Role 的 Bean。此时,Spring 的 Bean 创建过程可以分为以下几个阶段:
解析 User 和 Role 的 BeanDefinition,将其解析为对象。
创建 Role Bean 实例,并放入 singletonObjects 缓存中。
创建 User Bean 实例,发现它依赖于 Role Bean,将 User 实例放入 earlySingletonObjects 缓存中。
创建 Role Bean 实例的代理对象,并将代理对象
放入 singletonObjects 缓存中。
将 Role Bean 实例注入到 User Bean 实例中。
将 User 实例从 earlySingletonObjects 缓存中移动到 singletonObjects 缓存中。
在这个过程中,三级缓存的作用可以概括为:
singletonObjects 缓存用于存储创建完成并已经进行了依赖注入的 Bean 实例。
earlySingletonObjects 缓存用于存储已经创建但尚未进行依赖注入的 Bean 实例。
singletonFactories 缓存用于存储 AOP 代理对象和目标对象名称相同时的代理工厂对象。
三级缓存的使用示例代码如下:

@Component
public class User {
 
    @Autowired
    private Role role;

    //省略其他代码
}
}



@Component
public class Role {

    // 省略其他代码
}
}



@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {

    @Bean
    public Role role() {
 
        return new Role();
 
    }

    @Bean
    public User user() {
        return new User();
    }

    @Bean
    public RoleInterceptor roleInterceptor() {
 
        return new RoleInterceptor();
 
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator(); 
    }



    @Bean
    public ProxyFactoryBean roleProxy() {
 
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
 
        proxyFactoryBean.setTarget(role());
 
        proxyFactoryBean.addAdvice(roleInterceptor());
 
        return proxyFactoryBean;
 
    }
}
}



public class RoleInterceptor implements MethodInterceptor {
 
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
 
        System.out.println("before");
 
        Object result = invocation.proceed();
 
        System.out.println("after");
 
        return result;
 
    }
}
}



public class Main {
 
    public static void main(String[] args) {
 
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
 
        User user = context.getBean(User.class);
 
    }
}
}
以上示例代码,
  创建一个 User Bean,它依赖于 Role Bean。
   我们还创建了一个 RoleInterceptor 来作为 Role Bean 的 AOP 拦截器,以及一个 Role Bean 的代理对象。

在这个例子中,如果我们将三级缓存的某一级去掉,就可能会导致 Bean 创建失败或者出现一些奇怪的问题

比如说:
  如果没有 earlySingletonObjects 缓存,就可能会出现循环依赖问题,导致 Bean 创建失败。
 如果没有 singletonFactories 缓存,就可能会出现两个对象名称相同的问题,导致注入错误的对象或者无法注入对象。
 因此,Spring 的三级缓存机制可以很好地保证 Bean 的创建和依赖注入的正确性,同时也能够有效地避免一些奇怪的问题出现
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaFramework/Spring/202407/8156.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者