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

Spring?Bean創(chuàng)建流程分析講解

 更新時(shí)間:2023年01月04日 09:32:31   作者:程序員小潘  
很多時(shí)候我們需要根據(jù)不同的條件在容器中加載不同的Bean,或者根據(jù)不同的條件來選擇是否在容器中加載某個(gè)Bean,這就是Bean的加載控制,一般我們可以通過編程式或注解式兩種不同的方式來完成Bean的管理

1. 前言

Spring提供了xml、注解、JavaConfig多種方式來配置bean,不論何種方式,Spring最終都會(huì)將bean封裝成BeanDefinition對(duì)象,Spring創(chuàng)建bean的依據(jù)也是通過BeanDefinition來完成的。

當(dāng)我們調(diào)用getBean()方法獲取bean實(shí)例時(shí),不管是單例bean還是原型bean,首次調(diào)用時(shí)容器內(nèi)都不存在可用的bean實(shí)例,這時(shí)就不得不去創(chuàng)建bean了,我們分析下Spring創(chuàng)建bean的過程。

2. Bean創(chuàng)建概覽

Spring Bean的創(chuàng)建過程是非常復(fù)雜的,但是整體流程又是清晰的。創(chuàng)建bean的入口函數(shù)在AbstractAutowireCapableBeanFactory#createBean(),Spring首先會(huì)觸發(fā)一個(gè)擴(kuò)展點(diǎn)InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(),如果擴(kuò)展點(diǎn)返回了可用的bean,這里會(huì)進(jìn)行短路操作,Spring將不再去實(shí)例化目標(biāo)bean,這樣做的好處是,擴(kuò)展點(diǎn)可以在這里返回一個(gè)代理對(duì)象去避免目標(biāo)bean被實(shí)例化。

如果擴(kuò)展點(diǎn)沒有返回可用的bean對(duì)象,Spring會(huì)自己去實(shí)例化bean,實(shí)例化bean的方式有三種,取決于BeanDefinition的配置。Bean實(shí)例化完了之后,Spring會(huì)通過擴(kuò)展點(diǎn)的方式來收集Bean的注解屬性和方法,比如:@Autowired、@Value、init-method等等,信息收集完畢會(huì)通過populateBean()方法對(duì)bean進(jìn)行屬性填充,其實(shí)就是注入依賴。屬性填充完畢,緊接著會(huì)對(duì)bean進(jìn)行初始化,觸發(fā)bean實(shí)現(xiàn)的各種Aware接口,生命周期方法,以及BeanPostProcessor擴(kuò)展點(diǎn)。

以上執(zhí)行完畢后,此時(shí)的bean就已經(jīng)是一個(gè)可用的bean了,可以直接返回了。但是,bean可能還會(huì)有destroy-method方法,需要在bean銷毀時(shí)被調(diào)用,所以最后還需要把這一類bean暫存到Map容器中,以便銷毀時(shí)觸發(fā)。

3. InstantiationAwareBeanPostProcessor

根據(jù)beanName創(chuàng)建bean,首先需要知道bean對(duì)應(yīng)的class。解析class有2種方式,如果mbd存在BeanClass就直接用,否則根據(jù)BeanClassName加載class。

/**
* 解析BeanClass
* 1.存在BeanClass
* 2.根據(jù)BeanClassName加載Class
*/
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

緊接著準(zhǔn)備MethodOverrides,因?yàn)镾pring支持lookup-methodreplace-method功能,針對(duì)這兩類方法Spring統(tǒng)一保存在MethodOverrides里面,如果bean存在MethodOverrides,則需要?jiǎng)?chuàng)建代理對(duì)象來增強(qiáng)。

這里的準(zhǔn)備階段,其實(shí)是解析MethodOverride是否存在重載方法,如果不存在重載方法,會(huì)將overloaded設(shè)為false,增強(qiáng)調(diào)用時(shí)就不用再根據(jù)參數(shù)類型去判斷該調(diào)用哪個(gè)重載方法了。

/**
 * 準(zhǔn)備重寫方法,解析是否有重載方法
 * 1.lookup-method
 * 2.replace-method
 * 如果存在MethodOverride,則創(chuàng)建代理對(duì)象
 */
try {
    mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException ex) {
    throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
}

然后Spring觸發(fā)擴(kuò)展點(diǎn)InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(),如果擴(kuò)展點(diǎn)返回了可用的bean,Spring將不再對(duì)目標(biāo)bean進(jìn)行實(shí)例化。這里你可以返回一個(gè)代理對(duì)象,然后自己決定什么時(shí)候?qū)嵗繕?biāo)bean。

try {
    /**
     * 觸發(fā)InstantiationAwareBeanPostProcessor擴(kuò)展
     * 允許它返回代理對(duì)象,來避免目標(biāo)Bean實(shí)例化
     * @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(java.lang.Class, java.lang.String)
     */
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        /**
         * 如果InstantiationAwareBeanPostProcessor返回了代理對(duì)象,則不再實(shí)例化目標(biāo)Bean,短路操作
         */
        return bean;
    }
} catch (Throwable ex) {
    throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
}

resolveBeforeInstantiation()其實(shí)就是從容器中取出所有的InstantiationAwareBeanPostProcessor實(shí)現(xiàn)類,然后依次調(diào)用postProcessBeforeInstantiation()方法。如果擴(kuò)展點(diǎn)返回了bean對(duì)象,緊接著會(huì)馬上觸發(fā)postProcessAfterInitialization()方法,跳過目標(biāo)bean的實(shí)例化。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 應(yīng)用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation處理器
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    /**
                     * 如果擴(kuò)展點(diǎn)返回了可用bean,不再實(shí)例化目標(biāo)bean,緊接著應(yīng)用after處理器
                     * 應(yīng)用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation處理器
                     */
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

4. createBeanInstance

如果InstantiationAwareBeanPostProcessor擴(kuò)展點(diǎn)沒有返回可用bean,Spring會(huì)對(duì)目標(biāo)bean實(shí)例化,緊接著調(diào)用doCreateBean()方法。

實(shí)例化bean的方法是AbstractAutowireCapableBeanFactory#createBeanInstance(),實(shí)例化bean的方式有三種:

  • 如果RootBeanDefinition提供了instanceSupplier方法,則直接調(diào)用instanceSupplier方法來生成bean對(duì)象,避免反射實(shí)例化bean的性能消耗。
  • 如果是@Bean方法聲明的bean,Spring會(huì)從容器中找到factoryBeanName對(duì)應(yīng)的工廠bean,然后反射調(diào)用factoryMethodName來創(chuàng)建bean。
  • 通過構(gòu)造函數(shù)實(shí)例化。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    /**
     * 如果是@Bean方法聲明的bean,則調(diào)用工廠方法來生成bean
     * 從容器中取出factoryBean,反射調(diào)用@Bean方法生成bean
     */
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            /*
                一個(gè)類有多個(gè)構(gòu)造函數(shù),每個(gè)構(gòu)造函數(shù)都有不同的參數(shù),
                所以需要根據(jù)參數(shù)鎖定構(gòu)造函數(shù)并進(jìn)行初始化
             */
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    // 如果已經(jīng)解析過則使用解析好的構(gòu)造函數(shù) , 不需要再次鎖定
    if (resolved) {
        if (autowireNecessary) {
            // 構(gòu)造函數(shù)注入
            return autowireConstructor(beanName, mbd, null, null);
        } else {
            // 無參構(gòu)造函數(shù)
            return instantiateBean(beanName, mbd);
        }
    }
    // 根據(jù)參數(shù)解析構(gòu)造函數(shù)
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        //構(gòu)造函數(shù)自動(dòng)注入
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }
    // 無需特殊處理:只需使用無參構(gòu)造函數(shù)。
    return instantiateBean(beanName, mbd);
}

5. MergedBeanDefinitionPostProcessor

通過**createBeanInstance()**方法實(shí)例化的bean只是一個(gè)不可用的bean對(duì)象,因?yàn)檫@個(gè)時(shí)候bean的屬性還沒有填充,依賴也沒有注入,初始化方法也沒有被調(diào)用,后置處理器也還沒有執(zhí)行。

緊接著,Spring會(huì)對(duì)bean做一些信息收集,收集的信息包括@Autowired、@Value、@Resource等注解,init-method、destroy-method方法等,將這些信息封裝成Member對(duì)象,存放到RootBeanDefinition的externallyManagedConfigMembers屬性里。

收集工作是通過擴(kuò)展點(diǎn)MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition()進(jìn)行的,Spring內(nèi)置了多個(gè)實(shí)現(xiàn)類來收集信息,通過名字基本就能看出來它們要收集哪些信息。

  • CommonAnnotationBeanPostProcessor
  • AutowiredAnnotationBeanPostProcessor
  • InitDestroyAnnotationBeanPostProcessor
synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
        try {
            /**
             * 觸發(fā)擴(kuò)展點(diǎn)
             * 解析bean的 @Autowired @Value @Resource注解
             * init destory-method方法
             * 存放到BD的externallyManagedConfigMembers中
             * @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Class, java.lang.String)
             */
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        } catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Post-processing of merged bean definition failed", ex);
        }
        mbd.postProcessed = true;
    }
}

6. SmartInstantiationAwareBeanPostProcessor

Bean的信息收集完畢,還有一個(gè)問題需要解決。Spring是允許Bean之間存在循環(huán)依賴的,比如BeanA有一個(gè)屬性BeanB,BeanB也有一個(gè)屬性BeanA,兩者互相依賴對(duì)方。Spring創(chuàng)建BeanA時(shí)發(fā)現(xiàn)它依賴BeanB,就會(huì)去創(chuàng)建BeanB,創(chuàng)建BeanB時(shí)又發(fā)現(xiàn)它依賴BeanA,此時(shí)又會(huì)去創(chuàng)建BeanA,循環(huán)依賴就此產(chǎn)生。為了打破這個(gè)死循環(huán),Spring的解決方案是,不等BeanA完全創(chuàng)建好,就提前暴露到緩存中,這樣在創(chuàng)建BeanB時(shí)就可以直接依賴這個(gè)半成品BeanA了,循環(huán)就此打破。

如果允許提前暴露 bean,那么Spring還會(huì)觸發(fā)一個(gè)擴(kuò)展點(diǎn)SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()來獲得提前暴露 bean的引用,默認(rèn)是直接原樣返回bean。

/**
 * 這個(gè)時(shí)候bean還沒初始化,是否要提前暴露 Bean?以便循環(huán)依賴
 * 條件:單例 & 允許循環(huán)依賴 & bean正在創(chuàng)建中
 */
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    /**
     * 加入到singletonFactories
     */
    addSingletonFactory(beanName,
            /**
             * 獲取提前暴露 Bean的引用,默認(rèn)原樣返回bean
             * 觸發(fā)擴(kuò)展點(diǎn),AOP在這里將advice織入bean中
             * @see SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(java.lang.Object, java.lang.String)
             */
            () -> getEarlyBeanReference(beanName, mbd, bean));
}

7. populateBean

bean實(shí)例生成了,bean的信息也收集完畢了,接下來就是對(duì)bean進(jìn)行屬性填充了,方法是populateBean()。

Spring此時(shí)又會(huì)觸發(fā)一個(gè)擴(kuò)展點(diǎn)InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(),返回值代表是否要繼續(xù)填充bean,默認(rèn)返回true。

/**
 * 觸發(fā)擴(kuò)展點(diǎn),返回值代表是否要繼續(xù)填充bean
 * @see InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(java.lang.Object, java.lang.String)
 */
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                continueWithPropertyPopulation = false;
                break;
            }
        }
    }
}
if (!continueWithPropertyPopulation) {
    return;
}

如果需要繼續(xù)填充bean,則通過InstantiationAwareBeanPostProcessor#postProcessProperties()擴(kuò)展點(diǎn)來完成的bean的填充。執(zhí)行完這一步,Bean的屬性會(huì)完成填充,依賴也會(huì)被注入。

/**
 * 觸發(fā)擴(kuò)展點(diǎn),這里會(huì)注入@Autowired、@Resource、@Value等屬性
 * @see InstantiationAwareBeanPostProcessor#postProcessProperties(org.springframework.beans.PropertyValues, java.lang.Object, java.lang.String) InstantiationAwareBeanPostProcessor#postProcessProperties(org.springframework.beans.PropertyValues, java.lang.Object, java.lang.String)
 * @see InstantiationAwareBeanPostProcessor#postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String)
 */
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
    if (pvs == null) {
        pvs = mbd.getPropertyValues();
    }
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                if (filteredPds == null) {
                    filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }
                // 對(duì)所有需要依賴檢查的屬性進(jìn)行后處理
                pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
            }
            pvs = pvsToUse;
        }
    }
}

8. initializeBean

屬性填充,依賴注入完,接下來就是bean的初始化。

首先會(huì)調(diào)用invokeAwareMethods()方法來觸發(fā)Bean實(shí)現(xiàn)的各類Aware接口。

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

然后觸發(fā)擴(kuò)展點(diǎn)BeanPostProcessor#postProcessBeforeInitialization()。

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
    /**
     * 觸發(fā)擴(kuò)展點(diǎn)
     * @see BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
     */
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

如果bean實(shí)現(xiàn)了InitializingBean接口,Spring緊接著會(huì)觸發(fā)InitializingBean#afterPropertiesSet()擴(kuò)展點(diǎn),再執(zhí)行init-method。

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {
        //判斷該bean 如果實(shí)現(xiàn)了InitializingBean接口,則調(diào)用bean的afterPropertiesSet方法
        boolean isInitializingBean = (bean instanceof InitializingBean);
        // 執(zhí)行afterPropertiesSet方法
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                } catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            } else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
        // 執(zhí)行initMethod方法
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            //判斷是否指定了init-method方法,如果指定了init-method方法,則再調(diào)用制定的init-method
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                //調(diào)用init-method方法中指定的方法, 是通過反射實(shí)現(xiàn)
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

initMethods執(zhí)行完畢,接著觸發(fā)BeanPostProcessor#postProcessAfterInitialization()擴(kuò)展點(diǎn)對(duì)bean做最后的擴(kuò)展。

if (mbd == null || !mbd.isSynthetic()) {
    /**
     * 觸發(fā)擴(kuò)展點(diǎn)
     * @see BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
     */
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;

9. registerDisposableBean

到此為止,bean就創(chuàng)建完畢了,是一個(gè)完整的可用的bean了。最后一步,是判斷bean是否存在destroy-method,如果有還需要把bean注冊(cè)到Map容器中,以便bean銷毀時(shí)調(diào)用。

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
    if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
        if (mbd.isSingleton()) {
            registerDisposableBean(beanName,
                    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        } else {
            Scope scope = this.scopes.get(mbd.getScope());
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
            }
            scope.registerDestructionCallback(beanName,
                    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
    }
}

到此這篇關(guān)于Spring Bean創(chuàng)建流程分析講解的文章就介紹到這了,更多相關(guān)Spring Bean創(chuàng)建內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Springboot actuator應(yīng)用后臺(tái)監(jiān)控實(shí)現(xiàn)

    Springboot actuator應(yīng)用后臺(tái)監(jiān)控實(shí)現(xiàn)

    這篇文章主要介紹了Springboot actuator應(yīng)用后臺(tái)監(jiān)控實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能實(shí)例

    Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能實(shí)例

    分頁功能是我們?nèi)粘i_發(fā)中經(jīng)常會(huì)遇到的,下面這篇文章主要給大家介紹了Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • JavaWeb Servlet生命周期細(xì)枝末節(jié)處深究

    JavaWeb Servlet生命周期細(xì)枝末節(jié)處深究

    Servlet指在服務(wù)器端執(zhí)行的一段Java代碼,可以接收用戶的請(qǐng)求和返回給用戶響應(yīng)結(jié)果,下面這篇文章主要給大家介紹了關(guān)于JavaWeb.servlet生命周期的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • FastJson對(duì)于JSON格式字符串、JSON對(duì)象及JavaBean之間的相互轉(zhuǎn)換操作

    FastJson對(duì)于JSON格式字符串、JSON對(duì)象及JavaBean之間的相互轉(zhuǎn)換操作

    這篇文章主要介紹了FastJson對(duì)于JSON格式字符串、JSON對(duì)象及JavaBean之間的相互轉(zhuǎn)換,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-11-11
  • Idea 同一窗口導(dǎo)入多個(gè)項(xiàng)目的實(shí)現(xiàn)步驟

    Idea 同一窗口導(dǎo)入多個(gè)項(xiàng)目的實(shí)現(xiàn)步驟

    本文主要介紹了Idea 同一窗口導(dǎo)入多個(gè)項(xiàng)目的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 淺析JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承

    淺析JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承

    這篇文章主要介紹了 JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • java實(shí)現(xiàn)登錄案例

    java實(shí)現(xiàn)登錄案例

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)登錄案例的相關(guān)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Spring?Boot中@Autowired注入為空的原因以及解決方法

    Spring?Boot中@Autowired注入為空的原因以及解決方法

    最近在開發(fā)中遇到了使用@Autowired注解自動(dòng)裝配時(shí)會(huì)報(bào)空指針,發(fā)現(xiàn)對(duì)象并沒有裝配進(jìn)來,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot中@Autowired注入為空的原因以及解決方法,需要的朋友可以參考下
    2024-01-01
  • java實(shí)現(xiàn)jdbc批量插入數(shù)據(jù)

    java實(shí)現(xiàn)jdbc批量插入數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)jdbc批量插入數(shù)據(jù),三種JDBC批量插入編程方法進(jìn)行比較,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Mybatis返回Map數(shù)據(jù)方式示例

    Mybatis返回Map數(shù)據(jù)方式示例

    這篇文章主要為大家介紹了Mybatis返回Map數(shù)據(jù)方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06

最新評(píng)論