欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot預(yù)加載與懶加載實(shí)現(xiàn)方法超詳細(xì)講解

 更新時(shí)間:2022年11月17日 17:03:17   作者:氵奄不死的魚(yú)  
Spring一直被詬病啟動(dòng)時(shí)間慢,可Spring/SpringBoot是輕量級(jí)的框架。因?yàn)楫?dāng)Spring項(xiàng)目越來(lái)越大的時(shí)候,在啟動(dòng)時(shí)加載和初始化Bean就會(huì)變得越來(lái)越慢,很多時(shí)候我們?cè)趩?dòng)時(shí)并不需要加載全部的Bean,在調(diào)用時(shí)再加載就行,那這就需要預(yù)加載與懶加載的功能了

預(yù)加載

bean在springBoot啟動(dòng)過(guò)程中就完成創(chuàng)建加載

在AbstractApplicationContext的refresh方法中

		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }
        //所有要進(jìn)行初始的Bean
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
        // 對(duì)所有Bean進(jìn)行初始化,除了懶加載
        for (String beanName : beanNames) {
            // 去合并Bean
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //非抽象、單例、懶加載才會(huì)進(jìn)行注冊(cè)
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //判斷是不是 FactoryBean,簡(jiǎn)單說(shuō)是我們這個(gè) Bean 實(shí)現(xiàn)了
                if (isFactoryBean(beanName)) {
                    // 是不是 FactoryBean,獲取 FactoryBean 的方式就是  前綴+beanName
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    // 判斷是否 FactoryBean
                    if (bean instanceof FactoryBean) {
                        // 強(qiáng)轉(zhuǎn)
                        FactoryBean<?> factory = (FactoryBean<?>) bean;
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged(
                                    (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                                    getAccessControlContext());
                        } else {
                            // 判斷 是不是 這個(gè)類(lèi)的,如果是就去創(chuàng)建 SmartFactoryBean 屬于 FactoryBean 子接口,擁有更加細(xì)粒度操作原數(shù)據(jù)的方式,
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);
                        }
                    }
                } else {
                    //獲取具體的Bean
                    getBean(beanName);
                }
            }
        }
        // Trigger post-initialization callback for all applicable beans...
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            // 執(zhí)行所有 單例Bean 的回調(diào),當(dāng)然Bean 需要實(shí)現(xiàn)這個(gè)接口~~~
            if (singletonInstance instanceof SmartInitializingSingleton) {
                SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }, getAccessControlContext());
                } else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

getMergedLocalBeanDefinition

這里是去合并Bean去了,這里其實(shí)有兩個(gè)動(dòng)作

將取出來(lái)的 BeanDefinition 進(jìn)行合并

將BeanDefinition 轉(zhuǎn)換成 RottBeanDefinition 也就說(shuō)頂級(jí)的 Bean ,此處的頂級(jí)Bean 指的就是User extends SuperUser,可以認(rèn)為是是 User,也可以認(rèn)為是 SuperUser,如果是 User 就代表了已經(jīng)進(jìn)行了合并,如果 SuperUser 由于其本身就是頂級(jí)類(lèi),所以不需要合并,這里會(huì)排除掉 Object

需要注意的是第一次 從 mergedBeanDefinitions 是從 當(dāng)前的 BeanFactory 中查找

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    //從當(dāng)前 BeanFactory 中的緩存中獲取
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    // 不是NUll 并且  沒(méi)有過(guò)期的話,如果過(guò)期了或者修改了 會(huì)重新去查找
    if (mbd != null && !mbd.stale) {
        //返回當(dāng)前的
        return mbd;
    }
    // 先去 beanDefinitionMap 中去獲取
    BeanDefinition thisBeanDefinition=   getBeanDefinition(beanName);
    // 緩存中未找到,就到 BeanFactory 中尋找
    return getMergedBeanDefinition(beanName, thisBeanDefinition);
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
    throws BeanDefinitionStoreException {
    //傳遞Name 和BeanDefinition
    return getMergedBeanDefinition(beanName, bd, null);
}

具體的邏輯

    protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
            throws BeanDefinitionStoreException {
        // 將 mergedBeanDefinitions 防止線程安全,為什么?
        // 雖然 ConcurrentHashMap 是線程安全的,但是下面的業(yè)務(wù)并不一定是線程安全的,所以要加鎖
        synchronized (this.mergedBeanDefinitions) {
            RootBeanDefinition mbd = null;
            RootBeanDefinition previous = null;
            // 這里為空,代表的是 當(dāng)前的 BeanDefinition 是頂層的 Bean 不存在 嵌套Bean
            if (containingBd == null) {
                // 獲取當(dāng)前Bean,為什么又一次獲取了呢?因?yàn)槿绻诙嗑€程操作下 可能 這個(gè)Bean已經(jīng)被修改了,所以重新獲取一次
                mbd = this.mergedBeanDefinitions.get(beanName);
            }
            //如果緩存中沒(méi)有,或者過(guò)期了,則會(huì)重新創(chuàng)建一個(gè)
            if (mbd == null || mbd.stale) {
                previous = mbd;
                //如果 父 parentName 為空
                if (bd.getParentName() == null) {
                    // 如果當(dāng)前類(lèi)型就是 RootBeanDefinition
                    if (bd instanceof RootBeanDefinition) {
                        // 進(jìn)行克隆~~~
                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                    } else {
                        // 如果不是就會(huì)將 其他 BeanDefinition 轉(zhuǎn)換成 RootBeanDefinition 代表的是當(dāng)前 BeanDefinition 為頂級(jí) Bean
                        mbd = new RootBeanDefinition(bd);
                    }
                }
                //  如果父 BeanDefinition 不為 空,也就代表了 當(dāng)前類(lèi)存在繼承,如果不理解這段的話,可以看一下<bean parent=""> bean標(biāo)簽中的 paretn 屬性,
                else {
                    // 子bean定義:需要與父bean合并。
                    BeanDefinition pbd;
                    try {
                        String parentBeanName = transformedBeanName(bd.getParentName());
                        // 當(dāng)前的 BeanName 不是 parentBeanName,會(huì)去獲取 父BeanDefinition,否則則會(huì)去父工廠去獲取
                        if (!beanName.equals(parentBeanName)) {
                            // 獲取 parent BeanDefinition這里會(huì)進(jìn)行一個(gè)遞歸操作,
                            pbd = getMergedBeanDefinition(parentBeanName);
                        } else {
                            // 如果當(dāng)前的BeanName 和傳遞的 parentName 一模一樣 則會(huì)去父 ParentBeanFactory 查找
                            BeanFactory parent = getParentBeanFactory();
                            // 如果當(dāng)前是層次 BeanFactory 轉(zhuǎn)換查找,如果不是 拋出異常
                            if (parent instanceof ConfigurableBeanFactory) {
                                pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                            } else {
                                throw new NoSuchBeanDefinitionException(parentBeanName,
                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                                "': cannot be resolved without a ConfigurableBeanFactory parent");
                            }
                        }
                    } catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                    }
                    // 進(jìn)行合并
                    // 進(jìn)行合并,這里的合并是指將 父級(jí)的Bean 合并到子 中,例如  user extends superUser
                    // 也就說(shuō)講 super中的 屬性 合并到 user 中
                    // Deep copy with overridden values.
                    mbd = new RootBeanDefinition(pbd);
                    mbd.overrideFrom(bd);
                }
                //設(shè)置成單例,如果之前沒(méi)設(shè)置的話~~~~
                if (!StringUtils.hasLength(mbd.getScope())) {
                    // 默認(rèn)為單例
                    mbd.setScope(SCOPE_SINGLETON);
                }
                // A bean contained in a non-singleton bean cannot be a singleton itself.
                // Let's correct this on the fly here, since this might be the result of
                // parent-child merging for the outer bean, in which case the original inner bean
                // definition will not have inherited the merged outer bean's singleton status.
                if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                    mbd.setScope(containingBd.getScope());
                }
                // Cache the merged bean definition for the time being
                // (it might still get re-merged later on in order to pick up metadata changes)
                // 是否緩存Bean的元數(shù)據(jù)
                if (containingBd == null && isCacheBeanMetadata()) {
                    // 將當(dāng)前的 BeanDefinitions 放入到map中,進(jìn)行緩存
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }
            if (previous != null) {
                copyRelevantMergedBeanDefinitionCaches(previous, mbd);
            }
            return mbd;
        }
    }

總結(jié)這里的合并是指將 父級(jí)的Bean 合并到子 中,例如 user extends superUser

也就說(shuō)講 super中的 屬性 合并到 user 中,父類(lèi)的BeanDefinition會(huì)被子類(lèi)的BeanDefinition繼承。

循環(huán)創(chuàng)建bean

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->

對(duì)于非抽象,單例,非懶加載的bean分別調(diào)用getBean方法

getBean方法比較復(fù)雜,簡(jiǎn)單總結(jié)下就創(chuàng)建bean的對(duì)象并且創(chuàng)建bean依賴(lài)的對(duì)象并且注入到當(dāng)前bean完成對(duì)bean的初始化

懶加載

@Lazy

在類(lèi)上加上@Lazy標(biāo)簽,那么就開(kāi)啟了懶加載

@Service("helloServiceB")
@Lazy
public class HelloServiceB {
············

懶加載指的是,初始化時(shí)不會(huì)創(chuàng)建實(shí)例,在真正被使用到的時(shí)候再進(jìn)行加載。

看了前面的預(yù)加載可以知道,在preInstantiateSingletons方法中會(huì)跳過(guò)懶加載的bean。

如果懶加載的bean被依賴(lài)會(huì)怎么樣?

比如又有serviceA依賴(lài)了ServiceB

@Service("helloServiceA")
public class HelloServiceA implements HelloService {
    @Autowired
    private HelloService helloServiceB;

那么此時(shí)HelloServiceB懶加載會(huì)失效

HelloServiceA沒(méi)有@Lazy標(biāo)簽會(huì)在啟動(dòng)時(shí)預(yù)加載通過(guò)getBean方法創(chuàng)建。同時(shí)會(huì)注入其依賴(lài)的bean。serviceB也會(huì)被創(chuàng)建。

因此要使懶加載生效,應(yīng)該在HelloServiceA也加@Lazy注解

全局懶加載

一般情況程序在啟動(dòng)時(shí)時(shí)有大量的 Bean 需要初始化,例如 數(shù)據(jù)源初始化、緩存初始化等導(dǎo)致應(yīng)用程序啟動(dòng)非常的慢。在 spring boot 2.2 之前的版本,我們對(duì)這些 bean 使用手動(dòng)增加 @Lazy 注解,來(lái)實(shí)現(xiàn)啟動(dòng)時(shí)不初始化,業(yè)務(wù)程序在調(diào)用需要時(shí)再去初始化,如上代碼修改為即可:

為什么需要全局懶加載

同上文中提到我們需要手動(dòng)在 bean 增加 @Lazy 注解,這就意味著我們僅能對(duì)程序中自行實(shí)現(xiàn)的 bean 進(jìn)行添加。但是現(xiàn)在 spring boot 應(yīng)用中引入了很多第三方 starter ,比如 druid-spring-boot-starter 數(shù)據(jù)源注入、spring-boot-starter-data-redis 緩存等默認(rèn)情況下, 引入即注入了相關(guān) bean 我們無(wú)法去修改添加 @Lazy。

spring boot 2.2 新增全局懶加載屬性,開(kāi)啟后全局 bean 被設(shè)置為懶加載,需要時(shí)再去創(chuàng)建

spring:
  main:
    lazy-initialization: true

原理

在SpringApplication#prepareContext方法中

if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}

如果開(kāi)啟了lazy-initialization,那么添加LazyInitializationBeanFactoryPostProcessor

LazyInitializationBeanFactoryPostProcessor執(zhí)行,會(huì)將beanFactory中的bean設(shè)置lazyinit

public final class LazyInitializationBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		// Take care not to force the eager init of factory beans when getting filters
		Collection<LazyInitializationExcludeFilter> filters = beanFactory
				.getBeansOfType(LazyInitializationExcludeFilter.class, false, false).values();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
			if (beanDefinition instanceof AbstractBeanDefinition) {
				postProcess(beanFactory, filters, beanName, (AbstractBeanDefinition) beanDefinition);
			}
		}
	}
	private void postProcess(ConfigurableListableBeanFactory beanFactory,
			Collection<LazyInitializationExcludeFilter> filters, String beanName,
			AbstractBeanDefinition beanDefinition) {
		Boolean lazyInit = beanDefinition.getLazyInit();
		if (lazyInit != null) {
			return;
		}
		Class<?> beanType = getBeanType(beanFactory, beanName);
		if (!isExcluded(filters, beanName, beanDefinition, beanType)) {
			beanDefinition.setLazyInit(true);
		}
	}

對(duì)于全局懶加載

個(gè)別 bean 可以通過(guò)設(shè)置 @Lazy(false) 排除,設(shè)置為啟動(dòng)時(shí)加載

@Lazy(false)
@Configuration
public class DemoConfig {}

當(dāng)然也可以指定規(guī)則實(shí)現(xiàn) LazyInitializationExcludeFilter 規(guī)則實(shí)現(xiàn)排除

@Bean LazyInitializationExcludeFilter integrationLazyInitExcludeFilter() {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E--> return LazyInitializationExcludeFilter.forBeanTypes(DemoConfig.class); }

全局懶加載的好處與問(wèn)題

當(dāng)項(xiàng)目比較大時(shí)。開(kāi)發(fā)人員本地調(diào)試時(shí),并不需要使用到全部的bean,那么開(kāi)啟全局懶加載可以節(jié)省很多啟動(dòng)項(xiàng)目的時(shí)間

通過(guò)設(shè)置全局懶加載,我們可以減少啟動(dòng)時(shí)的創(chuàng)建任務(wù)從而大幅度的縮減應(yīng)用的啟動(dòng)時(shí)間。但全局懶加載的缺點(diǎn)可以歸納為以下兩點(diǎn):

  • Http 請(qǐng)求處理時(shí)間變長(zhǎng)。 這里準(zhǔn)確的來(lái)說(shuō)是第一次 http 請(qǐng)求處理的時(shí)間變長(zhǎng),之后的請(qǐng)求不受影響
  • 錯(cuò)誤不會(huì)在應(yīng)用啟動(dòng)時(shí)拋出,不利于早發(fā)現(xiàn)、早解決、早下班。

到此這篇關(guān)于SpringBoot預(yù)加載與懶加載實(shí)現(xiàn)方法超詳細(xì)講解的文章就介紹到這了,更多相關(guān)SpringBoot預(yù)加載與懶加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論