4.1.3.1Spring源码解析——createBean方法细节之doCreateBean

2023-11-11

先贴代码,doCreateBean方法位于AbstractAutowireCapableBeanFactory方法中,前面已经解析了CreateBean方法,可以点这里传送CreateBean方法解析

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
        // Instantiate the bean.
        //BeanWrapper提供设置和获取属性值(单独或批量),获取属性描述符和查询属性以确定它们是可读还是可写的功能
        BeanWrapper instanceWrapper = null;
        //如果RootBeanDefinition是单例的,则移除未完成的FactoryBean实例的缓存
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            //创建bean实例
            //------------------------------------------方法1----------------------------------------//
            instanceWrapper = createBeanInstance(beanName, mbd, args);
       //------------------------------------------方法1----------------------------------------//
        }
      //获取BeanWrapper中封装的Object对象,其实就是bean对象的实例
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    //获取BeanWrapper中封装的bean的Class
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
            //--------------------------------------------------2---------------------------------------------//
          bean 的生命周期之一。如果实现了MergedBeanDefinitionPostProcessor会在这里调用postProcessMergedBeanDefinition方法
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                //--------------------------------------------------2---------------------------------------------//
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
              //如果RootBeanDefinition是单例的,并且开启了自动尝试解析bean之间的循环引用,并且当前bean正在创建中,则说明这个bean需要被加入到缓存的单例bean集合中
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            /**
             * addSingletonFactory会将beanName和ObjectFactory对象作为键值对保存到缓存的单例集合中
             * singletonObjects: 单例对象的缓存 ConcurrentHashMap
             * singletonFactories:单例工厂的缓存 HashMap
             * earlySingletonObjects: 早期单例对象的缓存  HashMap
             * registeredSingletons: 一组已经注册的单例,按注册顺序排序   LinkedHashSet
             */
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                public Object getObject() throws BeansException {
//---------------------------------------------3------------------------------//
                    return getEarlyBeanReference(beanName, mbd, bean);
//---------------------------------------------3------------------------------//
                }
            });
        }
        // Initialize the bean instance.
        Object exposedObject = bean;

        try {
//---------------------------------------------4------------------------------//
                  //进行属性填充
            populateBean(beanName, mbd, instanceWrapper);
//---------------------------------------------4------------------------------//
            if (exposedObject != null) {
                //---------------------------------------------5------------------------------//
                //初始化给定的bean实例,应用工厂回调以及init方法和bean后处理器
                exposedObject = initializeBean(beanName, exposedObject, mbd);
                //---------------------------------------------5------------------------------//
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }
    //如果单例bean已经缓存了,则直接获取            
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
//如果不允许在循环引用的情况下使用注入原始bean实例(即使注入的bean最终被包装),并且依赖的bean列表中存在需要创建bean。这时候就说明存在循环依赖
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    //根据beanName获取所有依赖的bean的beanName
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        //删除存在循环依赖的bean    
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
                        //将给定的bean添加到此一次性Bean列表中,这个列表中的bean在Spring关闭的时候会查询里面的bean,并调用实现的销毁方法(包含实现了DisposableBean接口的方法和自定义的destory方法),满足其中一个条件
            // 1.实现了DisposableBean接口
            //2.自定义了destroy方法
            //3.实现了AutoCloseable接口
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
  • (1)方法1createBeanInstance

这个createBeanInstance方法位于AbstractAutowireCapableBeanFactory类中

  protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // Make sure bean class is actually resolved at this point.
        //获取RootBeanDefinition的Class属性
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        //如果bean的类修饰符不是public则报错
        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());
        }
        //查看RootBeanDefinition的factor-method属性是不是空的,不为空,说明bean 
        // 的实现要通过先实例化对应的factoryBean然后调用factoryMethod方法实现,或者直接调用静态的factoryMethod方法
        if (mbd.getFactoryMethodName() != null)  {
//---------------------------------------------1------------------------------------------//
            return instantiateUsingFactoryMethod(beanName, mbd, args);
//---------------------------------------------1------------------------------------------//
        }

        // Shortcut when re-creating the same bean...
         //重新创建同一个bean时相关的判断条件
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
    //如果缓存的已解析的构造函数或工厂方法对象不为空,则说明这是重新创建同一个bean
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
  //如果是重新创建,就直接创建
        if (resolved) {
        //如果构造函数参数标记是已解析,就直接进行构造,否则重新解析然后创建
            if (autowireNecessary) {
//-----------------------------------------2--------------------------------------------------//
                return autowireConstructor(beanName, mbd, null, null);
//-----------------------------------------2--------------------------------------------------//
            }
            else {
                //使用给出的构造器来创建bean并封装到BeanWrapperImpl中,这个方法在autowireConstructor也有用到
                return instantiateBean(beanName, mbd);
            }
        }

        // Need to determine the constructor...
            //如果不是重新创建的bean,需要确定要用于给定bean的候选构造函数,检查所有已注册的构造函数
                    //bean 的生命周期之一,如果实现了SmartInstantiationAwareBeanPostProcessor接口,会在这里调用determineCandidateConstructors方法
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
          //没有特殊处理:只需使用no-arg构造函数
        return instantiateBean(beanName, mbd);
    }

(1.1)我们查看instantiateUsingFactoryMethod方法的具体实现

 instantiateUsingFactoryMethod方法位于AbstractAutowireCapableBeanFactory类中

protected BeanWrapper instantiateUsingFactoryMethod(
            String beanName, RootBeanDefinition mbd, Object[] explicitArgs) {
//相当于调用AbstractAutowireCapableBeanFactory类的instantiateUsingFactoryMethod方法
        return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
    }
//instantiateUsingFactoryMethod方法的逻辑就是用定义的factoryBean的factoryMethod方法来创建bean,或者用静态的factoryMethod方法来实现。然后获取到的bean用BeanWrapperImpl封装返回的信息。

(1.2)我们查看autowireConstructor方法的具体实现

 这个方法的步骤比较多我们在另外的一篇文章中分析
autowireConstructor方法的详解

方法2applyMergedBeanDefinitionPostProcessors

 这个方法在实例化bean之后会调用

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
            throws BeansException {

        try {
            //获取这个bean所有的实现了BeanPostProcessor接口的类
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                //如果是MergedBeanDefinitionPostProcessor类型的就调用实现的postProcessMergedBeanDefinition方法,
                if (bp instanceof MergedBeanDefinitionPostProcessor) {
                    MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                    bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
                }
            }
        }
        catch (Exception ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Post-processing failed of bean type [" + beanType + "] failed", ex);
        }
    }

(1.3)getEarlyBeanReference方法

 这个方法主要用于检查这个bean是否已经

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        //bean不为空,并且RootBeanDefinition是程序自己定义的,并且实现了InstantiationAwareBeanPostProcessors(一个bean实例化过程中调用的类)
        if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    //获取早期访问指定bean的引用,通常用于解析循环引用。
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    if (exposedObject == null) {
                        return null;
                    }
                }
            }
        }
        return exposedObject;
    }

(1.4)populateBean方法

 使用bean定义中的属性值填充给定BeanWrapper中的bean实例

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        //获取RootBeanDefinition中bean的属性值
        PropertyValues pvs = mbd.getPropertyValues();
        //如果BeanWrapper为null说明bean没有实例化成功,会报错
        if (bw == null) {
            if (!pvs.isEmpty()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }
        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the state of the bean before properties are set. This can be used, for example, to support styles of field injection.
        //为任何实现了InstantiationAwareBeanPostProcessors接口的方法,提供在设置属性之前修改bean状态的机会,就是实例化bean的时候(不是复赋值的时候)
        boolean continueWithPropertyPopulation = true;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    //调用实现的postProcessAfterInstantiation方法
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }
        if (!continueWithPropertyPopulation) {
            return;
        }
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            //深拷贝RootBeanDefinition的所有的属性值。保证PropertyValue引用是独立的,但它不能深度复制当前由各个PropertyValue对象引用的对象。
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            //按照按名称注入的方式注入
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {

                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            //按照按名称类型的方式注入
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
        //如果bean实现了InstantiationAwareBeanPostProcessor接口或者bean需要进行依赖检查,需要进行处理
        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            //一次调用实现的InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues方法
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            //进行依赖检查,主要检查设置到bean中的数据类型和对象是否个bean对象自身定义的数据类型和对象是不是一样
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        applyPropertyValues(beanName, mbd, bw, pvs);
    }

//其中的autowireByName方法解析
      protected void autowireByName(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        //获取所有的不是普通属性(普通指的基本类型,字符串,数字类型,日期,URL,URI一个Local类或者一个Class对象)的元素的name(name从BeanWrapper中获取)数组
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        //按照获取的名称去找对应的bean,并添加到依赖缓存集合中记录
        for (String propertyName : propertyNames) {
            if (containsBean(propertyName)) {
                Object bean = getBean(propertyName);
                pvs.add(propertyName, bean);
                registerDependentBean(propertyName, beanName);
                if (logger.isDebugEnabled()) {
                    logger.debug("Added autowiring by name from bean name '" + beanName +
                            "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                            "' by name: no matching bean found");
                }
            }
        }
    }

(1.5)initializeBean方法

  在这里会初始化已经实例化之后的bean,并会在这里调用部分用户自己实现了的bean生命周期的方法

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        //如果bean是BeanNameAware,BeanClassLoaderAware或者BeanFactoryAware其中某一个的实现类就需要进行处理
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        //bean的生命周期之一。如果实现了BeanPostProcessor接口则在这里调用postProcessBeforeInitialization方法
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
        //bean的生命周期之一,如果实现了InitializingBean接口,会在这里调用实现的afterPropertiesSet方法
        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        //bean的生命周期之一。如果实现了BeanPostProcessor接口则在这里调用postProcessAfterInitialization方法
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

4.1.3.1Spring源码解析——createBean方法细节之doCreateBean 的相关文章

  • centos断电重启卡在登录前界面的问题解决

    出现这个情况的原因猜测是断电 启动后就卡在登录前界面 只有网络是通的 其他服务貌似都没正常启动 ssh远程终端也连不上 ctrl alt 1 切换到详细信息模式下看到这样的错误 就是文件系统xfs有损坏 查资料都说是需要通过xfs repa
  • c语言编程3*3矩阵的转置

    include
  • 【FreeRTOS】任务通知的使用

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • Java比较两个对象是否相同并获取值不同的属性

    最近项目中要加操作日志 同时要把用户修改了那些字段记录下来 在更新的时候就需要比较之前的数据和现在的数据有哪些不同 这么多类一个一个的比较就太麻烦了 所以打算写一个工具类 主要思想还是通过反射获取类的属性的getter方法 调用getter
  • 【Mo 人工智能技术博客】基于耦合网络的推荐系统

    基于耦合网络的推荐系统 作者 陈东瑞 1 复杂网络基础知识 当我们拿起手机给家人 朋友或者同事拨打电话时 就不知不觉中参与到了社交网络形成的过程中 当我们登上高铁或者飞机时 就可以享受交通网络给我们带来的方便 即使当我们躺在床上什么也不干时
  • 【Java小实验】【Java并发】使用线程池按行并发取二维数组最大值

    使用线程池按行并发取二维数组最大值 生成二维数组 使用Callable实现线程 使用Runnable获取线程 快手后端二面问题 由于网上直接搜竟然没有搜出来 自己写了一下 生成二维数组 生成二维数组的公共类 class RandomArra
  • Mybatis中@MapKey注解简介说明

    转自 Mybatis中 MapKey注解简介说明 下文笔者讲述Mybatis中 MapKey注解的简介说明 Mybatis中 MapKey注解的功能 MapKey注解 1 用于返回map的key值 通常情况下使用唯一键作为key 2 此注解
  • 网络原理(四):传输层协议 TCP/UDP

    目录 应用层 传输层 udp 协议 端口号 报文长度 udp 长度 校验和 TCP 协议 确认应答 超时重传 链接管理 滑动窗口 流量控制 拥塞控制 延时应答 捎带应答 总结 我们第一章让我们对网络有了一个初步认识 第二章和第三章我们通过代
  • NSI45025AT1G 25mA 45V LED驱动器,恒流调节器 工业指示灯、背光灯解决方案

    NSI45025AT1G是一款线性恒流调节器是一种简单 经济和稳健的装置 旨在为LED 类似于恒流二极管 CCD 中的电流调节提供一种成本有效的解决方案 恒流调节器基于自偏置晶体管 SBT 技术 在宽电压范围内调节电流 具有负温度系数 以保
  • 第一章 红绿灯数据采集

    第一章 红绿灯数据采集 华为hilens主控 AI实现自主导航和红绿灯控制 总章目录 第一章 Hilens红绿灯数据采集 第二章 ModelArts数据处理 第三章 ModelArts模型训练 第四章 ModelArts模型转换 第五章 H
  • 国内各大互联网公司技术团队站点

    利用闲暇时间整理了一份国内各大互联网公司的相关技术站点 希望能够对大家有所帮助 也欢迎各位帮忙补充 1 腾讯系列 名称 地址 财付通设计中心TID 地址 fitdesign tencent com QQ邮箱博客 地址 blog mail q
  • 使用linux服务器相关命令

    最近需要在云GPU服务器上跑模型 初次接触这样的形式 因此记录一下比较常用的命令 一 ssh登陆指令 1 常见登陆方式 ssh 用户名 服务器ip 2 有端口号和用户名的登陆方式 ssh l 用户名 服务器ip p 端口号 二 scp指令
  • git push遇到503错误的解决方案:The requested URL returned error: 503

    git remote set url origin https your user name github com your user name your project name git 参考了这个blog https www shuiz
  • 球谐函数在环境光照中的使用原理

    在三维空间中如何对场景光照进行球谐函数展开 图形学论文解析与复现 Spherical Harmonic Lighting The Gritty Details 首先 对场景中某像素点的漫反射光照进行计算 L p w
  • 机房 机柜的保养 和清理

    https www linuxprobe com clear idc html
  • 取消Allegro的PCB文件在Drill Legend后产生的过孔标注的方法

    在cadence的PCB编辑完成后 Drill Legend生产钻孔说明表 程序会自动加上钻孔的标注 如图 给后续的再次编辑带来困扰 关闭方法 关闭图层Manufacturing gt Ncdrill Figure即可关闭钻孔标注
  • float取小数点后几位_float类型的存储方式

    在c语言中float函数是单精度的 它在内存中以二进制的形式存储 分为符号位 阶码与尾数三部分 符号位最为简单 如果你存储的是正数那么符号数就是0 如果是负数 则为1 下面 我以13 625为例说明阶码与尾数的表示方法 首先 我们取出13
  • 深入理解程序设计使用linux汇编语言(一)

    在编译运行第四章power函数遇到报错 报错信息Invalid SP address 0xffffdf2c 通过gdb定位到程序 gt 0x40007e
  • mysql数据库,oracle数据库中对字段的拼接方法

    mysql数据库 oracle数据库中对字段的拼接方法 1 简介 在日常开发中 常常有将多个字段拼接进行sql操作的场景 比如做模糊查询 我这里分两种环境阐述 1 在数据库中的写法 2 在mybatis或mybatisplus中的写法 2

随机推荐

  • Matlab绘图-详细全面(图)

    Matlab绘图 强大的绘图功能是Matlab的特点之一 Matlab提供了一系列的绘图函数 用户不需要过多的考虑绘图的细节 只需要给出一些基本参数就能得到所需图形 这类函数称为高层绘图函数 此外 Matlab还提供了直接对图形句柄进行操作
  • 自动驾驶(五十三)---------浅析深度学习与自动驾驶

    之前有分析过深度学习和自动驾驶的关系 但是主要是在视觉的基础上来分析的 连接 这里想从各个角度来分析深度学习在自动驾驶中的应用 如果你正好有这方面的需要 不妨选择一个着力点 笔者从事自动驾驶3年来 也处于瓶颈期 需要在一个特定的领域深挖 这
  • 华为OD机试真题-最大花费金额-2023年OD统一考试(B卷)

    题目描述 双十一众多商品进行打折销售 小明想购买自己心仪的一些物品 但由于受购买资金限制 所以他决定从众多心仪商品中购买三件 而且想尽可能的花完资金 现在请你设计一个程序帮助小明计算尽可能花费的最大资金数额 输入描述 输入第一行为一维整型数
  • 区块链技术生态的设计

    区块链技术生态的设计 详见 区块链技术生态
  • String-字符串替换

    例子 原始字符串 String demo aback 文章目录 一 replace 字符或者字符串替换 1 使用方法 2 源码 二 replaceAll 多个正则替换 1 使用方法 2 源码 三 replaceFirst 首次出现替换 1
  • 移动端兼容宝典大全,专治各种不适

    古人学问遗无力 少壮功夫老始成 移动端兼容宝典大全 专治各种不适 你是否也曾为浏览器各种的不兼容而苦恼 尤其是IE这个牛皮癣 这篇文章可能会给你帮助哦 常码字不易 出精品更难 没有特别幸运 那么请先特别努力 别因为懒惰而失败 还矫情地将原因
  • 小程序调整文章正文样式:

    1 官网地址 npm install github markdown css 2 案例 右键 gt 另存为 gt 导入 使用css文件 引入的css已markdown body的class名开头 适配时禁止github markdown转换
  • Openlayers API-Select点击要素图层

    Select是交互事件中的一种 用于选择矢量图层上的几何图形 添加选择交互事件后 点击地图上的几何图形或者将鼠标移动到几何图形上时 将获取到几何图形的相关信息 我们可以将选择的几何图形进行高亮显示 使用起来很简单 首先创建一个Select对
  • Xcode MacOS与clang c++版本关系

    关于clang https en wikipedia org wiki Clang 7 September 2017 Clang 5 0 0 released 19 January 2018 Clang becomes default co
  • QT系列第2节 QT中元对象系统

    QT是在标准C 上进行了扩展 所以就有自己的特性 其中元对象系统就是其一 元对象系统有点类似于java和go语言中的反射 让我们在编程时解决问题多了些方法和思路 关于元对象可以简单总结出以下内容项 目录 一 元对象要点总结 二 示例代码 一
  • SVN的常见用法

    3 发生冲突后 执行 更新 操作后 对于发生冲突的文件 SVN会加上冲突标记 冲突解决 Tortoise 编辑冲突 找到这个文件 右键选择Edit conflicts 按钮 弹出编辑冲突的界面 手工将前一版本中的修改整合到自己的文件中 选择
  • apache2.4+php5.4 安装配置

    尝试一个新东西有时候会遇到很多问题 apache2 4 php5 4 安装完成后 记录下解决的办法 1 安装apache2 4需要 microsoft visual C 2010 x86 运行库 2 apache2 4 加载php5 4 需
  • 连接oracle出现ORA-12514错误

    1 PL SQL连接oracle出现ORA 12514错误 注意看图中画出的重点 2 java 连接的时候报错 连接URL option url jdbc oracle thin 47 97 11 138 1522 XE java sql
  • gitlab合并不同分支的(二)种方法 git merge 分支

    gitlab分支 git merge 合并 文章目录 gitlab分支 git merge 合并 前言 一 第一种gitlab工具合并的方法 二 代码提交进行合并 总结 前言 提示 遇到的问题 以前在公司的开发 多人开发的时候是在统一个 m
  • 微信小程序 -- ios 底部小黑条安全距离兼容解决方案(转载)

    在苹果 iPhoneX iPhone XR等设备上 可以看到物理Home键被取消 改为底部小黑条替代home键功能 微信小程序和 h5 网页需要针对这种情况进行适配 否则可能会遇到底部按钮或选项卡栏与底部黑线重叠的情况 如下图 在微信小程序
  • 原来还有linux kernel api

    linux kernel api http www gnugeneration com books linux 2 6 20 kernel api 居然有人将linux kernel api给列出来了 这样编写驱动程序就是和编写普通程序一样
  • 区块链行业前景还好吗?区块链技术有没有经过时间的检验?

    一直有人在发问 被各种科技大佬们炒得那么火热的区块链技术 说到底 跟我们普通的 市井小民 有什么切身的关系利益吗 各位大佬们一口一个 改变未来 革命未来 未来又在哪里 各种吃瓜群众们还在观望的时候 区块链行业的小伙伴们 已经将区块链技术慢慢
  • Java:数值-字符串转换(String转Double)

    代码如下 String ss 3 141592653 double value Double valueOf ss toString
  • 【JavaScript——牛客网算法No.HJ26】字符串排序(字符串里英文字母按字典顺序重新排列,其他字符保持原位)附:详细排坑经历

    No HJ26 字符串排序 problem description 编写一个程序 将输入字符串中的字符按如下规则排序 规则 1 英文字母从 A 到 Z 排列 不区分大小写 如 输入 Type 输出 epTy 规则 2 同一个英文字母的大小写
  • 4.1.3.1Spring源码解析——createBean方法细节之doCreateBean

    先贴代码 doCreateBean方法位于AbstractAutowireCapableBeanFactory方法中 前面已经解析了CreateBean方法 可以点这里传送CreateBean方法解析 protected Object do