Spring 源码--Bean 实例化
2021/12/4 20:18:47
本文主要是介绍Spring 源码--Bean 实例化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
上一篇的 BeanWrapper 我们介绍了 BeanWrapper 的来由。现在我们继续看看 Spring 是如何构造一个 Bean 的。
代码不长、也不是特别的复杂
/** * 使用合适的实例化策略去创建bean: FactoryMethod,构造器自动注入、或者简单的无参构造器 */ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. Class<?> beanClass = resolveBeanClass(mbd, beanName); ....... Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // Candidate constructors for autowiring? Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); 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); }
Class<?> beanClass = resolveBeanClass(mbd, beanName);
这一步就是解释 bean 对应的类型被解释成 Class 放置到 BeanDefinition 中(创建 BeanDefinition 的时候可能是设置了 className 而非 Class 对象)
InstanceSupplier
Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); }
这一步是获取 Supplier 对象、调用这个对象的 get 方法即可得到创建好的 bean、然后就构建 BeanWrapper 并进行初始化。注册相应的 PropertyEditor。
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) { Object instance; String outerBean = this.currentlyCreatedBean.get(); this.currentlyCreatedBean.set(beanName); try { instance = instanceSupplier.get(); } finally { if (outerBean != null) { this.currentlyCreatedBean.set(outerBean); } else { this.currentlyCreatedBean.remove(); } } if (instance == null) { instance = new NullBean(); } BeanWrapper bw = new BeanWrapperImpl(instance); initBeanWrapper(bw); return bw; } protected void initBeanWrapper(BeanWrapper bw) { bw.setConversionService(getConversionService()); registerCustomEditors(bw); }
那我们怎么样注册这个 Supplier 呢 ?
if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context).registerBean(Service.class,()->{ System.out.println("create bean in supplier"); return new Service(); }); } Service bean = context.getBean(Service.class);
FactoryMethod
if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } protected BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs); }
第二种实例化 bean 的方式。什么是 FactoryMethod 呢?
设计模式中存在静态工厂和工厂方法、而这里也是类似的。我们在配置类中声明的 bean 就是类似这种模式。
@Configuration public class Config { @Bean public Service service() { return new Service(); } @Bean public static Service staticService() { return new Service(); } }
一步步分析代码
public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Object factoryBean; Class<?> factoryClass; boolean isStatic; String factoryBeanName = mbd.getFactoryBeanName(); if (factoryBeanName != null) { if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } factoryBean = this.beanFactory.getBean(factoryBeanName); if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } factoryClass = factoryBean.getClass(); isStatic = false; } else { // It's a static factory method on the bean class. if (!mbd.hasBeanClass()) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "bean definition declares neither a bean class nor a factory-bean reference"); } factoryBean = null; factoryClass = mbd.getBeanClass(); isStatic = true; } ................
mbd.getFactoryBeanName() 如果 @Bean 注解对应的方法非静态、那么则返回它的配置类的 beanId 、此处为 config
如果 @Bean 注解对应的方法是静态、那么则返回为 null。这个设置的过程是在 ConfigurationClassPostProcessor 中使用 ConfigurationClassBeanDefinitionReader 扫描注册 bean 的时候解释设置的。
factoryBean 则为这个配置类的实例、是从 Spring 容器中获取的。而对于静态方法来说、后续通过反射调用 @Bean 修饰的方法时、invoke 的对象可以为 null 、所以 @Bean 修饰的是静态方法时、factoryBean = null 。
......................... Method factoryMethodToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; if (explicitArgs != null) { argsToUse = explicitArgs; } else { Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; // 上一次创建 bean 时使用过的方法、主要是针对 prototype 类型的 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // 上一次创建 bean 使用的构造函数参数 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { // 上一次使用的构造函数参数(尚未转型或者需要额外处理) argsToResolve = mbd.preparedConstructorArguments; } } } if (argsToResolve != null) { // 涉及到类型转换、属性编辑、可参见上一篇文章 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); } } .........................
这里主要是对参数的解释以及调用方法的选定、主要都是从 BeanDefinition 中获取、如果是第一次的话、则不会从中获取到值。
explicitArgs 如果调用 Spring#getBean 方法有指定该值、则不为 null。如果指定了该值、那么即使 BeanDefinition 中有上一次解释过的产生 bean 的 method 也不会再使用、只会从中再次选择最合适的。
@Bean() @Scope(value = SCOPE_PROTOTYPE) public static Service staticService() { return new Service(); } public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(JunitSpringBootApplication.class, args); Object staticService = context.getBean("staticService"); staticService = context.getBean("staticService"); }
第二次调用 context.getBean("staticService") 时、则会进入到使用上一次创建的缓存中。
if (factoryMethodToUse == null || argsToUse == null) { // Need to determine the factory method... // Try all methods with this name to see if they match the given arguments. factoryClass = ClassUtils.getUserClass(factoryClass); List<Method> candidates = null; if (mbd.isFactoryMethodUnique) { if (factoryMethodToUse == null) { factoryMethodToUse = mbd.getResolvedFactoryMethod(); } if (factoryMethodToUse != null) { candidates = Collections.singletonList(factoryMethodToUse); } } if (candidates == null) { candidates = new ArrayList<>(); Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { candidates.add(candidate); } } } ................
判断一个 BeanDefinition 的 FactoryMethod 是否唯一是根据 @Bean 修饰的方法名在配置类中是否唯一、因为方法名就是其 beanId。如果存在两个一样方法名的方法、不管是否是静态还是非静态方法、都是不唯一的。如果是唯一的话、则直接成为候选方法。
如果不是唯一的话、那么就反射获取配置类的所有方法、然后根据方法名和是否是静态方法进行筛选。此时可能存在多个候选方法。
if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Method uniqueCandidate = candidates.get(0); if (uniqueCandidate.getParameterCount() == 0) { mbd.factoryMethodToIntrospect = uniqueCandidate; synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS)); return bw; } }
如果候选方法只有一个、并且没有传入参数、并且 @Bean 修饰的方法没有入参、那么就非常简单的进行反射调用该方法即可。
如果候选方法大于一个的话、则对其进行排序。public 的高于非 public、入参多的高于入参少的(对于配置类的 bean、Spring 一直想给它最好的爱)
if (candidates.size() > 1) { // explicitly skip immutable singletonList candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR); } public static final Comparator<Executable> EXECUTABLE_COMPARATOR = (e1, e2) -> { int result = Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers())); return result != 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount()); };
所有配置类里面的 @Bean 创建的 BeanDefinition 都是 AUTOWIRE_CONSTRUCTOR 的。
minTypeDiffWeight 代表的是方法参数类型与实际从 Spring 中找出来的 bean 参数类型的差异权重。差异小的就选其作为最后的候选方法、调用它创建返回 bean。
ConstructorArgumentValues resolvedValues = null; boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); int minTypeDiffWeight = Integer.MAX_VALUE; Set<Method> ambiguousFactoryMethods = null; int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // We don't have arguments passed in programmatically, so we need to resolve the // arguments specified in the constructor arguments held in the bean definition. if (mbd.hasConstructorArgumentValues()) { ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } else { minNrOfArgs = 0; } } LinkedList<UnsatisfiedDependencyException> causes = null;
这里面涉及到依赖关系的处理、默认来说是先从 BeanFactory 中找出该参数类型的所有 beanName、如果是一个则直接使用该 bean、如果是多个则比较 beanId 。如果都找不到或者无法确定哪个 bean 作为方法入参则抛出异常、for 循环则会继续下一个候选方法进行比较筛选。如果出现类型差异一致、则会记录、后续退出循环抛出模凌无法选出正确方法的异常。
for (Method candidate : candidates) { int parameterCount = candidate.getParameterCount(); if (parameterCount >= minNrOfArgs) { ArgumentsHolder argsHolder; Class<?>[] paramTypes = candidate.getParameterTypes(); if (explicitArgs != null) { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } else { // Resolved constructor arguments: type conversion and/or autowiring necessary. try { String[] paramNames = null; ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.size() == 1); } catch (UnsatisfiedDependencyException ex) { if (logger.isTraceEnabled()) { logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next overloaded factory method. if (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } } int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this factory method if it represents the closest match. if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && !mbd.isLenientConstructorResolution() && paramTypes.length == factoryMethodToUse.getParameterCount() && !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) { if (ambiguousFactoryMethods == null) { ambiguousFactoryMethods = new LinkedHashSet<>(); ambiguousFactoryMethods.add(factoryMethodToUse); } // 模凌两可 ambiguousFactoryMethods.add(candidate); } } }
FactoryMethod 到此就结束了。最后选取一个最合适的方法放射调用产生 bean
当我们在配置类中、重载方法的时候、那么就会不是唯一的 BeanFactory、如果我们的参数还是都是依赖 bean 的父类/父接口、那么就会变得模凌两可进而抛出异常
Constructor
// Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } }
这个是有缓存、解释过之后的操作。当你的 bean 是 prototype 的时候、且不是在配置类中声明的时候、则第二次获取该 bean 时会进入到该代码块中。
// Candidate constructors for autowiring? Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); }
这块代码最终会来到 AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors 中
抛开 Lookup 注解以及缓存
- 找出这个类所申明的构造函数
- 找出所有使用啦 @Autowire 注解的构造器。如果已经存在了一个 required 为 true 的构造器、那么就不能有第二个构造器被 @Autowire 修饰。如果都是为 false 的话、可以有多个
- 如果不存在 required = true 的构造器(存在有@Autowire 修饰的构造器)、那么如果存在默认构造器、那么也将它加入到数组中一次返回
- 如果不存在 @Autowire 修饰的构造器、但是存在一个非默认构造器、即入参大于 0 的构造器、那么就返回它
如果返回的构造器数组不为 null 、那么就进入到 ConstructorResolver#autowireConstructor 方法中。根据传入的构造函数、如果只有一个、那么就选择它来创建 bean、如果多个、那么就按照顺序一个个尝试、逻辑上跟选择 FactoryMethod 是一样的。
- 先排序 (public 优先、参数多的优先)
- for 循环、在 Spring 中寻找参数对象、比较参数类型的差异度、选择出差异度最小的构造函数
- 反射调用构造函数、创建出 bean
// 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);
getPreferredConstructors 该方法默认返回 null 只有一个子类尝试返回。ClassDerivedBeanDefinition 该类只有我们尝试主动注册 Supplier 的时候才会使用该类(上面的 InstanceSupplier)、其他情况都是返回 null
@Override @Nullable public Constructor<?>[] getPreferredConstructors() { Class<?> clazz = getBeanClass(); // Kotlin 才会有可能返回非 null Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz); if (primaryCtor != null) { return new Constructor<?>[] {primaryCtor}; } // public 的构造函数 Constructor<?>[] publicCtors = clazz.getConstructors(); if (publicCtors.length > 0) { return publicCtors; } return null; }
而 instantiateBean(beanName, mbd); 则是非常简单的通过反射调用无参构造方法反射创建 bean。而这里面涉及到方法注入(replace/lookup)、后续文章会介绍到。
最后
supplier 是简单的、而 FactoryMethod 也相对 Constructor 来说简单一些、因为不用找出对应的 method、只要按照排序以及规则筛选出合适的 method 即可、当然这个排序和规则同样适用于 Contructor。
constructor 则是需要选出一个合适的构造函数、@Autowire 修饰的、还是没有、然后使用默认构造函数。多个的时候、筛选出合适的构造函数、跟 FactoryMethod 是一致的。
这篇关于Spring 源码--Bean 实例化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-15JavaMailSender是什么,怎么使用?-icode9专业技术文章分享
- 2024-11-15JWT 用户校验学习:从入门到实践
- 2024-11-15Nest学习:新手入门全面指南
- 2024-11-15RestfulAPI学习:新手入门指南
- 2024-11-15Server Component学习:入门教程与实践指南
- 2024-11-15动态路由入门:新手必读指南
- 2024-11-15JWT 用户校验入门:轻松掌握JWT认证基础
- 2024-11-15Nest后端开发入门指南
- 2024-11-15Nest后端开发入门教程
- 2024-11-15RestfulAPI入门:新手快速上手指南