当前位置: 首页 > news >正文

Spring源码之IoC容器的Bean创建和依赖注入,DefaultListableBeanFactory容器为例

接上篇Spring源码之IoC容器初始化过程,以FileSystemXmlApplicationContext容器为例
因为FileSystemXmlApplicationContext使用的容器为DefaultListableBeanFactory,所以该篇基于DefaultListableBeanFactory的实现分析依赖注入过程。

目录

  • 获取Bean的总体流程
  • Bean对象的实例化
  • Bean对象依赖关系的注入
  • 总结:
  • 源码
    • doGetBean方法源码
    • createBean方法
    • doCreateBean方法
    • createBeanInstance方法创建对象
      • instantiateBean方法
      • 通过反射创建对象
      • 通过CGLIB创建对象
        • createEnhancedSubclass方法
    • populateBean方法设置依赖关系
      • populateBean方法
      • applyPropertyValues方法
      • resolveValueIfNecessary方法
      • resolveReference方法

获取Bean的总体流程

getBean流程:
依赖注入通过BeanFactory的getBean方法触发。
DefaultListableBeanFactory的getBean方法通过继承AbstractAutowireCapableBeanFactory,AbstractAutowireCapableBeanFactory继承AbstractBeanFactory获得,具体的实现在AbstractBeanFactory中。

1、通过getBean方法触发依赖注入

2、getBean方法调用doGetBean方法,这是实际触发依赖注入的方法

3、先从缓存中取得Bean,处理那些已经被创建过的单件模式的Bean,对这种Bean的请求不需要重复的创建

4、如果从缓存中获得Bean,通过getObjectForBeanInstance方法完成FactoryBean的相关处理,取得FactoryBean的处理结果。

5、如果从缓存中未获得Bean,并且双亲BeanFactory不为null。检查当前IoC容器中是否存在对应的BeanDefinition,也就是检查是否能在当前的BeanFactory的Map中取得需要的Bean。

6、如果在当前的BeanFactory工厂中取不到BeanDefinition,则到双亲BeanFactory中取,也就是调用双亲BeanFactory的getBean方法。如果在当前的双亲工厂中还取不到,则递归顺着双亲BeanFactory链一直向上查找。

7、如果双亲BeanFactory为null,或者当前IoC容器中存在对应的BeanDefinition,根据Bean的名称获取BeanDefinition。

8、获取当前Bean的所有依赖的Bean名称,把依赖的Bean注册到dependentBeanMap中。并调用getBean方法注册每个依赖Bean的依赖Bean。调用getBean方法传入依赖Bean名称,这样会触发getBean的递归调用,直到取到一个没有任何依赖的Bean为止。

9、判断Bean是Singleton还是Prototype,通过调用createBean方法创建Bean实例,通过getObjectForBeanInstance方法完成FactoryBean的相关处理。

10、最后对Bean进行类型检查,如果没问题,则返回这个新创建的Bean,这个Bean是包含了依赖关系的Bean。

Bean对象的实例化

createBean方法流程:
该方法在AbstractAutowireCapableBeanFactory中实现

1、判断需要创建的Bean是否可以实例化,这个类是否可以通过类装载器来载入

2、如果Bean配置了PostProcessor,则获取一个proxy代理对象。

3、createBean调用doCreateBean创建Bean。doCreateBean中,用一个BeanWrapper持有创建出来的Bean对象。

4、如果是Singleton,先把缓存中的同名Bean清除。如果缓存找那个存在对应的Bean,则返回对应的Bean并作为即将获取的Bean,如果缓存中不存在,则调用createBeanInstance创建Bean对象。

5、调用populateBean方法对Bean进行初始化,以及依赖关系的注入。

createBeanInstance方法:

1、确认需要创建的Bean实例的类可以实例化。

2、如果instanceSupplier不为空,则通过instanceSupplier直接获取实例。

3、如果有工厂方法,则通过工厂方法对Bean进行实例化。

4、以上两种情况都不满足,则使用构造函数进行实例化。

5、通过构造函数后置处理器determineConstructorsFromBeanPostProcessors, 来选择使用哪个构造函数来实例化Bean。

6、如果构造函数后置处理器返回的构造函数为空,则用默认的构造函数对Bean进行实例化。通过instantiateBean(beanName, mbd)方法进行实例化。

instantiateBean方法:

1、使用默认的实例化策略对Bean进行实例化,默认的策略是使用CGLIB来对Bean进行实例化。

2、调用instantiate实例化Bean

SimpleInstantiationStrategy中的instantiate方法:

MethodOverrides的作用是在spring配置中存在lookup-mehtod和rreplace-method的,而这两个配置在加载xml的时候就会统一存放在BeanDefinition中的methodOverrides属性里

1、判断MethodOverrides是否为空,不为空时,使用CGLIB来实例化对象。

2、MethodOverrides为空时,取得指定的构造器或者生成对象的工厂方法来对Bean进行实例化,通过BeanUtils进行实例化,BeanUtils通过Constructor来实例化Bean,使用的是JVM的反射功能。

Bean对象依赖关系的注入

populateBean方法:

1、在创建Bean后,执行Bean的后置处理BeanPostProcessor

2、获取Bean的所有属性PropertyValues

3、开始进行依赖注入,先处理autowire的注入

4、根据Bean的名字或者类型,调用autowireByName或autowireByType方法,来完成Bean的autowire注入

5、调用applyPropertyValues对属性进行注入

6、applyPropertyValues中,通过BeanDefinitionValueResolver对BeanDefinition进行解析,applyPropertyValues方法调用了resolveValueIfNecessary方法,resolveValueIfNecessary方法调用了resolveReference方法,resolveValueIfNecessary包含了所有对注入类型的处理。

7、通过bw.setPropertyValues(new MutablePropertyValues(deepCopy));进行依赖注入

resolveReference方法:

1、根据RuntimeBeanReference判断每个PropertyValue,也就是依赖对象,是否在双亲IoC容器中

2、如果是在双亲IoC容器中,Bean的类型不为空,根据类型从双亲IoC容器中获取Bean,否则根据名字从双亲IoC容器中获取Bean

3、如果不在双亲IoC容器中,从当前容器获取Bean的实例和名字,调用当前容器的getBean获取

4、完成以上步骤后,已经为依赖注入准备好了条件,接下来就是真正注入的方法,在BeanWrapper的setPropertyValues中实现的,具体是在BeanWrapperImpl中实现的。

5、通过bw.setPropertyValues方法,遍历所有的PropertyValue,挨个进行设置

6、最终在BeanWrapperImpl中的setValue方法中,通过反射进行注入

总结:

在Bean的创建爱你和对象依赖注入的过程中,需要依据BeanDefinition中的信息来递归地完成依赖注入。从上面的几个递归过程中可以看到,这些递归都是以getBean为入口的。

一个递归是在上下文体系中查找需要的Bean和创建Bean的递归调用;另一个递归是在依赖注入时,通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。

在对Bean的属性进行依赖注入时,解析的过程也是一个递归的过程。这样,根据依赖关系,一层一层地完成Bean的创建和注入,直到最后完成当前Bean的创建。有了这个顶层Bean的创建和对它的属性依赖注入的完成,意味着和当前Bean相关的整个依赖链的注入也完成了。

源码

BeanFactory中定义了getBean方法,依赖注入正是通过getBean方法触发

public interface BeanFactory {String FACTORY_BEAN_PREFIX = "&";Object getBean(String var1) throws BeansException;<T> T getBean(String var1, Class<T> var2) throws BeansException;Object getBean(String var1, Object... var2) throws BeansException;<T> T getBean(Class<T> var1) throws BeansException;<T> T getBean(Class<T> var1, Object... var2) throws BeansException;<T> ObjectProvider<T> getBeanProvider(Class<T> var1);<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);boolean containsBean(String var1);boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String var1) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;String[] getAliases(String var1);
}

doGetBean方法源码

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {String beanName = this.transformedBeanName(name);// 先从缓存中取得Bean,处理那些已经被创建过的单件模式的Bean,对这种Bean的请求不需要重复的创建Object sharedInstance = this.getSingleton(beanName);Object bean;if (sharedInstance != null && args == null) {if (this.logger.isTraceEnabled()) {if (this.isSingletonCurrentlyInCreation(beanName)) {this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");} else {this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}// 如果从缓存中获得Bean,通过getObjectForBeanInstance方法完成FactoryBean的相关处理,// 取得FactoryBean的处理结果。bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);} else {if (this.isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 如果从缓存中未获得Bean,并且双亲BeanFactory不为null。// 检查当前IoC容器中是否存在对应的BeanDefinition,也就是检查是否能在当前的BeanFactory的Map中取得需要的Bean。BeanFactory parentBeanFactory = this.getParentBeanFactory();if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {// 如果在当前的BeanFactory工厂中取不到BeanDefinition,则到双亲BeanFactory中取,// 也就是调用双亲BeanFactory的getBean方法。如果在当前的双亲工厂中还取不到,// 则递归顺着双亲BeanFactory链一直向上查找。String nameToLookup = this.originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}if (args != null) {return parentBeanFactory.getBean(nameToLookup, args);}if (requiredType != null) {return parentBeanFactory.getBean(nameToLookup, requiredType);}return parentBeanFactory.getBean(nameToLookup);}if (!typeCheckOnly) {this.markBeanAsCreated(beanName);}// 如果双亲BeanFactory为null,或者当前IoC容器中存在对应的BeanDefinition,// 根据Bean的名称获取BeanDefinition。try {RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);this.checkMergedBeanDefinition(mbd, beanName, args);String[] dependsOn = mbd.getDependsOn();String[] var11;if (dependsOn != null) {var11 = dependsOn;int var12 = dependsOn.length;// 获取当前Bean的所有依赖的Bean名称,把依赖的Bean注册到dependentBeanMap中。// 并调用getBean方法注册每个依赖Bean的依赖Bean。for(int var13 = 0; var13 < var12; ++var13) {String dep = var11[var13];if (this.isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}this.registerDependentBean(dep, beanName);try {this.getBean(dep);} catch (NoSuchBeanDefinitionException var24) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);}}}// 判断Bean是Singleton还是Prototype,通过调用createBean方法创建Bean实例,// 通过getObjectForBeanInstance方法完成FactoryBean的相关处理。if (mbd.isSingleton()) {sharedInstance = this.getSingleton(beanName, () -> {try {return this.createBean(beanName, mbd, args);} catch (BeansException var5) {this.destroySingleton(beanName);throw var5;}});bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);} else if (mbd.isPrototype()) {var11 = null;Object prototypeInstance;try {this.beforePrototypeCreation(beanName);prototypeInstance = this.createBean(beanName, mbd, args);} finally {this.afterPrototypeCreation(beanName);}bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);} else {String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ��" + beanName + "'");}Scope scope = (Scope)this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, () -> {this.beforePrototypeCreation(beanName);Object var4;try {var4 = this.createBean(beanName, mbd, args);} finally {this.afterPrototypeCreation(beanName);}return var4;});bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);} catch (IllegalStateException var23) {throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var23);}}} catch (BeansException var26) {this.cleanupAfterBeanCreationFailure(beanName);throw var26;}}// 最后对Bean进行类型检查,如果没问题,// 则返回这个新创建的Bean,这个Bean是包含了依赖关系的Bean。if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());} else {return convertedBean;}} catch (TypeMismatchException var25) {if (this.logger.isTraceEnabled()) {this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}} else {return bean;}}

createBean方法

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {if (this.logger.isTraceEnabled()) {this.logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}try {mbdToUse.prepareMethodOverrides();} catch (BeanDefinitionValidationException var9) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);}Object beanInstance;try {beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);if (beanInstance != null) {return beanInstance;}} catch (Throwable var10) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);}try {beanInstance = this.doCreateBean(beanName, mbdToUse, args);if (this.logger.isTraceEnabled()) {this.logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;} catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {throw var7;} catch (Throwable var8) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);}}

doCreateBean方法

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = this.createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}synchronized(mbd.postProcessingLock) {if (!mbd.postProcessed) {try {this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);} catch (Throwable var17) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);}mbd.postProcessed = true;}}boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {if (this.logger.isTraceEnabled()) {this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");}this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});}Object exposedObject = bean;try {this.populateBean(beanName, mbd, instanceWrapper);exposedObject = this.initializeBean(beanName, exposedObject, mbd);} catch (Throwable var18) {if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {throw (BeanCreationException)var18;}throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);}if (earlySingletonExposure) {Object earlySingletonReference = this.getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {String[] dependentBeans = this.getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);String[] var12 = dependentBeans;int var13 = dependentBeans.length;for(int var14 = 0; var14 < var13; ++var14) {String dependentBean = var12[var14];if (!this.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 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}try {this.registerDisposableBeanIfNecessary(beanName, bean, mbd);return exposedObject;} catch (BeanDefinitionValidationException var16) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);}}

createBeanInstance方法创建对象

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);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());} else {Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return this.obtainFromSupplier(instanceSupplier, beanName);} else if (mbd.getFactoryMethodName() != null) {return this.instantiateUsingFactoryMethod(beanName, mbd, args);} else {boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized(mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);} else {Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {ctors = mbd.getPreferredConstructors();return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);} else {return this.autowireConstructor(beanName, mbd, ctors, args);}}}}}

instantiateBean方法

    protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {try {Object beanInstance;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged(() -> {return this.getInstantiationStrategy().instantiate(mbd, beanName, this);}, this.getAccessControlContext());} else {beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);}BeanWrapper bw = new BeanWrapperImpl(beanInstance);this.initBeanWrapper(bw);return bw;} catch (Throwable var5) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", var5);}}

通过反射创建对象

BeanUtils.instantiateClass(constructorToUse, new Object[0])

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {Assert.notNull(ctor, "Constructor must not be null");try {ReflectionUtils.makeAccessible(ctor);if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {return BeanUtils.KotlinDelegate.instantiateClass(ctor, args);} else {Class<?>[] parameterTypes = ctor.getParameterTypes();Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");Object[] argsWithDefaultValues = new Object[args.length];for(int i = 0; i < args.length; ++i) {if (args[i] == null) {Class<?> parameterType = parameterTypes[i];argsWithDefaultValues[i] = parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null;} else {argsWithDefaultValues[i] = args[i];}}return ctor.newInstance(argsWithDefaultValues);}} catch (InstantiationException var6) {throw new BeanInstantiationException(ctor, "Is it an abstract class?", var6);} catch (IllegalAccessException var7) {throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var7);} catch (IllegalArgumentException var8) {throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var8);} catch (InvocationTargetException var9) {throw new BeanInstantiationException(ctor, "Constructor threw exception", var9.getTargetException());}}

通过CGLIB创建对象

this.instantiateWithMethodInjection(bd, beanName, owner)

    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {return this.instantiateWithMethodInjection(bd, beanName, owner, (Constructor)null);}protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor<?> ctor, Object... args) {return (new CglibSubclassingInstantiationStrategy.CglibSubclassCreator(bd, owner)).instantiate(ctor, args);}
        public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {Class<?> subclass = this.createEnhancedSubclass(this.beanDefinition);Object instance;if (ctor == null) {instance = BeanUtils.instantiateClass(subclass);} else {try {Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());instance = enhancedSubclassConstructor.newInstance(args);} catch (Exception var6) {throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", var6);}}Factory factory = (Factory)instance;factory.setCallbacks(new Callback[]{NoOp.INSTANCE, new CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor(this.beanDefinition, this.owner), new CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});return instance;}

createEnhancedSubclass方法

        private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(beanDefinition.getBeanClass());enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);if (this.owner instanceof ConfigurableBeanFactory) {ClassLoader cl = ((ConfigurableBeanFactory)this.owner).getBeanClassLoader();enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));}enhancer.setCallbackFilter(new CglibSubclassingInstantiationStrategy.MethodOverrideCallbackFilter(beanDefinition));enhancer.setCallbackTypes(CALLBACK_TYPES);return enhancer.createClass();}

populateBean方法设置依赖关系

populateBean方法

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {if (bw == null) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}} else {if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {Iterator var4 = this.getBeanPostProcessors().iterator();while(var4.hasNext()) {BeanPostProcessor bp = (BeanPostProcessor)var4.next();if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}}PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;int resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);if (resolvedAutowireMode == 1) {this.autowireByName(beanName, mbd, bw, newPvs);}if (resolvedAutowireMode == 2) {this.autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = mbd.getDependencyCheck() != 0;PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}Iterator var9 = this.getBeanPostProcessors().iterator();while(var9.hasNext()) {BeanPostProcessor bp = (BeanPostProcessor)var9.next();if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;PropertyValues pvsToUse = ibp.postProcessProperties((PropertyValues)pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);}if (pvs != null) {this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);}}}

applyPropertyValues方法

    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {if (!pvs.isEmpty()) {if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());}MutablePropertyValues mpvs = null;List original;if (pvs instanceof MutablePropertyValues) {mpvs = (MutablePropertyValues)pvs;if (mpvs.isConverted()) {try {bw.setPropertyValues(mpvs);return;} catch (BeansException var18) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var18);}}original = mpvs.getPropertyValueList();} else {original = Arrays.asList(pvs.getPropertyValues());}TypeConverter converter = this.getCustomTypeConverter();if (converter == null) {converter = bw;}BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, (TypeConverter)converter);List<PropertyValue> deepCopy = new ArrayList(original.size());boolean resolveNecessary = false;Iterator var11 = original.iterator();while(true) {while(var11.hasNext()) {PropertyValue pv = (PropertyValue)var11.next();if (pv.isConverted()) {deepCopy.add(pv);} else {String propertyName = pv.getName();Object originalValue = pv.getValue();if (originalValue == AutowiredPropertyMarker.INSTANCE) {Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();if (writeMethod == null) {throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);}originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);}Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);Object convertedValue = resolvedValue;boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);if (convertible) {convertedValue = this.convertForProperty(resolvedValue, propertyName, bw, (TypeConverter)converter);}if (resolvedValue == originalValue) {if (convertible) {pv.setConvertedValue(convertedValue);}deepCopy.add(pv);} else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue)originalValue).isDynamic() && !(convertedValue instanceof Collection) && !ObjectUtils.isArray(convertedValue)) {pv.setConvertedValue(convertedValue);deepCopy.add(pv);} else {resolveNecessary = true;deepCopy.add(new PropertyValue(pv, convertedValue));}}}if (mpvs != null && !resolveNecessary) {mpvs.setConverted();}try {bw.setPropertyValues(new MutablePropertyValues(deepCopy));return;} catch (BeansException var19) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);}}}}

resolveValueIfNecessary方法

    public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {if (value instanceof RuntimeBeanReference) {RuntimeBeanReference ref = (RuntimeBeanReference)value;return this.resolveReference(argName, ref);} else if (value instanceof RuntimeBeanNameReference) {String refName = ((RuntimeBeanNameReference)value).getBeanName();refName = String.valueOf(this.doEvaluate(refName));if (!this.beanFactory.containsBean(refName)) {throw new BeanDefinitionStoreException("Invalid bean name '" + refName + "' in bean reference for " + argName);} else {return refName;}} else if (value instanceof BeanDefinitionHolder) {BeanDefinitionHolder bdHolder = (BeanDefinitionHolder)value;return this.resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());} else if (value instanceof BeanDefinition) {BeanDefinition bd = (BeanDefinition)value;String innerBeanName = "(inner bean)#" + ObjectUtils.getIdentityHexString(bd);return this.resolveInnerBean(argName, innerBeanName, bd);} else {Object valueObject;if (value instanceof DependencyDescriptor) {Set<String> autowiredBeanNames = new LinkedHashSet(4);valueObject = this.beanFactory.resolveDependency((DependencyDescriptor)value, this.beanName, autowiredBeanNames, this.typeConverter);Iterator var19 = autowiredBeanNames.iterator();while(var19.hasNext()) {String autowiredBeanName = (String)var19.next();if (this.beanFactory.containsBean(autowiredBeanName)) {this.beanFactory.registerDependentBean(autowiredBeanName, this.beanName);}}return valueObject;} else if (value instanceof ManagedArray) {ManagedArray array = (ManagedArray)value;Class<?> elementType = array.resolvedElementType;if (elementType == null) {String elementTypeName = array.getElementTypeName();if (StringUtils.hasText(elementTypeName)) {try {elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());array.resolvedElementType = elementType;} catch (Throwable var7) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, var7);}} else {elementType = Object.class;}}return this.resolveManagedArray(argName, (List)value, elementType);} else if (value instanceof ManagedList) {return this.resolveManagedList(argName, (List)value);} else if (value instanceof ManagedSet) {return this.resolveManagedSet(argName, (Set)value);} else if (value instanceof ManagedMap) {return this.resolveManagedMap(argName, (Map)value);} else if (value instanceof ManagedProperties) {Properties original = (Properties)value;Properties copy = new Properties();original.forEach((propKey, propValue) -> {if (propKey instanceof TypedStringValue) {propKey = this.evaluate((TypedStringValue)propKey);}if (propValue instanceof TypedStringValue) {propValue = this.evaluate((TypedStringValue)propValue);}if (propKey != null && propValue != null) {copy.put(propKey, propValue);} else {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error converting Properties key/value pair for " + argName + ": resolved to null");}});return copy;} else if (value instanceof TypedStringValue) {TypedStringValue typedStringValue = (TypedStringValue)value;valueObject = this.evaluate(typedStringValue);try {Class<?> resolvedTargetType = this.resolveTargetType(typedStringValue);return resolvedTargetType != null ? this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType) : valueObject;} catch (Throwable var8) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, var8);}} else {return value instanceof NullBean ? null : this.evaluate(value);}}}

resolveReference方法

applyPropertyValues方法调用了resolveValueIfNecessary方法,resolveValueIfNecessary方法调用了resolveReference方法

    private Object resolveReference(Object argName, RuntimeBeanReference ref) {try {Class<?> beanType = ref.getBeanType();Object bean;if (ref.isToParent()) {BeanFactory parent = this.beanFactory.getParentBeanFactory();if (parent == null) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean " + ref + " in parent factory: no parent factory available");}if (beanType != null) {bean = parent.getBean(beanType);} else {bean = parent.getBean(String.valueOf(this.doEvaluate(ref.getBeanName())));}} else {String resolvedName;if (beanType != null) {NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);bean = namedBean.getBeanInstance();resolvedName = namedBean.getBeanName();} else {resolvedName = String.valueOf(this.doEvaluate(ref.getBeanName()));bean = this.beanFactory.getBean(resolvedName);}this.beanFactory.registerDependentBean(resolvedName, this.beanName);}if (bean instanceof NullBean) {bean = null;}return bean;} catch (BeansException var7) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, var7);}}

相关文章:

Spring源码之IoC容器的Bean创建和依赖注入,DefaultListableBeanFactory容器为例

接上篇Spring源码之IoC容器初始化过程&#xff0c;以FileSystemXmlApplicationContext容器为例 因为FileSystemXmlApplicationContext使用的容器为DefaultListableBeanFactory&#xff0c;所以该篇基于DefaultListableBeanFactory的实现分析依赖注入过程。 目录获取Bean的总体流…...

解决小程序页面scroll-view块自身滑动问题

修改scroll-view的style样式 本来通过函数限制高度 style"margin-top:200rpx;"height: calc(100vh - 200rpx - env(safe-area-inset-bottom));会出现整个scroll-view块位置不固定滑动里面的内容后&#xff0c;自己本身在整个页面内上移&#xff0c;将样式改为&#…...

PowerCommand康明斯发电机控制屏维修HMI211

康明斯柴油发电机的监控系统分为普通机组控制屏和智能化机组控制界面。普通操作界面实用于普通的康明斯柴油发电机的控制&#xff0c;康明斯柴油发电机的起动与停止、供电与断电、状态调整等均由手动操作&#xff1b;自动化康明斯柴油发电机控制系统适合于智能化康明斯柴油发电…...

ELK + Kafka 测试

配置file beat输出到 Kafkalogstash服务器从kafka获取数据并输出到es集群在es集群上查看索引kibana界面添加索引查看数据1.配置file beat输出到 Kafka 1.1 Filebeat机器配置数据采集和输出目标 做好域名解析 # vim /usr/local/filebeat/filebeat.yml # 修改输出目标为kafka…...

迁移系统:换电脑或者硬盘转移磁盘文件的方法!

为什么要将操作系统迁移到新驱动&#xff1f; “将操作系统转移到新驱动您好&#xff0c;我刚刚为我的台式机订购了一个新的2TB希捷Barracuda硬盘&#xff0c;我想知道如何将我的Windows 10操作系统与我下载的其他一些软件一起转移过来。我使用新的/大的硬盘&#xff0c;然…...

职场性别报告,男女薪酬仍有差距,男性平均薪酬比女性高29.7%

性别是否影响职业&#xff1f;女性求职比男性更加困难&#xff1f;男性薪酬比女性更有优势&#xff1f;人们一说到警察、建筑师通常会想到高大魁梧的男性形象&#xff0c;一说到幼师、护士往往想到的都是温柔的女性形象&#xff0c;职业好似与性别挂钩&#xff1b;女性求职通常…...

5-Azidopentanoic acid,79583-98-5,5-Azidopentanoic COOH具有高效稳定,高特异性

5-Azidopentanoic acid&#xff0c;5-Azidopentanoic COOH&#xff0c;5-叠氮基戊酸产品规格&#xff1a;1.CAS号&#xff1a;79583-98-52.分子式&#xff1a;C5H9N3O23.分子量&#xff1a;143.074.包装规格&#xff1a;1g&#xff0c;5g&#xff0c;10g&#xff0c;包装灵活&a…...

滴滴前端高频react面试题汇总

说说 React组件开发中关于作用域的常见问题。 在 EMAScript5语法规范中&#xff0c;关于作用域的常见问题如下。 &#xff08;1&#xff09;在map等方法的回调函数中&#xff0c;要绑定作用域this&#xff08;通过bind方法&#xff09;。 &#xff08;2&#xff09;父组件传递…...

能在软路由docker给部署搭建teamsperk服务器么?并且设置好ddns

参考链接(4条消息) 【个人学习总结】使用docker搭建Teamspeak服务器_blcurtain的博客-CSDN博客_teamspeak3 docker(⊙﹏⊙)哎呀&#xff0c;崩溃啦&#xff01; (tdeh.top)TeamSpeak服务器搭建与使用 - 缘梦の镇 (cmsboy.cn)Openwrt X86 docker运行甜糖-软路由,x86系统,openwrt…...

应用统计学实验1-蒙特卡罗方法求解定积分

目录 1. 用蒙特卡罗方法计算定积分(随机投点法) 2. 用蒙特卡罗方法计算定积分(平均值法)...

用Pyhon编写一个属于自己的nmap

用Pyhon编写一个属于自己的nmap 文章目录用Pyhon编写一个属于自己的nmap导入 socket 模块&#xff0c;确定目标主机 IP 或域名以及需要扫描的端口列表开始扫描、扫描每个端口创建一个 socket 对象&#xff0c;用于建立 TCP 连接尝试连接目标主机的指定端口如果连接成功&#xf…...

电信网上用户资管理系统的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;在对目前市面上已经拥有的营业厅功能分析和整理后&#xff0c;为了保证营业厅中多种功能的分层次处理设计了一个的电信网上用户自管理系统&#xff0c;以web页面方式实现了与用户的交互&#xff0c;同时保证了移动电话计费管理系统…...

js函数柯里化-面试手写版

概念 用我自己的话来总结一下&#xff0c;函数柯里化的意思就是你可以一次传很多参数给curry函数&#xff0c;也可以分多次传递&#xff0c;curry函数每次都会返回一个函数去处理剩下的参数&#xff0c;一直到返回最后的结果。 实例 这里还是举几个例子来说明一下&#xff1…...

【学习笔记】深入理解JVM之类加载机制

【学习笔记】深入理解JVM之类加载机制 以后基本上都在语雀上面更新&#xff0c;大家有兴趣可以看看嗷&#xff01; 首发地址&#xff1a; 知识库 文章流程图&#xff1a; 1、概述 首先我们先来看看一个 Class 文件所需要经过的一个流程图&#xff1a; 而我们今天要重点需讲的…...

驾驭云端之风1——Spring Cloud微服务架构实践指南

本博客纯属个人总结&#xff0c;非原创。喜欢技术交流的&#xff0c;可关注博主&#xff0c;武汉有后端开发群&#xff0c;可支持内推&#xff0c;了解武汉行情等。 前沿 优惠卷平台项目的整体功能和模块&#xff0c;以及每个功能点的技术选型和背后的依据。 搭建一个简化版的…...

【计算机网络基础】

计算机网络基础网络的基本概念网络互联网IP地址MAC地址网络协议网络分层模型网络应用程序的通信流程网络的基本概念 网络 网络是由若干结点和链接这些结点的链路组成&#xff0c;网络中的结点可以是计算机&#xff0c;交换机&#xff0c;路由器等设备 网络设备&#xff1a;交…...

grep与nm命令的应用

相关知识拓展 Linux中grep的命令使用 在Linux中&#xff0c;grep可用于shell脚本&#xff0c;因为grep通过返回一个状态值来说明搜索状态&#xff0c;如果模板搜索成功&#xff0c;则返回0&#xff0c;如果搜索不成功&#xff0c;则返回1&#xff0c;如果搜索的文件不存在&…...

【linux】软硬链接

在linux中在磁盘中定位文件并不是根据文件名而是根据文件的inode&#xff0c;一个文件对应一个inode但是一个inode可以对应多个文件。硬链接硬链接是通过索引节点进行的链接。在Linux中&#xff0c;多个文件指向同一个索引节点是允许的&#xff0c;像这样的链接就是硬链接。硬链…...

骨传导蓝牙耳机排行,盘点几款性能不错的骨传导耳机

随着蓝牙耳机的普及&#xff0c;骨传导耳机也越来越受到欢迎&#xff0c;很多人也都开始在了解并尝试骨传导耳机。相比于其他类型耳机&#xff0c;在舒适度、安全方面有一定优势。尤其是在户外运动时&#xff0c;或者长时间佩戴运动时&#xff0c;使用骨传导耳机可以避免耳朵因…...

ARM中的寄存器

ARM工作模式 ARM有8个基本的工作模式 User 非特权模式&#xff0c;一般在执行上层的应用程序时ARM处于该模式FIQ 当一个高优先级中断产生后ARM将进入这种模式IRQ 当一个低优先级中断产生后ARM将进入这种模式SVC 当复位或执行软中断指令后ARM将进入这种模式Abort 当产生存取异常…...

git操作修改历史版本指定tag标签的代码,并发布新标签

场景&#xff1a; 当项目已经迭代多个版本之后&#xff0c;突然发现旧版本0.0.1出现了紧急bug&#xff0c;需要及时处理&#xff1b; 如果直接用新版本替换上去是存在极大隐患的&#xff0c;且时间来不及&#xff1b; 所以需要直接在0.0.1版本的基础上去修复bug&#xff0c;然…...

SpringMVC——响应处理(1)【包含源码分析】

Controller public class JsonReturnController {ResponseBodyGetMapping("/getPet")public Pet getPet(){Pet petnew Pet();pet.setAge(5);pet.setName("lily");return pet;} }项目启动后 浏览器输入 http://localhost:8080/getPet 。 debug DispatcherS…...

Normalization

1、BN&#xff08;Batch Normalization&#xff09; 深度网络参数训练时内部存在协方差偏移&#xff08;Internal Covariate Shift&#xff09;现 象&#xff1a;深度网络内部数据分布在训练过程中发生变化的现象。训练深度网络时&#xff0c;神经网络隐层参数更新会导致网络输…...

27K测试老鸟分享自己6年面试心得,四种公司、四种问题…

这里总结了下自己今年的面试情况 先说一下自己的个人情况&#xff0c;普通二本计算机专业毕业&#xff0c;懂python&#xff0c;会写脚本&#xff0c;会selenium&#xff0c;会性能。趁着金三银四跳槽季&#xff0c;面试字节跳动测试岗技术面都已经过了&#xff0c;本来以为是…...

中小企业数字化自动化转型的方法

自动化是我们国内未来的趋势。智能制造的实现主要依托两个基础能力&#xff0c;一个是工业制造技术&#xff0c;另一个就是工业互联网。而自动化是工业制造技术的重要组成部分&#xff0c;是高度智能制造装备的核心部分&#xff0c;与承接着制造单元与工业互联网这两大核心。懂…...

利用GPT-3 Fine-tunes训练专属语言模型

利用GPT-3 Fine-tunes训练专属语言模型 文章目录什么是模型微调&#xff08;fine-tuning&#xff09;&#xff1f;为什么需要模型微调&#xff1f;微调 vs 重新训练微调 vs 提示设计训练专属模型数据准备清洗数据构建模型微调模型评估模型部署模型总结什么是模型微调&#xff0…...

kubeadm方式安装k8s高可用集群(版本1.26x)

K8S官网&#xff1a;https://kubernetes.io/docs/setup/ 高可用Kubernetes集群规划 配置备注系统版本CentOS 7.9Docker版本20.10.xPod网段172.16.0.0/12Service网段10.103.10.0/16 主机IP说明k8s-master01 ~ 03192.168.77.101 ~ 103master节点 * 3k8s-master-lb192.168.77.2…...

分享5款堪称神器的免费软件,建议先收藏再下载

转眼间新年已经过去一个月了&#xff0c;最近陆陆续续收到好多小伙伴的咨询&#xff0c;这边也是抓紧整理出几个好用的软件&#xff0c;希望可以帮到大家。 1.电脑安全管家——火绒 火绒是一款电脑安全软件&#xff0c;病毒库更新及时&#xff0c;界面清晰干净&#xff0c;没…...

【项目实战】从0开始入门JDK源码 - LinkedList源码

一、源码位置 一般来说IDEA配置好JDK以后 ,JDK的源码其实也配置好了,本文是基于JDK1.8的源码说明 rt - java - util - LinkedList 二、 继承关系图 LinkedList public class LinkedList<E>extends AbstractSequentialList<E>implements...

Polygon zkEVM的gas定价

1. 引言 所有的zkEVM都存在一个有趣的问题&#xff1a; 如何给gas定价&#xff1f; 在Ethereum Virtual Machine (EVM)中&#xff0c;gas通过为每个计算设置economic fee&#xff0c;来保持网络安全。恶意行为&#xff0c;如拒绝服务&#xff08;DoS&#xff09;攻击&#x…...

河南省建设网站/百度投诉中心24人工客服

一会修改转载于:https://www.cnblogs.com/yedaodao/archive/2013/02/20/2919272.html...

环球影城漫游卡持卡人是什么意思/东莞网站seo技术

2945:拦截导弹 查看 提交 统计 提示 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 某国为了防御敌国的导弹袭击&#xff0c;开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷&#xff1a;虽然它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每一发炮弹都…...

杭州网页模板建站/怎么开自己的网站

Mr. Kitayutas Colorful Graph 并查集不仅可以用于一维&#xff0c;也可以用于高维。 此题的大意是10W个点10W条边&#xff08;有多种颜色&#xff09;&#xff0c;10W个询问&#xff1a;任意两个节点之间可以由几条相同颜色的路径连通。 这里要用到高维的并查集&#xff0c;定…...

百度推广 手机网站/国际军事最新头条新闻

一、学会如何读一个JavaWeb项目源代码步骤&#xff1a;表结构->web.xml->mvc->db->spring ioc->log->代码先了解项目数据库的表结构&#xff0c;这个方面是最容易忘记的&#xff0c;有时候我们只顾着看每一个方法是怎么进行的&#xff0c;却没有去了解数据库…...

做一名优秀网站设计师计划/东莞seo排名扣费

SpringBoot2.x系列教程53--NoSQL之SpringBoot整合Neo4j 作者&#xff1a;一一哥 一. Spring Boot中整合Neo4j 我们上一章节简单介绍了Neo4j及其安装配置过程&#xff0c;这节带大家学习在Spring Boot中整合Neo4j. 1. 创建web项目 我们按照之前的经验&#xff0c;创建一个w…...

网站站内交换链接怎么做/刷钻业务推广网站

现有一表&#xff0c;其内容既有中文也有英文字符&#xff0c;但在统计该字段内容中最大长度时&#xff0c;由于len&#xff08;&#xff09;函数统计的是字符而不是字节&#xff0c;使得得到的长度无法达到统一标准。请问如何解决这样的问题。表的内容如下&#xff1a; table…...