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

Sping中如何處理@Bean注解bean同名的問題

 更新時(shí)間:2023年06月20日 09:50:04   作者:Snowbae  
這篇文章主要介紹了Sping中如何處理@Bean注解bean同名的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

首先明確

@Bean注解的兩個(gè)方法返回對(duì)象是同一類型的時(shí)候,才會(huì)出現(xiàn)覆蓋問題,如果兩個(gè)bean不是同一個(gè)類型,直接就報(bào)錯(cuò)了。

所以下述的情況都是@Bean注解的方法返回的bean是同類型同名的bean,這樣才有討論的必要。

    @Bean("sim1")
    public Sim2 sim2(){
        Sim2 sim1 = new Sim2();
        return sim1;
    }
    @Bean("sim1")
    public Sim1 sim1(){
        Sim1 sim1 = new Sim1();
        return sim1;
    }

報(bào)錯(cuò):

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified 
bean name 'sim1' for bean class [springdemo.entity.sim.Sim1] conflicts with existing, non-compatible bean definition of same name and class [springdemo.entity.sim.Sim2]

@Bean注解的bean同名的兩種情況

  • @Bean注解的方法:方法名不同但是返回對(duì)象類型相同,@Bean注解中顯式指定相同的beanName
  • @Bean注解:不同的重載方法,且bean同名

情況一

@Bean注解的方法:方法名不同但是返回對(duì)象類型相同,@Bean注解中顯式指定相同的beanName

@Bean("sim1")
	public Sim1 sim1(){
		System.out.println("public Sim1 sim1()");
		Sim1 sim1 = new Sim1();
		sim1.setName("sim1");
		return sim1;
	}
	@Bean("sim1")
	public Sim1 sim2(){
		System.out.println("public Sim1 sim2()");
		Sim1 sim1 = new Sim1();
		sim1.setName("sim1");
		return sim1;
	}

輸出結(jié)果如下:

public Sim1 sim1()

源碼分析

在以下方法中會(huì)判斷現(xiàn)在的beanName在現(xiàn)有的beanDefinitionMap中是否已存在,

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(BeanMethod)

然后在以下方法中決定是否覆蓋。

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.isOverriddenByExistingDefinition(BeanMethod, String)

isOverriddenByExistingDefinition()部分具體代碼如下:

       BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
       // Is the existing bean definition one that was created from a configuration class?
       // -> allow the current bean method to override, since both are at second-pass level.
       // However, if the bean method is an overloaded case on the same configuration class,
       // preserve the existing bean definition.
       if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
           ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
           //獲得existingBean所在的配置類名,和當(dāng)前要?jiǎng)?chuàng)建的bean進(jìn)行比較:如果是 same config class,則mbd中保留先前的
           if (ccbd.getMetadata().getClassName().equals(
                   beanMethod.getConfigurationClass().getMetadata().getClassName())) {
               if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
                   //設(shè)置mbd中isFactoryMethodUnique為false,即標(biāo)記該bean的工廠方法不唯一,這樣后面instantiateUsingFactoryMethod才會(huì)處理
                   ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
               }
               return true;
           }
           else {
               return false;
           }
       }

可以看出是否覆蓋的策略如下

  • 如果是來自不同層級(jí)的factory method,允許覆蓋,isOverriddenByExistingDefinition()方法返回false
  • 如果是來自同一配置類,保留先前的beanDefinition,isOverriddenByExistingDefinition()返回true。
  • (除此之外該方法還會(huì)設(shè)置beanDefinition中isFactoryMethodUnique字段為false,即標(biāo)記該factory method不唯一)

spring如何完成覆蓋或者保留的?

分析onfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod 以下源碼片段可以看出:

        //如果需要保留先前注冊(cè)的bean,isOverriddenByExistingDefinition()方法返回true,
        //該方法就會(huì)進(jìn)入該條件代碼塊,直接返回
        if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
            if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
                throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
                        beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
                        "' clashes with bean name for containing configuration class; please make those names unique!");
            }
            return;
        }
        //如果需要覆蓋,就會(huì)繼續(xù)執(zhí)行接下來的代碼,生成新的beanDefinition并進(jìn)行更新,新的beanDefinition就會(huì)保留新的factory method

覆蓋規(guī)則分析

  • 通過@ComponentScan掃描進(jìn)來的優(yōu)先級(jí)是最低的,原因就是它掃描進(jìn)來的Bean定義是最先被注冊(cè)的,也就是說同文件下@Bean的會(huì)生效,@ComponentScan掃描進(jìn)來不會(huì)生效。
  • @Import引入的配置類中的bean會(huì)被當(dāng)前配置類中的同名bean覆蓋。
  • 不同配置文件中存在同名Bean,后解析的配置文件會(huì)覆蓋先解析的配置文件。

此處需要注意的是:配置文件的先后順序其實(shí)會(huì)受到@Order來控制,只是若沒有@Order注解的話就按照傳入的順序執(zhí)行解析。

情況二

@Bean注解:不同的重載方法,且返回同名bean

BeanDefinition的生成

ConfigurationClassBeanDefinitionReader#isOverriddenByExistingDefinition

在情況一中我們知道,該方法碰到來自同一配置類的同名bean,會(huì)設(shè)置其beanDefinition對(duì)象中isFactoryMethodUnique字段為false,以此標(biāo)記該bean的工廠方法不唯一,為之后利用factory method實(shí)例化bean做準(zhǔn)備。

重載工廠方法的選擇

利用factory method實(shí)例化bean主要在以下方法中完成:

ConstructorResolver.instantiateUsingFactoryMethod()

在該方法中完成了重載方法的選擇

基本思想:

1.if(mbd.isFactoryMethodUnique)工廠方法唯一:工廠方法不存在重載或者@Bean注解的beanName相同但方法名不同的方法

2.如果不唯一則繼續(xù)處理:通過反射獲取該配置類下所有方法保存到集合rawCandidates

3.遍歷rawCandidates,找出所有符合要求的重載的candidate,判斷條件如下:

  • 首先是實(shí)例還是靜態(tài)要和當(dāng)前從bd中解析出的結(jié)果相同
  • mbd.isFactoryMethod(candidate)比較當(dāng)前方法名和bd中保存的FactoryMethodName是否相同:

4.給所有candidate排序:

  • 先比較可見性public的排在前面
  • 否則比較參數(shù)個(gè)數(shù),優(yōu)先選參數(shù)多的

5.createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.size() == 1)

根據(jù)已經(jīng)解析的構(gòu)造器參數(shù)值、mbd等,創(chuàng)建一個(gè)參數(shù)數(shù)組以作為匹配標(biāo)準(zhǔn)選擇要調(diào)用構(gòu)造函數(shù)或工廠方法。

6.尋找最小類型差異值minTypeDiffWeight:

對(duì)所有重載方法(candidates)進(jìn)行遍歷, 并計(jì)算每個(gè)方法參數(shù)列表的typeDiffWeight,該值代表了該方法的參數(shù)和beanDefinition中保存的參數(shù)列表的匹配程度,選取參數(shù)差異值最小的方法作為要使用的工廠方法。

7.對(duì)于具有相同數(shù)量參數(shù)的方法,

  • 如果它們具有相同的typeDiffWeight,則收集此類候選方法放入ambiguousFactoryMethods并最終引發(fā)歧義異常。
  • 但是僅在isLenientConstructorResolution==false模式下執(zhí)行該檢查。
  • !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes()條件能夠顯式忽略掉重寫的方法(因?yàn)橹貙懢哂邢嗤膮?shù)簽名)

源碼分析

    public BeanWrapper instantiateUsingFactoryMethod(
            String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.beanFactory.initBeanWrapper(bw);
        Object factoryBean;
        Class<?> factoryClass;
        boolean isStatic;
        String factoryBeanName = mbd.getFactoryBeanName();//首先,在bd中找是否有factoryBean
        if (factoryBeanName != null) {
            if (factoryBeanName.equals(beanName)) {//factoryBean不能和要?jiǎng)?chuàng)建的bean一樣,即不能在配置類中配置config本身的bean
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "factory-bean reference points back to the same bean definition");
            }
            factoryBean = this.beanFactory.getBean(factoryBeanName);//從bean工廠中返回factoryBean
            if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                throw new ImplicitlyAppearedSingletonException();//bean在它的factoryBean創(chuàng)建的過程中已經(jīng)隱式地被創(chuàng)建了
            }
            factoryClass = factoryBean.getClass();
            isStatic = false;
        }
        else {
            // It's a static factory method on the bean class.
            // 如果bean definition中沒有傳入一個(gè)factory-bean,
            // 而是傳入一個(gè)class對(duì)象或者一個(gè)使用依賴注入配置的factory object本身的實(shí)例變量。
            // 那么該命名工廠方法可能是一個(gè)靜態(tài)方法
            if (!mbd.hasBeanClass()) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "bean definition declares neither a bean class nor a factory-bean reference");
            }
            factoryBean = null;
            factoryClass = mbd.getBeanClass();//如果是靜態(tài)方法,就獲取配置類的class對(duì)象
            isStatic = true;
        }
        Method factoryMethodToUse = null;
        ArgumentsHolder argsHolderToUse = null;
        Object[] argsToUse = null;
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }
        else {
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;//程序包可見的字段,用于緩存已解析的構(gòu)造函數(shù)或工廠方法
                if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                    // Found a cached factory method...
                    // 如果緩存中存在,那么從緩存中獲取factory method參數(shù)
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            //如果緩存中獲取到參數(shù)
            if (argsToResolve != null) {
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
            }
        }
        //緩存中沒有,嘗試使用所有具有該名稱的方法,以查看它們是否與給定參數(shù)匹配。
        if (factoryMethodToUse == null || argsToUse == null) {
            // Need to determine the factory method...
            // Try all methods with this name to see if they match the given arguments.
            factoryClass = ClassUtils.getUserClass(factoryClass);//根據(jù)代理類獲取原配置類
            List<Method> candidates = null;
            //工廠方法唯一:工廠方法不存在重載或者@Bean注解的beanName相同但方法名不同的方法
            if (mbd.isFactoryMethodUnique) {
                if (factoryMethodToUse == null) {
                    factoryMethodToUse = mbd.getResolvedFactoryMethod();
                }
                if (factoryMethodToUse != null) {
                    candidates = Collections.singletonList(factoryMethodToUse);
                }
            }
            if (candidates == null) {
                candidates = new ArrayList<>();
                //通過反射獲取該factoryClass下所有方法
                Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
                //遍歷,找出所有符合要求的重載的candidate
                for (Method candidate : rawCandidates) {
                    //1、首先是實(shí)例還是靜態(tài)要和當(dāng)前從bd中解析出的結(jié)果相同
                    // 2、mbd.isFactoryMethod(candidate)比較當(dāng)前方法名和bd中保存的FactoryMethodName是否相同:
                    //     只有重載的方法才會(huì)返回true,所以重載方法都可以作為candidate
                    //    @Bean注解解析出的beanname相同但是方法名不同的多個(gè)方法,只會(huì)有一個(gè)是bd中設(shè)置的工廠方法,其他會(huì)被過濾掉。
                    if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                        candidates.add(candidate);
                    }
                }
            }
            //如果沒有重載方法,且沒有顯式傳遞參數(shù),且mbd中沒有提前存有構(gòu)造函數(shù)參數(shù)值
            if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
                Method uniqueCandidate = candidates.get(0);
                if (uniqueCandidate.getParameterCount() == 0) {
                    //工廠方法的參數(shù)個(gè)數(shù)為0
                    mbd.factoryMethodToIntrospect = uniqueCandidate;
                    synchronized (mbd.constructorArgumentLock) {
                        mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                        mbd.constructorArgumentsResolved = true;
                        mbd.resolvedConstructorArguments = EMPTY_ARGS;
                    }
                    //FactoryMethod參數(shù)為0個(gè)的情況
                    bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
                    return bw;
                }
            }
            //存在多個(gè)重載的factoryMethod 如:配置類中聲明的是多個(gè)重載的工廠方法
            if (candidates.size() > 1) {  // explicitly skip immutable singletonList
                //給所有candidate排序:
                // 1、先比較可見性public的排在前面
                // 否則比較參數(shù)個(gè)數(shù),優(yōu)先選參數(shù)多的
                candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
            }
            // getResolvedAutowireMode返回bean的裝配方式 
            // autowiring指示是否為構(gòu)造器裝配
            ConstructorArgumentValues resolvedValues = null;
            boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
            //尋找最小類型差異值minTypeDiffWeight
            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Method> ambiguousFactoryMethods = null;
            int minNrOfArgs;
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            }
            else {
                //我們沒有以代碼方式顯式傳遞參數(shù),因此我們需要解析在beanDefinition中保存的構(gòu)造函數(shù)參數(shù)列表中指定的參數(shù)。
                // We don't have arguments passed in programmatically, so we need to resolve the
                // arguments specified in the constructor arguments held in the bean definition.
                if (mbd.hasConstructorArgumentValues()) {
                    //beanDefinition中保存了構(gòu)造函數(shù)參數(shù)
                    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                    resolvedValues = new ConstructorArgumentValues();
                    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
                }
                else {
                    //beanDefinition中沒有保存參數(shù)
                    minNrOfArgs = 0;
                }
            }
            //保存出現(xiàn)異常的原因,最后統(tǒng)一處理
            LinkedList<UnsatisfiedDependencyException> causes = null;
            //對(duì)所有重載方法(candidates)進(jìn)行遍歷,
            // 并計(jì)算每個(gè)方法參數(shù)列表的typeDiffWeight---代表了該方法的參數(shù)和bd中保存的參數(shù)列表的匹配程度,
            // 遍歷并選取參數(shù)差異值最小的方法作為要使用的工廠方法
            for (Method candidate : candidates) {
                int parameterCount = candidate.getParameterCount();//獲取方法的參數(shù)個(gè)數(shù)
                if (parameterCount >= minNrOfArgs) {
                    ArgumentsHolder argsHolder;
                    Class<?>[] paramTypes = candidate.getParameterTypes();
                    if (explicitArgs != null) {
                        // Explicit arguments given -> arguments length must match exactly.
                        if (paramTypes.length != explicitArgs.length) {
                            continue;
                        }
                        argsHolder = new ArgumentsHolder(explicitArgs);
                    }
                    else {
                        // Resolved constructor arguments: type conversion and/or autowiring necessary.
                        try {
                            String[] paramNames = null;
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            if (pnd != null) {
                                paramNames = pnd.getParameterNames(candidate);
                            }
                            //根據(jù)已經(jīng)解析的構(gòu)造器參數(shù)值、mbd等,創(chuàng)建一個(gè)參數(shù)數(shù)組以作為匹配標(biāo)準(zhǔn)選擇要調(diào)用構(gòu)造函數(shù)或工廠方法。
                            argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                    paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
                        }
                        catch (UnsatisfiedDependencyException ex) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
                            }
                            // Swallow and try next overloaded factory method.
                            if (causes == null) {
                                causes = new LinkedList<>();
                            }
                            causes.add(ex);
                            continue;
                        }
                    }
                    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                            argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                    // Choose this factory method if it represents the closest match.
                    //如果它表示最接近的匹配項(xiàng),則選擇此工廠方法
                    if (typeDiffWeight < minTypeDiffWeight) {
                        factoryMethodToUse = candidate;
                        argsHolderToUse = argsHolder;
                        argsToUse = argsHolder.arguments;
                        minTypeDiffWeight = typeDiffWeight;
                        ambiguousFactoryMethods = null;
                    }
                    //找出歧義:對(duì)于具有相同數(shù)量參數(shù)的方法,
                    // 如果它們具有相同的類型差權(quán)重,則收集此類候選方法放入ambiguousFactoryMethods并最終引發(fā)歧義異常。 
                    // 但是,僅在isLenientConstructorResolution==false非寬松構(gòu)造函數(shù)解析模式下執(zhí)行該檢查,
                    // !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes()條件
                    // 顯式忽略重寫的方法(具有相同的參數(shù)簽名))。
                    else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
                            !mbd.isLenientConstructorResolution() &&//如果當(dāng)前typeDiffWeight和目前遍歷出的候選方法相同,且參數(shù)個(gè)數(shù)相同
                            paramTypes.length == factoryMethodToUse.getParameterCount() &&
                            !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
                        if (ambiguousFactoryMethods == null) {
                            ambiguousFactoryMethods = new LinkedHashSet<>();
                            ambiguousFactoryMethods.add(factoryMethodToUse);
                        }
                        ambiguousFactoryMethods.add(candidate);
                    }
                }
            }
            if (factoryMethodToUse == null || argsToUse == null) {
                if (causes != null) {
                    UnsatisfiedDependencyException ex = causes.removeLast();
                    for (Exception cause : causes) {
                        this.beanFactory.onSuppressedException(cause);
                    }
                    throw ex;
                }
                List<String> argTypes = new ArrayList<>(minNrOfArgs);
                if (explicitArgs != null) {
                    for (Object arg : explicitArgs) {
                        argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
                    }
                }
                else if (resolvedValues != null) {
                    Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
                    //getIndexedArgumentValues()返回參數(shù)索引為鍵,ValueHolder為值的不可修改的Map
                    valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
                    valueHolders.addAll(resolvedValues.getGenericArgumentValues());
                    //維護(hù)argTypes List
                    for (ValueHolder value : valueHolders) {
                        String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
                                (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
                        argTypes.add(argType);
                    }
                }
                String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "No matching factory method found: " +
                        (mbd.getFactoryBeanName() != null ?
                            "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
                        "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
                        "Check that a method with the specified name " +
                        (minNrOfArgs > 0 ? "and arguments " : "") +
                        "exists and that it is " +
                        (isStatic ? "static" : "non-static") + ".");
            }
            else if (void.class == factoryMethodToUse.getReturnType()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Invalid factory method '" + mbd.getFactoryMethodName() +
                        "': needs to have a non-void return type!");
            }
            else if (ambiguousFactoryMethods != null) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Ambiguous factory method matches found in bean '" + beanName + "' " +
                        "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
                        ambiguousFactoryMethods);
            }
            //維護(hù)mbd和緩存
            if (explicitArgs == null && argsHolderToUse != null) {
                mbd.factoryMethodToIntrospect = factoryMethodToUse;
                argsHolderToUse.storeCache(mbd, factoryMethodToUse);
            }
        }
        //確定工廠方法后,開始實(shí)例化bean
        bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
        return bw;
    }

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)分頁(yè)的前臺(tái)頁(yè)面和后臺(tái)代碼

    Java實(shí)現(xiàn)分頁(yè)的前臺(tái)頁(yè)面和后臺(tái)代碼

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)分頁(yè)的前臺(tái)頁(yè)面和后臺(tái)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Java RPC框架熔斷降級(jí)機(jī)制原理解析

    Java RPC框架熔斷降級(jí)機(jī)制原理解析

    這篇文章主要介紹了Java RPC框架熔斷降級(jí)機(jī)制原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java命令設(shè)計(jì)模式優(yōu)雅解耦命令和執(zhí)行提高代碼可維護(hù)性

    Java命令設(shè)計(jì)模式優(yōu)雅解耦命令和執(zhí)行提高代碼可維護(hù)性

    本文介紹了Java命令設(shè)計(jì)模式,它將命令請(qǐng)求封裝成對(duì)象,以達(dá)到解耦命令請(qǐng)求和執(zhí)行者的目的,從而提高代碼可維護(hù)性。本文詳細(xì)闡述了該模式的設(shè)計(jì)原則、實(shí)現(xiàn)方法和優(yōu)缺點(diǎn),并提供了實(shí)際應(yīng)用場(chǎng)景和代碼示例,幫助讀者深入理解和應(yīng)用該模式
    2023-04-04
  • Sparsearray稀疏數(shù)組原理及實(shí)例詳解

    Sparsearray稀疏數(shù)組原理及實(shí)例詳解

    這篇文章主要介紹了Sparsearray稀疏數(shù)組原理及實(shí)例詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 從面試中的問題分析ThreadLocal

    從面試中的問題分析ThreadLocal

    這篇文章主要介紹了從面試中的問題分析ThreadLocal,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來一起學(xué)習(xí)一下吧
    2019-06-06
  • spring mvc中的@PathVariable動(dòng)態(tài)參數(shù)詳解

    spring mvc中的@PathVariable動(dòng)態(tài)參數(shù)詳解

    這篇文章主要介紹了spring mvc中的@PathVariable動(dòng)態(tài)參數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java純代碼實(shí)現(xiàn)導(dǎo)出pdf合并單元格

    Java純代碼實(shí)現(xiàn)導(dǎo)出pdf合并單元格

    這篇文章主要為大家詳細(xì)介紹了Java如何純代碼實(shí)現(xiàn)導(dǎo)出pdf與合并單元格功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • 詳解SpringBoot+Lucene案例介紹

    詳解SpringBoot+Lucene案例介紹

    這篇文章主要介紹了詳解SpringBoot+Lucene案例介紹,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對(duì)比

    后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對(duì)比

    這篇文章主要給大家介紹了關(guān)于后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對(duì)比的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 通過java.util.TreeMap源碼加強(qiáng)紅黑樹的理解

    通過java.util.TreeMap源碼加強(qiáng)紅黑樹的理解

    通過分析java.util.TreeMap源碼來對(duì)經(jīng)典問題紅黑樹加強(qiáng)理解和理清思路。
    2017-11-11

最新評(píng)論