getBean整体逻辑

AbstractBeanFactory#doGetBean方法

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {//参数传进来的name,可能是一个别名,也可能是&开头的name//1.别名,alias,需要重定向出一个真实的beanName//2、&name,说明要获取的对象是一个FactoryBean对象//FactoryBean:如果某个bean的配置非常复杂,使用Spring管理不容易,不灵活,想使用直接编码的方式去构建//那么可以提供构建该bean实例的工厂,这个工厂就是FactoryBean接口实现类。FactoryBean接口实现类需要使用Spring管理。//这里涉及到两种对象,一种是FactoryBean接口实现类(IOC管理的),另一种就是FactoryBean接口内部管理的对象、//如果要拿到FactoryBean接口实现类,使用getBean时传的beanName需要带 & 开头//如果要拿到FactoryBean内部管理的对象,直接传beanName不需要带 &String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.//到缓存中获取共享单实例。这里是第一次getSingleton(beanName)Object sharedInstance = getSingleton(beanName);//CASE1:缓存中有对应的数据,缓存中的数据可能是普通单实例,也可能是factoryBean,所以需要根据name来判断返回的数据if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}//这里为什么又要套?不直接拿去用//因为拿到的对象可能是普通的单实例,也可能是FactoryBean//如果是FactoryBean,还需要进行处理,主要看是否待&//带&,说明拿的就是FactoryBean,否则拿的是普通beanbean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}//CASE2:缓存中没有数据,需要自己创建else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.//1、原型循环依赖问题判断//举个例子://prototypeA -> B, B -> prototypeA//1、会向正在创建中的原型集合中添加一个字符串"prototypeA"//2、创建prototypeA对象,只是一个早期对象//3、处理prototypeA的依赖,发现A依赖了B对象//4、触发了Spring.getBean("B")的操作//5、根据B的构造方法反射创建出来了B的早期实例//6、Spinrg处理B对象的依赖,发现了依赖A//7、Spring转头去获取A,Spring.getBean("prototypeA")//8、条件会返回true,最终抛出异常,算是结束了循环依赖注入if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType != null) {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}else {return (T) parentBeanFactory.getBean(nameToLookup);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {//2、获取合并md信息//为什么需要合并?//因为bd支持继承,子bd可以继承到父bd的所有信息RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//判断当前bd是否为抽象bd,抽象bd不能创建实例,只能父bd让子bd继承checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.//3.depends-on属性处理..//<bean name="A" depends-on="B" ... />//<bean name="B" .../>//循环依赖问题//<bean name="A" depends-on="B" ... />//<bean name="B" depends-on="A" .../>//Spring是处理不了这种情况的,需要报错..//Spring需要发现这种情况的产生。//怎么发现呢? 依靠两个Map,一个map是 dependentBeanMap 另一个是 dependenciesForBeanMap//1. dependentBeanMap 记录依赖当前beanName的其他beanName//2. dependenciesForBeanMap 记录当前beanName依赖的其它beanName集合String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {//判断循环依赖if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//假设<bean name="A" depends-on="B" ... />//dep:B,beanName:A//以B为视角 dependentBeanMap {"B":{"A"}}//以A为视角 dependenciesForBeanMap {"A" :{"B"}}registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// Create bean instance.//CASE-SINGLETON的情况if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});//这里为啥不直接返回,还调用getObjectForBeanInstance//因为可能当前的bean是factoryBean,但是要的name带着&,此时需要的是factoryBean内部管理的对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}//CASE-PROTOTYPE的情况else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {//记录当前线程正在创建的原型对象的beanNamebeforePrototypeCreation(beanName);//创建对象prototypeInstance = createBean(beanName, mbd, args);}finally {//创建完成,移除当前线程正在创建的原型对象的beanNameafterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}//CASE-OTHER的情况(不管)else {String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");}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, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {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",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;}

第一次getSingleton的逻辑,第二个参数是boolean类型

 //allowEarlyReference:是否运行拿到早期的引用@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lock//到一级缓存获取对应的单实例对象Object singletonObject = this.singletonObjects.get(beanName);//条件1成立:// 1.说明单实例没有在一级缓存// 2.单实例正在创建中,当前发生循环依赖了//什么是循环依赖:A <=> B//单实例有几种循环依赖?//1、构造方法循环依赖(无解)//2、setter循环依赖(有解,靠3级缓存)//3级缓存怎么解决setter循环依赖?//A -> B, B -> A//1.假设Spring先实例化A,首先先拿到A的构造方法,进行反射创建出来A的早期实例对象,这个时候,这个早起对象被包装成ObjectFactory对象,放到了3级缓存//2.处理A的依赖数据,检查发现A依赖了B对象,接下来,Spring会根据B类型到容器中去getBean(B.class),这里就递归了//3.拿到B的构造方法,反射创建出B的早期对象,把B包装成ObjectFactory对象,放到3级缓存//4.处理B的依赖数据,检查发现,B依赖了A对象,所以接下来根据A类型去容器getBean(A.class)去拿A对象,这里又递归了//5.程序还会走到当前这个方法,这里是第二次getBean 拿A了//6.条件1次成立,条件2成立if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);//检查二级缓存//条件成立:说明二级缓存没有,到三级缓存检查//Spring为什么需要3级缓存存在,而不只有2级缓存呢?//AOP,靠得是动态代理实现//静态代理:需要手动写代码,实现一个新的java类,这个java类和需要代理的对象 实现了同一个接口,代理类内部维护了被代理对象(原生)代理类,//在调用原生对象前后,可以加一些逻辑,代理对象和被代理对象是两个不同的对象,内存地址一定是不一样的。//动态代理:不需要人为写代码了,而是依赖字节码框架动态生成class字节码文件,然后jvm再加载,然后也一样,也是去new代理对象,//这个代理对象没有什么特殊的,也是内部保留了原生对象,然后在调用原生对象前后 实现的 字节码增强。//第3级缓存存在这里有什么目的?//第3级缓存里面保存的对象工厂,这个对象工厂内部保留着最原生的对象引用,ObjectFactory的实现类,getObject()方法,他需要考虑一个问题//它到底返回的是原生的对象,还是增强后的对象?//getObject会判断当前这个早期实例是否需要增强,如果是,那么提前完成动态代理增强,返回代理对象。否则,返回原生对象if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);//条件成立:3级缓存存在数据。这里涉及到缓存升级if (singletonFactory != null) {singletonObject = singletonFactory.getObject();//向22级缓存存数据、将3级缓存抹除this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}

这里的代码处理了setter循环依赖,并且解决了循环依赖,原因就在于提前暴露对象到了第3级缓存中,在接下来发现循环依赖的时候,可以从第3级缓存中获取。

 //allowEarlyReference:是否运行拿到早期的引用@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lock//到一级缓存获取对应的单实例对象Object singletonObject = this.singletonObjects.get(beanName);//条件1成立:// 1.说明单实例没有在一级缓存// 2.单实例正在创建中,当前发生循环依赖了//什么是循环依赖:A <=> B//单实例有几种循环依赖?//1、构造方法循环依赖(无解)//2、setter循环依赖(有解,靠3级缓存)//3级缓存怎么解决setter循环依赖?//A -> B, B -> A//1.假设Spring先实例化A,首先先拿到A的构造方法,进行反射创建出来A的早期实例对象,这个时候,这个早起对象被包装成ObjectFactory对象,放到了3级缓存//2.处理A的依赖数据,检查发现A依赖了B对象,接下来,Spring会根据B类型到容器中去getBean(B.class),这里就递归了//3.拿到B的构造方法,反射创建出B的早期对象,把B包装成ObjectFactory对象,放到3级缓存//4.处理B的依赖数据,检查发现,B依赖了A对象,所以接下来根据A类型去容器getBean(A.class)去拿A对象,这里又递归了//5.程序还会走到当前这个方法,这里是第二次getBean 拿A了//6.条件1次成立,条件2成立if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);//检查二级缓存//条件成立:说明二级缓存没有,到三级缓存检查//Spring为什么需要3级缓存存在,而不只有2级缓存呢?//AOP,靠得是动态代理实现//静态代理:需要手动写代码,实现一个新的java类,这个java类和需要代理的对象 实现了同一个接口,代理类内部维护了被代理对象(原生)代理类,//在调用原生对象前后,可以加一些逻辑,代理对象和被代理对象是两个不同的对象,内存地址一定是不一样的。//动态代理:不需要人为写代码了,而是依赖字节码框架动态生成class字节码文件,然后jvm再加载,然后也一样,也是去new代理对象,//这个代理对象没有什么特殊的,也是内部保留了原生对象,然后在调用原生对象前后 实现的 字节码增强。//第3级缓存存在这里有什么目的?//第3级缓存里面保存的对象工厂,这个对象工厂内部保留着最原生的对象引用,ObjectFactory的实现类,getObject()方法,他需要考虑一个问题//它到底返回的是原生的对象,还是增强后的对象?//getObject会判断当前这个早期实例是否需要增强,如果是,那么提前完成动态代理增强,返回代理对象。否则,返回原生对象if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);//条件成立:3级缓存存在数据。这里涉及到缓存升级if (singletonFactory != null) {singletonObject = singletonFactory.getObject();//向2级缓存存数据、将3级缓存抹除this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}

具体逻辑还需要结合其他代码,后面再详细解释

重点

单例构造函数循环依赖

             //CASE-SINGLETON的情况if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});//这里为啥不直接返回,还调用getObjectForBeanInstance//因为可能当前的bean是factoryBean,但是要的name带着&,此时需要的是factoryBean内部管理的对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}

具体的获取单实例和检测循环依赖的方法,都在getSingleton中,要注意,这里传入的第二个参数是ObjectFactory的实现类。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {//容器销毁时,会设置这个属性为true,这个时候就不能参加bean实例了,直接抛出异常if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}//面试重灾区://将当前beanName放入到"正在创建单实例集合",放入成功,说明没有产生循环依赖,失败说明产生循环依赖//举个例子:构造方法参数依赖//A -> B, B -> A//1、加载A,根据A的构造方法,想要去实例化A对象,但是发现A的构造方法有一个参数是B(在这之前,已经向这个集合添加了{A})//2、因为A的构造方法依赖了B,所以触发了加载B的逻辑//3、加载B,根据B的构造方法,想要去实例化B对象,但是发现B的构造方法有一个参数是A(在这之前,已经添加了{A,B})//4、因为B的构造方法依赖A,所以再次触发了加载A的逻辑//5、再次来到getSingleton方法里,调用beforeSingletonCreation(A),添加失败,抛出异常//结束beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}//将beanName从当前正在创建的bean的集合移除afterSingletonCreation(beanName);}if (newSingleton) {//添加到缓存addSingleton(beanName, singletonObject);}}return singletonObject;}}

每次通过构造函数创建bean实例之前,也就是在走ObjectFactory.getObject()逻辑之前,会先记录当前要创建的beanName到set集合中,也就是beforeSingletonCreation的逻辑,加入失败说明之前现在要创建这个bean,之前也要创建这个bean,也就是发生了循环依赖。来看看这段代码逻辑

 protected void beforeSingletonCreation(String beanName) {//条件成立:发生循环依赖if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}}

最终会删除记录

 protected void afterSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");}}

原型循环依赖

             //CASE-PROTOTYPE的情况else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {//记录当前线程正在创建的原型对象的beanNamebeforePrototypeCreation(beanName);//创建对象prototypeInstance = createBean(beanName, mbd, args);}finally {//创建完成,移除当前线程正在创建的原型对象的beanNameafterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}

这段代码就是prototype实例的创建,并且会对当前创建的beanName记录到threadLocal中,再次创建走doGetBean的逻辑时候,会被检测到,当前创建的bean之前已经被要求创建了,说明发送了循环依赖,我们来看看这段记录和检测的代码。
记录的代码逻辑:

 protected void beforePrototypeCreation(String beanName) {//prototypesCurrentlyInCreation:ThreadLocal<Object>Object curVal = this.prototypesCurrentlyInCreation.get();//记录当前线程正在创建的bean,并且还没有创建完的beanif (curVal == null) {this.prototypesCurrentlyInCreation.set(beanName);}else if (curVal instanceof String) {Set<String> beanNameSet = new HashSet<>(2);beanNameSet.add((String) curVal);beanNameSet.add(beanName);this.prototypesCurrentlyInCreation.set(beanNameSet);}else {Set<String> beanNameSet = (Set<String>) curVal;beanNameSet.add(beanName);}}

检测的代码逻辑:

         //1、原型循环依赖问题判断//举个例子://prototypeA -> B, B -> prototypeA//1、会向正在创建中的原型集合中添加一个字符串"prototypeA"//2、创建prototypeA对象,只是一个早期对象//3、处理prototypeA的依赖,发现A依赖了B对象//4、触发了Spring.getBean("B")的操作//5、根据B的构造方法反射创建出来了B的早期实例//6、Spinrg处理B对象的依赖,发现了依赖A//7、Spring转头去获取A,Spring.getBean("prototypeA")//8、条件会返回true,最终抛出异常,算是结束了循环依赖注入if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}

在进入具体的创建bean的实例逻辑之前,会先判断是否存在prototype循环依赖。

 protected boolean isPrototypeCurrentlyInCreation(String beanName) {Object curVal = this.prototypesCurrentlyInCreation.get();return (curVal != null &&(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));}

depends-on循环依赖

             //3.depends-on属性处理..//<bean name="A" depends-on="B" ... />//<bean name="B" .../>//循环依赖问题//<bean name="A" depends-on="B" ... />//<bean name="B" depends-on="A" .../>//Spring是处理不了这种情况的,需要报错..//Spring需要发现这种情况的产生。//怎么发现呢? 依靠两个Map,一个map是 dependentBeanMap 另一个是 dependenciesForBeanMap//1. dependentBeanMap 记录依赖当前beanName的其他beanName//2. dependenciesForBeanMap 记录当前beanName依赖的其它beanName集合String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {//判断循环依赖if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//假设<bean name="A" depends-on="B" ... />//dep:B,beanName:A//以B为视角 dependentBeanMap {"B":{"A"}}//以A为视角 dependenciesForBeanMap {"A" :{"B"}}registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}

depends-on的逻辑是在必须走在单实例和prototype逻辑之前。这里最关键的其实就是循环依赖问题,需要创建两个map,具体看代码:

public void registerDependentBean(String beanName, String dependentBeanName) {String canonicalName = canonicalName(beanName);synchronized (this.dependentBeanMap) {Set<String> dependentBeans =this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));if (!dependentBeans.add(dependentBeanName)) {return;}}synchronized (this.dependenciesForBeanMap) {Set<String> dependenciesForBean =this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));dependenciesForBean.add(canonicalName);}}

dependentBeans和dependenciesForBean,前者记录被谁依赖,后者记录依赖了谁。

检测的代码逻辑:

 protected boolean isDependent(String beanName, String dependentBeanName) {synchronized (this.dependentBeanMap) {return isDependent(beanName, dependentBeanName, null);}}
 //<bean name="A" depends-on="B"></bean>//<bean name="B" depends-on="A"></bean>private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {if (alreadySeen != null && alreadySeen.contains(beanName)) {return false;}String canonicalName = canonicalName(beanName);//{"A"}Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans == null) {return false;}//{"A"}包含了A,所以条件成立,这里会返回true,表示产生了循环依赖if (dependentBeans.contains(dependentBeanName)) {return true;}//这里是为了处理不是直接的循环依赖,而是 a -> b, b -> c, c -> a的情况for (String transitiveDependency : dependentBeans) {if (alreadySeen == null) {alreadySeen = new HashSet<>();}alreadySeen.add(beanName);if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {return true;}}return false;}

假设一个场景:A depends-on B;B depends-on A
那么在创建A的时候,会先记录两个map:dependentBeans:{B:{A}} 和 dependenciesForBean:{A:{B}}
然后就去走getBean的逻辑先去创建B,B对象来到doGetBean的逻辑的时候,发现B要依赖对象A,可是之前已经记录了B被对象A依赖,此时就发生了循环依赖,并且被检测到了,直接抛出异常。

小结

getBean的主要逻辑:
1、先从缓存中获取bean实例,获取不到那么就根据需要获取的bean实例是单实例还是prototype去走对应的逻辑
2、在获取单实例或者prototype实例之前,会先处理depends-on依赖的实例,这里涉及到了循环依赖问题,不能解决,只能检测并且抛出异常。大概的做法就是提供两个map,一个是谁依赖了我,一个是我依赖了谁,等发现存在依赖bean的时候会去走getBean的逻辑,发现我要依赖的bean,它已经依赖了我,这个时候抛出异常。
3、单实例的获取,主要就是走getSingleton的逻辑,并且提供了一个createBean的ObjectFactory。getSingleton的逻辑首先会去一级缓存获取bean实例,没有拿到那么就需要创建单实例了,创建单实例可能存在构造方法循环依赖,那么就要检测到循环依赖,抛出异常了。具体的操作就是,1、先记录现在要创建的beanName存放到set集合中,存放成功则说明没有发送循环依赖,失败则说明发送了循环依赖;2、存放成功,那么就去走ObjectFactory.getObject(),这里会去走createBean的逻辑;3、最终将创建的bean存放到一级缓存中,并且从set集合中删除记录的beanName
4、在走对应的逻辑之前,都会先判断是否发生prototype循环依赖,其实判断机制实现的前置内容都是在创建bean之前,会记录当前正在创建的beanName到threadLocal中,然后再去创建bean,最后再从threadLocal中删除记录的beanName

核心逻辑

createBean整体逻辑

 @Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.//判断当前mbd中的class是否已经加载到jvm中,如果未加载,则使用类加载器加载到jvm中,,并且返回class对象Class<?> resolvedClass = resolveBeanClass(mbd, beanName);//条件1:说明拿到了mbd实例化对象时的真实Class对象//条件2:成立说明mbd在resolveBeanClass之前是没有Class对象的//条件3:条件成立,说明mbd中有classNameif (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.//这里的代码直接跳过不看try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.//跳过后处理器返回一个代理实例对象...注意这里的代理对象不是springAop逻辑实现的地方//instantiation:实例化之前的解析。不要和init混淆,init已经创建完成了//后处理器调用点:创建实例之前的调用点Object bean = resolveBeforeInstantiation(beanName, mbdToUse);//条件成立:形成一个短路操作,直接返回。一般不会直接返回,不是正常的执行逻辑if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {//核心方法:创建bean实例对象,并且声明周期的动作大部分在这里Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

resolveBeforeInstantiation中执行了一系列后置处理器,正常是不会直接走这一步逻辑后就返回bean实例的。但是可以手动注入自定义的后置处理器从而直接返回一个bean。

 @Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.//条件2成立:说明存在InstantiationAwareBeanPostProcessorif (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {//执行instantiation后处理器bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {//执行init后处理器bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}

doCreateBean整体逻辑

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//包装对象,内部最核心的就是真实的bean实例。另外提供的额外的接口,如:属性访问器BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//创建真实的bean实例,并且将其包装到beanWrapper实例中instanceWrapper = createBeanInstance(beanName, mbd, args);}//获取创建出来的真实的beanObject bean = instanceWrapper.getWrappedInstance();//获取创建出来的真实的bena的类型Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {//记录实例类型mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {//每个bd只能执行一次applyMergedBeanDefinitionPostProcessorsif (!mbd.postProcessed) {try {//后处理器调用点:合并bd信息,因为接下来就是populate处理依赖了。(保存@Autowired,@Value,@Inject注解信息到缓存)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.//决定了早期实例是否要暴露到第3级缓存中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");}//参数2:将bean包装成一个ObjectFactory,getObject调用的是getEarlyBeanReference的逻辑addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {//处理当前实例的依赖数据的,依赖注入在这一步完成(出来普通的property还有@Autowired,@Value,@Inject信息的注入)populateBean(beanName, mbd, instanceWrapper);//生命周期中初始化方法的调用exposedObject = initializeBean(beanName, exposedObject, mbd);}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);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {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 " +"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {//判断当前bean是否需要注册析构回调,即容器销毁的时候,会执行bean的销毁方法registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

进入createBeanInstance整体逻辑

createBeanInstance整体逻辑

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.//返回mbd中的class对象Class<?> beanClass = resolveBeanClass(mbd, beanName);//判断是否能够创建beanif (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());}//5.x新特性Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}//bean标签中配置了factory-method的情况处理,这个分支也很复杂,跳过if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...//表示bd对应的构造信息是否已经解析成可以反射调用的构造方法method信息了boolean resolved = false;//是否自动匹配构造方法boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {//条件成立:说明bd的构造信息已经转换为可以反射调用的bd信息了if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;//resolvedConstructorOrFactoryMethod 有值时,且构造方法有参数时,那么可以认为这个字段值就是true//只有什么情况下这个字段是false呢?//1、resolvedConstructorOrFactoryMethod == null//2、resolvedConstructorOrFactoryMethod 表示的是默认的构造方法,无参构造方法autowireNecessary = mbd.constructorArgumentsResolved;}}}//下面的就是本方法的核心那部分if (resolved) {if (autowireNecessary) {//有参数,那么就需要根据参数去匹配合适的构造方法//拿出当前Class的所有构造器,然后根据参数信息去匹配出最优的选项,执行最优的构造器创建出实例return autowireConstructor(beanName, mbd, null, null);}else {//无参构造方法return instantiateBean(beanName, mbd);}}// Candidate constructors for autowiring?//典型应用:@Autowired 注解打在了构造器方法上Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);//条件1成立:后处理器指定了构造方法数组//条件2:autowireMode一般情况是no//条件3:条件成立,说明配置的bean标签下存在constructor-arg//条件4:getBean时,args有参数if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// Preferred constructors for default construction?ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// No special handling: simply use no-arg constructor.//未指定构造参数,未设计偏好,使用默认的无参构造方法创建实例return instantiateBean(beanName, mbd);}

这个方法就是选择哪个构造函数的,往里深了跟就是选择最优的构造函数,很繁琐。抓住主要逻辑就可以。走出这个方法就得到了早期bean实例

autowireConstructor

这里大部分内容都在找到最匹配的构造函数对象。太复杂了,就记住一个构造器优先级:public > 非public,参数多 > 参数少

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {BeanWrapperImpl bw = new BeanWrapperImpl();//1、向wrapper中注册conversion//2、向wrapper中注册属性编辑器this.beanFactory.initBeanWrapper(bw);//实例化反射调用的构造器Constructor<?> constructorToUse = null;//实例化时真正去用的参数持有对象ArgumentsHolder argsHolderToUse = null;//实例化时使用的参数Object[] argsToUse = null;if (explicitArgs != null) {argsToUse = explicitArgs;}else {//表示构造器参数需要做转换的参数引用Object[] argsToResolve = null;synchronized (mbd.constructorArgumentLock) {constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;//条件1成立:表示当前bd生成实例不是第一次,缓存中有解析好的构造器方法可以直接拿来反射调用...//mbd.constructorArgumentsResolved 条件成立,说明构造器参数已经解析过了if (constructorToUse != null && mbd.constructorArgumentsResolved) {// Found a cached constructor...argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {argsToResolve = mbd.preparedConstructorArguments;}}}//条件成立:说明resolvedConstructorArguments(argsToUse)为null,preparedConstructorArguments(argsToResolve)一定有值if (argsToResolve != null) {//可以认为preparedConstructorArguments不是完全解析好的参数,还需要进一步解析argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);}}//条件成立:说明缓存机制没有生效,进入大if逻辑,进行构造器匹配逻辑//条件不成立:缓存机制生效,跳过大if逻辑,直接去创建bean实例if (constructorToUse == null || argsToUse == null) {// Take specified constructors, if any.//chosenCtors  什么时候有数据呢?//构造方法上有@Autowired注解时,chosenCtors才会有数据Constructor<?>[] candidates = chosenCtors;//条件成立:说明外部调用当前autowireConstructs方法时,并没有提供好可选用的构造器,咱们需要通过Class拿到构造器信息if (candidates == null) {Class<?> beanClass = mbd.getBeanClass();try {//isNonPublicAccessAllowed 返回true,表示非public的构造器也可以访问,否则只能访问public的构造方法candidates = (mbd.isNonPublicAccessAllowed() ?beanClass.getDeclaredConstructors() : beanClass.getConstructors());}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Resolution of declared constructors on bean Class [" + beanClass.getName() +"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);}}//执行到这里,可选用那些的构造方法已经准备好了,具体使用哪个还不清楚//条件成立:说明当前实例化使用的是无参构造器if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {Constructor<?> uniqueCandidate = candidates[0];//条件成立:说明这个构造器就是无参构造器,可以实例化了if (uniqueCandidate.getParameterCount() == 0) {synchronized (mbd.constructorArgumentLock) {mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;mbd.constructorArgumentsResolved = true;mbd.resolvedConstructorArguments = EMPTY_ARGS;}//使用无参构造器,完成反射调用,并且设置到bw中bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));return bw;}}// Need to resolve the constructor.boolean autowiring = (chosenCtors != null ||mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);//表示已经完成解析后的构造器参数值ConstructorArgumentValues resolvedValues = null;//表示构造器参数个数int minNrOfArgs;if (explicitArgs != null) {minNrOfArgs = explicitArgs.length;}else {ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();//表示已经完成解析后的构造器参数值resolvedValues = new ConstructorArgumentValues();//表示构造器参数个数minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}//可选用的构造器数组排序//排序规则:public > 非public > 参数多的 > 参数少的AutowireUtils.sortConstructors(candidates);//这个参数值越小,表示当前构造器参数列表类型和构造器参数匹配度越高,反之越低int minTypeDiffWeight = Integer.MAX_VALUE;//模棱两可的构造器?假设第二个构造器的diffWeight值与上一个一致,则将其放入到该集合Set<Constructor<?>> ambiguousConstructors = null;LinkedList<UnsatisfiedDependencyException> causes = null;//筛选可选项 构造方法,找出一个diffWeight最低的构造器for (Constructor<?> candidate : candidates) {//获取当前的构造器参数个数int parameterCount = candidate.getParameterCount();//条件3:argsToUse.length > parameterCount,不用找了,按照排序规则,后面的更短。直接退出if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {// Already found greedy constructor that can be satisfied ->// do not look any further, there are only less greedy constructors left.break;}//parameterCount:当前构造器参数个数//minNrOfArgs:表示bd中配置的构造器参数个数//条件成立:不匹配,参数少了if (parameterCount < minNrOfArgs) {continue;}ArgumentsHolder argsHolder;//获取当前构造器参数类型数组Class<?>[] paramTypes = candidate.getParameterTypes();//条件成立:说明bd中配置了构造器参数if (resolvedValues != null) {try {//获取构造器各个参数的名称//@ConstructorProperties(value=["a","b"])//Student(String name,String sex)String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);if (paramNames == null) {ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();if (pnd != null) {//Student(String name,String sex) => ["name","sex"]paramNames = pnd.getParameterNames(candidate);}}argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);}catch (UnsatisfiedDependencyException ex) {if (logger.isTraceEnabled()) {logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);}// Swallow and try next constructor.if (causes == null) {causes = new LinkedList<>();}causes.add(ex);continue;}}else {// Explicit arguments given -> arguments length must match exactly.if (parameterCount != explicitArgs.length) {continue;}argsHolder = new ArgumentsHolder(explicitArgs);}//LenientConstructorResolution == true 表示 ambiguousConstructors 允许有数据//LenientConstructorResolution == false 表示 ambiguousConstructors 不允许有数据,有数据会报错//计算匹配度:数值越高,构造器与参数匹配度越低int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this constructor if it represents the closest match.//条件成立:说明当前的构造器比之前筛选出的构造器更优先if (typeDiffWeight < minTypeDiffWeight) {constructorToUse = candidate;argsHolderToUse = argsHolder;argsToUse = argsHolder.arguments;minTypeDiffWeight = typeDiffWeight;ambiguousConstructors = null;}//条件成立:说明当前筛选出来的构造器和上一次筛选出来的构造器优先级别一样,将当前构造器加入到ambiguousConstructors中去else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {if (ambiguousConstructors == null) {ambiguousConstructors = new LinkedHashSet<>();ambiguousConstructors.add(constructorToUse);}ambiguousConstructors.add(candidate);}}//条件成立:没有找到可以用的构造器,直接抛出异常if (constructorToUse == null) {if (causes != null) {UnsatisfiedDependencyException ex = causes.removeLast();for (Exception cause : causes) {this.beanFactory.onSuppressedException(cause);}throw ex;}throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Could not resolve matching constructor " +"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");}//LenientConstructorResolution == false,不允许ambiguousConstructors存在数据,否则抛出异常else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Ambiguous constructor matches found in bean '" + beanName + "' " +"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +ambiguousConstructors);}//条件成立:说明自动匹配成功了,需要进行缓存,方便后来者再次使用该bd实例化if (explicitArgs == null && argsHolderToUse != null) {argsHolderToUse.storeCache(mbd, constructorToUse);}}Assert.state(argsToUse != null, "Unresolved constructor arguments");//根据筛选出来的构造器和参数进行实例化操作,包装返回bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));return bw;}

具体实例化,选择合适的策略去实例化

private Object instantiate(String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) {try {InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();if (System.getSecurityManager() != null) {return AccessController.doPrivileged((PrivilegedAction<Object>) () ->strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse),this.beanFactory.getAccessControlContext());}else {return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);}}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean instantiation via constructor failed", ex);}}

applyMergedBeanDefinitionPostProcessors

     // Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {//每个bd只能执行一次applyMergedBeanDefinitionPostProcessorsif (!mbd.postProcessed) {try {//后处理器调用点:合并bd信息,因为接下来就是populate处理依赖了。(保存@Autowired,@Value,@Inject注解信息到缓存)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}

这个后置处理器主要是保存了注解信息到后置处理器的缓存中,给后面的逻辑使用,并且这个逻辑只会走一次。
要走的最主要的后置处理器就是AutowiredAnnotationBeanPostProcessor

 @Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);}

看看是如何保存注解元数据信息的:

 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {// Fall back to class name as cache key, for backwards compatibility with custom callers.String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());// Quick check on the concurrent map first, with minimal locking.//获取缓存中之前扫描得到的注解元数据InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}//查询当前clazz关注的注解信息metadata = buildAutowiringMetadata(clazz);//将注解信息存入到缓存,key是beanName,value是当前clazz上的注解信息this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}

获取成功后,会保存注解元数据到injectionMetadataCache缓存中。具体的获取逻辑:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;//clazz继承体系上所有的注解信息do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();ReflectionUtils.doWithLocalFields(targetClass, field -> {MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static fields: " + field);}return;}boolean required = determineRequiredStatus(ann);currElements.add(new AutowiredFieldElement(field, required));}});ReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static methods: " + method);}return;}if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation should only be used on methods with parameters: " +method);}}boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}

获取类继承体系上的所有注解信息,并且返回

早期实例提前暴露

早期bean实例创建成功后,需要决定是否放入到第3级缓存

     if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//参数2:将bean包装成一个ObjectFactory,getObject调用的是getEarlyBeanReference的逻辑addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}

提前暴露到第3级缓存中

 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {//存放到第3级缓存this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}

getEarlyBeanReference是会调用后置处理器,对对象进行增强,这是AOP实现的关键

 protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;//对bean进行增强,AOP实现的关键。exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;}

放到3级缓存

 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {//存放到第3级缓存this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}

populateBean

这里的逻辑完成了依赖注入操作,注入了普通的实例,还将之前后置处理器中的注解元数据转为propertyValue并且注入依赖。

     Object exposedObject = bean;try {//处理当前实例的依赖数据的,依赖注入在这一步完成(出来普通的property还有@Autowired,@Value,@Inject信息的注入)populateBean(beanName, mbd, instanceWrapper);//生命周期中初始化方法的调用exposedObject = initializeBean(beanName, exposedObject, mbd);}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);}}

具体逻辑:

 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 {// 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.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;//AfterInstantiation实例化之后的后处理器调用,返回值决定了当前实例是否需要在进行依赖注入处理。//默认ibp.postProcessAfterInstantiation返回ture,如果不想要依赖注入,可以自己写一个InstantiationAwareBeanPostProcessor实现类if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}}//来到这里:处理依赖注入的逻辑//<property name="id" value="1"></property>//<property name="name" value="sfan"></property>//<property name="age" value="18"></property>PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);int resolvedAutowireMode = mbd.getResolvedAutowireMode();//条件成立:说明bd的autowireMode是byName或者byTypeif (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {//包装成MutablePropertyValuesMutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {//byName应该怎么处理?//根据字段名称去查找依赖的bean,然后完成注入autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}//newPvs相当于处理了依赖数据之后的pvspvs = newPvs;}//表示当前是否有InstantiationAwareBeanPostProcessors的后置处理器boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();//不重要boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}//后处理器调点:InstantiationAwareBeanPostProcessor.postProcessPropertiesfor (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {//典型应用:@Autowired注解的注入(之前扫描了注解信息,并且存放到了InstantiationAwareBeanPostProcessor缓存中,// 来到这里将注解元数据转为PropertyValues,注入value到bean的指定field中)InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs != null) {//完成的依赖注入合并后的pvs,应用到真实的实例中applyPropertyValues(beanName, mbd, bw, pvs);}}

存在一个后置处理器,用来将缓存的注解元信息保证成propertyValue。

 @Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//包装着当前bd需要注入的注解信息集合。@Autowired,@Value,@InjectInjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {//将注解信息注入到pvs中,解析出来value注入到bean中指定field中metadata.inject(bean, beanName, pvs);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);}return pvs;}
 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {// Fall back to class name as cache key, for backwards compatibility with custom callers.String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());// Quick check on the concurrent map first, with minimal locking.//获取缓存中之前扫描得到的注解元数据InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}//查询当前clazz关注的注解信息metadata = buildAutowiringMetadata(clazz);//将注解信息存入到缓存,key是beanName,value是当前clazz上的注解信息this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}

转换元数据信息存放到propertyValues中:

 public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {//拿到注解信息Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {//迭代处理当前bean需要解析的注解信息for (InjectedElement element : elementsToIterate) {if (logger.isTraceEnabled()) {logger.trace("Processing injected element of bean '" + beanName + "': " + element);}//element.inject(target, beanName, pvs);}}}
@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}else {//根据注解描述的字段和required信息 创建出来 依赖信息表述对象DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set<String> autowiredBeanNames = new LinkedHashSet<>(1);Assert.state(beanFactory != null, "No BeanFactory available");TypeConverter typeConverter = beanFactory.getTypeConverter();try {//解析出来的真实的依赖对象value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}synchronized (this) {if (!this.cached) {if (value != null || this.required) {this.cachedFieldValue = desc;registerDependentBeans(beanName, autowiredBeanNames);if (autowiredBeanNames.size() == 1) {String autowiredBeanName = autowiredBeanNames.iterator().next();if (beanFactory.containsBean(autowiredBeanName) &&beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());}}}else {this.cachedFieldValue = null;}this.cached = true;}}}//条件成立:说明根据依赖信息到容器内获取到依赖对象了if (value != null) {//使用反射技术 将 value 赋值给当前 bean的该字段的field中ReflectionUtils.makeAccessible(field);field.set(bean, value);}}}

真正的依赖注入:

applyPropertyValues(beanName, mbd, bw, pvs);
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {if (pvs.isEmpty()) {return;}if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());}MutablePropertyValues mpvs = null;List<PropertyValue> original;if (pvs instanceof MutablePropertyValues) {mpvs = (MutablePropertyValues) pvs;if (mpvs.isConverted()) {// Shortcut: use the pre-converted values as-is.try {bw.setPropertyValues(mpvs);return;}catch (BeansException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}}original = mpvs.getPropertyValueList();}else {original = Arrays.asList(pvs.getPropertyValues());}TypeConverter converter = getCustomTypeConverter();if (converter == null) {converter = bw;}BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);// Create a deep copy, resolving any references for values.List<PropertyValue> deepCopy = new ArrayList<>(original.size());boolean resolveNecessary = false;for (PropertyValue pv : original) {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 = convertForProperty(resolvedValue, propertyName, bw, converter);}// Possibly store converted value in merged bean definition,// in order to avoid re-conversion for every created bean instance.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();}// Set our (possibly massaged) deep copy.try {bw.setPropertyValues(new MutablePropertyValues(deepCopy));}catch (BeansException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}}

initializeBean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//aware接口对应方法的参数注入invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//后处理器调用点:BeforeInitialization初始化之前的后处理器调用点,主要还是aware接口方法对于实例的注入wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//执行初始化方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}//后置处理器调用点:AfterInitialization初始化之后的后处理器调用点//典型应用:Spring AOP的实现,暂时不涉及,后面再来if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

来到这个方法,最重要的就是:
1、对于实现aware接口方法的实例注入
2、两个后置处理器和一个初始化方法的执行。(第一个后置处理器还在注入aware接口方法要求的实
例。第二个后置处理器是AOP核心,暂不涉及)

执行初始化方法:
两种方式,要么是实现InitializingBean接口,要么是指定init-method,两个都有那么执行接口的方法

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {//执行初始化方法有两种方式,一种是实现了InitializingBean,一种是xml中的bean标签指定了init-method属性boolean isInitializingBean = (bean instanceof InitializingBean);//条件成立:说明实现了InitializingBean接口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 {//完成afterPropertiesSet接口方法调用((InitializingBean) bean).afterPropertiesSet();}}//条件成立:if (mbd != null && bean.getClass() != NullBean.class) {//bd中获取init-method指定方法名称String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&//通过接口实现了初始化方法,isInitializingBean就会是true,取反得到false,直接退出!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {//反射执行初始化方法invokeCustomInitMethod(beanName, bean, mbd);}}}

注册析构回调

//判断当前bean是否需要注册析构回调,即容器销毁的时候,会执行bean的销毁方法registerDisposableBeanIfNecessary(beanName, bean, mbd);

具体逻辑:

 protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);//条件1:原型不会注册析构回调//条件2:判断是否需要注册析构回调if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {if (mbd.isSingleton()) {// Register a DisposableBean implementation that performs all destruction// work for the given bean: DestructionAwareBeanPostProcessors,// DisposableBean interface, custom destroy method.//给当前单实例注册回调adapter适配器。适配器内根据当前的bean是继承接口还是通过bd来决定是通过调用哪个方法来完成析构registerDisposableBean(beanName,new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));}else {// A bean with a custom scope...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));}}}

小结

第一个重点是整体的createBean流程:
0、执行beforeInstantiation后置处理器,进入doCreateBean逻辑
1、createBeanInstance创建出来早期bean(这里最复杂的是匹配最优构造器,知道就行,不要深入)
2、将注解信息(@Autowired,@Value,@Inject注解信息到缓存)缓存到AutowiredAnnotationBeanPostProcessor中的Map<String, InjectionMetadata> injectionMetadataCache中
3、暴露早期bean到第3级缓存
4、注入依赖信息
4.1、注入依赖信息中,有一个核心逻辑就是将AutowiredAnnotationBeanPostProcessor缓存的注解元信息转为PropertyValue合并到bd中的PropertyValues中。最后才是执行真正的注入逻辑applyPropertyValues
5、初始化bean实例:1、_aware接口对应方法的参数注入;2、BeforeInitialization后置处理器调用,主要还是和aware接口相关;3、执行init方法;4、_AfterInitialization后置处理器调用,与AOP有关
6、注册析构回调
7、返回bean

第二个重点是各个后置处理器大致出现的位置及其作用:
1、一个是合并bd阶段调用的AutowiredAnnotationBeanPostProcessor后置处理器,扫描类继承体系上的注解元数据,并且缓存下来
2、第二个是依赖注入阶段,需要将AutowiredAnnotationBeanPostProcessor后置处理器中的注解元数据转换为propertyValue存放到propertyValues中
3、第三个bean初始化阶段,BeforeInitialization初始化之前的后处理器调用点,主要是aware接口参数实例的注入
4、第四个bean初始化阶段,AfterInitialization初始化之后的后处理器调用点,主要是AOP逻辑,后面再来分析

最终小结

这一小结对于bean的加载是很复杂的,重点掌握就是getBean的整体流程,循环依赖的处理和检测,各个后置处理器的作用(主要是有关两个注解的后置处理器,一个BeforeInitialization和AOP相关的后置处理器AfterInitialization),注解是如何融入getBean的逻辑的等代码逻辑。还是需要多多看看代码,多多阅读相关的资料,才能够加深对这一步源码的理解。

筑基期第一式:深入Spring源码之第二节getBean全流程【循环依赖分析+扩展点分析】相关推荐

  1. Spring源码解析(七)-Bean属性间的循环依赖

    首先复习一下前面学习的Spring容器启动的大致流程,首先Spring会先扫描所有需要实例化的Bean,将这些Bean的信息封装成一个个BeanDefinition,然后注册到BeanDefiniti ...

  2. Spring 源码解析 - Bean创建过程 以及 解决循环依赖

    一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...

  3. 筑基期第一式:SpringMVC源码解析

    文章目录 SpringMVC源码解析 SPI机制 案例 SpringMVC中SPI的使用 初始化IOC容器与九大组件 初始化容器 初始化九大组件 小结 SpringMVC如何处理一个请求 doDisp ...

  4. spring源码解读-第二部分面想切面编程

    这是第二部分了.看这部分源码需要第一部分基础.但是不知道也没关系.spring在代码耦合上控制的很好. 先进行知识扫盲: JoinPoint : 大白话:就是你的bean里面的方法:一个类里面有多少个 ...

  5. Spring源码解析(五)-Bean的实例化流程(上)

    在前面已经完成了对需要实例化bean的收集并封装成BeanDefinition,并且将BeanPostProcess等组件进行了提前实例化.接下来就到了容器启动的最后一步,也是最复杂的一步-实例化be ...

  6. 【框架源码】Spring源码解析之BeanDefinition加载流程解析

    观看本文之前,我们先思考一个问题,Spring是如何描述Bean对象的? Spring是根据BeanDefinition来创建Bean对象,BeanDefinition就是Spring中表示Bean定 ...

  7. Spring 源码讲解:bean 的创建流程 - 公开课笔记

    Spring 官网所有版本下载 官网文档中的链接找起来比较麻烦.我们可以通过下面这个链接: https://repo.spring.io/release/org/springframework/spr ...

  8. 电子招投标系统源码之了解电子招标投标全流程

    随着各级政府部门的大力推进,以及国内互联网+的建设,电子招投标已经逐渐成为国内主流的招标投标方式,但是依然有很多人对电子招投标的流程不够了解,在具体操作上存在困难.虽然各个交易平台的招标投标在线操作会 ...

  9. 电子招标系统源码之了解电子招标投标全流程

    随着各级政府部门的大力推进,以及国内互联网+的建设,电子招投标已经逐渐成为国内主流的招标投标方式,但是依然有很多人对电子招投标的流程不够了解,在具体操作上存在困难.虽然各个交易平台的招标投标在线操作会 ...

最新文章

  1. R语言glm拟合logistic回归模型实战:基于glm构建逻辑回归模型及模型系数统计显著性分析、每个预测因子对响应变量的贡献
  2. 淘宝秒杀系统设计的几个注意点
  3. jsp论坛网站模版_网站关键词优化怎么做
  4. linux安装python2环境_Python基础手册 2 —— Python 环境搭建(Linux)
  5. 【转】使用EBNF相对于BNF表示的优越性
  6. 面向对象---特----性
  7. 程序员修炼之道(一)
  8. BFS 算法框架套路详解
  9. 【技巧记录】如何批量制作文件夹/文件夹名
  10. 科学计算机度计算,科学计算器arctan
  11. arcgis html图像标记,图片标记
  12. mysql 破坏索引_mysql表索引被破坏的问题及解决
  13. ios系统安装包下载_iOS 屏蔽系统升级,描述文件版本已复活,无需越狱,请速度下载!...
  14. MySQL远程连接报错:ERROR 2002 (HY000): Can‘t connect to server on ‘192.168.172.130‘ (115)
  15. android屏幕唤醒与解锁
  16. 【总结】alter table *** add constraint *** 用法 . 建立约束 ,主键、外键的SQL语句写法
  17. hydra详细使用教程
  18. 名企到访|南京汇智动力共建教学资源,推进校企项目IT人才实训!
  19. C++常用的一些网络库
  20. SQL Server——T-SQL基础技术

热门文章

  1. BNU10878:下载测速
  2. vue写百度网盘页面
  3. 学习笔记04(java多人聊天室)
  4. 【web前端】相对路径和绝对路径详解
  5. 【ML】高斯混合模型(GMM)
  6. linux iscsi 虚拟化,使用 iSNS 在 RHEL6 中简化 Linux iSCSI 管理
  7. 【微信小程序】自定义属性值,及路由传参
  8. 有关计算机辅助手术方面的SCI,临床类SCI写作,我走过的“小白路”!
  9. 内存被填充为0xcc
  10. 禁止0xCC断点(最简单的反调试手段)