當(dāng)我們?cè)谑褂?Spring 框架時(shí),通常會(huì)遇到循環(huán)依賴、AOP 代理等問題。為了解決這些問題,Spring 引入了三級(jí)緩存機(jī)制,
即 singletonObjects、earlySingletonObjects 和 singletonFactories 三個(gè)緩存。本文將詳細(xì)介紹 Spring 三級(jí)緩存的原理和作用。
1. Spring 三級(jí)緩存的作用
在 Spring 框架中,Bean 實(shí)例化和依賴注入是非常重要的步驟。在這個(gè)過程中,循環(huán)依賴和 AOP 代理是兩個(gè)比較常見的問題,而三級(jí)緩存機(jī)制就是為了解決這些問題而設(shè)計(jì)的。
具體來說,Spring 的三級(jí)緩存的作用如下:
解決循環(huán)依賴問題:當(dāng)一個(gè) Bean 的創(chuàng)建依賴于其他 Bean 的創(chuàng)建時(shí),就可能會(huì)出現(xiàn)循環(huán)依賴的問題。Spring 的三級(jí)緩存機(jī)制可以通過代理對(duì)象的方式來解決循環(huán)依賴問題。
確保單例模式:Spring 默認(rèn)使用單例模式來管理 Bean,即同一個(gè) Bean 在應(yīng)用程序的整個(gè)生命周期中只被創(chuàng)建一次。而三級(jí)緩存機(jī)制可以確保單例模式的正確實(shí)現(xiàn)。
提高 Spring 的性能:使用緩存可以提高 Spring 的性能,因?yàn)榫彺婵梢员苊庵貜?fù)創(chuàng)建 Bean 實(shí)例的開銷。
解決 AOP 代理對(duì)象和目標(biāo)對(duì)象名稱沖突問題:在使用 AOP 的時(shí)候,如果將目標(biāo)對(duì)象和代理對(duì)象都緩存在 singletonObjects 緩存中,就可能會(huì)出現(xiàn)兩個(gè)對(duì)象名稱相同的問題,這可能會(huì)導(dǎo)致一些奇怪的問題出現(xiàn),比如說無法注入正確的對(duì)象。因此,Spring 引入了 singletonFactories 緩存來解決這個(gè)問題。
2. Spring 三級(jí)緩存的實(shí)現(xiàn)原理
在 Spring 中,Bean 的創(chuàng)建過程可以分為以下幾個(gè)階段:
解析 BeanDefinition:讀取配置文件或者注解等方式,將 BeanDefinition 解析成對(duì)象。
創(chuàng)建 Bean 實(shí)例:根據(jù) BeanDefinition 中的信息,創(chuàng)建 Bean 實(shí)例,并進(jìn)行屬性注入和初始化等操作。
將 Bean 實(shí)例放入緩存:將創(chuàng)建好的 Bean 實(shí)例放入 Spring 的緩存中,以供后續(xù)使用。
在這個(gè)過程中,Spring 的三級(jí)緩存機(jī)制就發(fā)揮了重要的作用。下面我們來分別介紹三級(jí)緩存的作用和實(shí)現(xiàn)原理。
2.1 singletonObjects 緩存
singletonObjects 緩存是 Spring 中最常用的一個(gè)緩存,用于存儲(chǔ)已經(jīng)創(chuàng)建好的 Bean 實(shí)例。這個(gè)緩存是一個(gè) ConcurrentHashMap 類型的對(duì)象,它將 Bean 的名稱作為 key,將 Bean 實(shí)例作為 value。
在使用 singletonObjects 緩存時(shí)
,在使用 singletonObjects 緩存時(shí),Spring 首先會(huì)從緩存中嘗試獲取 Bean 實(shí)例。如果緩存中不存在對(duì)應(yīng)的 Bean 實(shí)例,那么就會(huì)繼續(xù)執(zhí)行創(chuàng)建 Bean 實(shí)例的操作。在創(chuàng)建 Bean 實(shí)例的過程中,如果發(fā)現(xiàn)當(dāng)前 Bean 已經(jīng)被創(chuàng)建了,則會(huì)從 singletonObjects 緩存中獲取該 Bean 實(shí)例并返回。
在默認(rèn)情況下,singletonObjects 緩存的存儲(chǔ)策略是“早期曝光”。也就是說,當(dāng) Bean 實(shí)例被創(chuàng)建后,就會(huì)被立即放入 singletonObjects 緩存中。這樣可以確保在創(chuàng)建 Bean 實(shí)例時(shí)就能夠獲取到該實(shí)例的引用,避免了出現(xiàn)循環(huán)依賴問題。
2.2 earlySingletonObjects 緩存
earlySingletonObjects 緩存是 Spring 中比較少用到的一個(gè)緩存。它的作用是存儲(chǔ)“早期曝光”的 Bean 實(shí)例,也就是在創(chuàng)建 Bean 實(shí)例時(shí)尚未完成依賴注入的 Bean 實(shí)例。
在創(chuàng)建 Bean 實(shí)例的過程中,如果發(fā)現(xiàn)該 Bean 依賴于另外一個(gè)還未創(chuàng)建完成的 Bean,那么就會(huì)將當(dāng)前 Bean 實(shí)例放入 earlySingletonObjects 緩存中。等到該依賴的 Bean 實(shí)例創(chuàng)建完成后,Spring 就會(huì)將 earlySingletonObjects 緩存中的 Bean 實(shí)例進(jìn)行依賴注入,并將其移動(dòng)到 singletonObjects 緩存中。
2.3 singletonFactories 緩存
singletonFactories 緩存是 Spring 中專門為解決 AOP 代理對(duì)象和目標(biāo)對(duì)象名稱沖突問題而設(shè)計(jì)的緩存。在使用 AOP 的時(shí)候,如果將目標(biāo)對(duì)象和代理對(duì)象都緩存在 singletonObjects 緩存中,就可能會(huì)出現(xiàn)兩個(gè)對(duì)象名稱相同的問題,這可能會(huì)導(dǎo)致一些奇怪的問題出現(xiàn),比如說無法注入正確的對(duì)象。
為了解決這個(gè)問題,Spring 引入了 singletonFactories 緩存。在創(chuàng)建代理對(duì)象時(shí),Spring 首先會(huì)創(chuàng)建一個(gè) ObjectFactory 對(duì)象,并將其放入 singletonFactories 緩存中。等到需要使用代理對(duì)象時(shí),Spring 就會(huì)調(diào)用 ObjectFactory 的 getObject() 方法來創(chuàng)建代理對(duì)象,并將其放入 singletonObjects 緩存中。
3. 三級(jí)緩存的使用示例
為了更好地理解 Spring 的三級(jí)緩存機(jī)制,下面我們來看一個(gè)簡(jiǎn)單的示例。
假設(shè)我們有一個(gè)名為 User 的 Bean,它依賴于另一個(gè)名為 Role 的 Bean。此時(shí),Spring 的 Bean 創(chuàng)建過程可以分為以下幾個(gè)階段:
解析 User 和 Role 的 BeanDefinition,將其解析為對(duì)象。
創(chuàng)建 Role Bean 實(shí)例,并放入 singletonObjects 緩存中。
創(chuàng)建 User Bean 實(shí)例,發(fā)現(xiàn)它依賴于 Role Bean,將 User 實(shí)例放入 earlySingletonObjects 緩存中。
創(chuàng)建 Role Bean 實(shí)例的代理對(duì)象,并將代理對(duì)象
放入 singletonObjects 緩存中。
將 Role Bean 實(shí)例注入到 User Bean 實(shí)例中。
將 User 實(shí)例從 earlySingletonObjects 緩存中移動(dòng)到 singletonObjects 緩存中。
在這個(gè)過程中,三級(jí)緩存的作用可以概括為:
singletonObjects 緩存用于存儲(chǔ)創(chuàng)建完成并已經(jīng)進(jìn)行了依賴注入的 Bean 實(shí)例。
earlySingletonObjects 緩存用于存儲(chǔ)已經(jīng)創(chuàng)建但尚未進(jìn)行依賴注入的 Bean 實(shí)例。
singletonFactories 緩存用于存儲(chǔ) AOP 代理對(duì)象和目標(biāo)對(duì)象名稱相同時(shí)的代理工廠對(duì)象。
三級(jí)緩存的使用示例代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-440206.html
@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);
}
}
}
在上面的代碼中,我們創(chuàng)建了一個(gè) User Bean,它依賴于 Role Bean。我們還創(chuàng)建了一個(gè) RoleInterceptor 來作為 Role Bean 的 AOP 攔截器,以及一個(gè) Role Bean 的代理對(duì)象。
在這個(gè)例子中,如果我們將三級(jí)緩存的某一級(jí)去掉,就可能會(huì)導(dǎo)致 Bean 創(chuàng)建失敗或者出現(xiàn)一些奇怪的問題,比如說:
如果沒有 earlySingletonObjects 緩存,就可能會(huì)出現(xiàn)循環(huán)依賴問題,導(dǎo)致 Bean 創(chuàng)建失敗。
如果沒有 singletonFactories 緩存,就可能會(huì)出現(xiàn)兩個(gè)對(duì)象名稱相同的問題,導(dǎo)致注入錯(cuò)誤的對(duì)象或者無法注入對(duì)象。
因此,Spring 的三級(jí)緩存機(jī)制可以很好地保證 Bean 的創(chuàng)建和依賴注入的正確性,同時(shí)也能夠有效地避免一些奇怪的問題出現(xiàn)。文章來源地址http://www.zghlxwxcb.cn/news/detail-440206.html
到了這里,關(guān)于spring bean的三級(jí)緩存原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!