在Bean实例的生命周期中,会调用doCreateBean()方法来创建Bean实例,其中最主要的是实例化得到一个原始Bean,后续的属性填充、循环依赖以及AOP等等操作,都是依赖于原始的实例化bean对象,而实例化的时候,需要调用合适的构造方法来创建实例,Spring提供了推断构造方法的机制来获取最合适的构造方法
核心的源码位于AbstractAutowireCapableBeanFactory的createBeanInstance()中
一、其他方式创建实例
1.1 通过instanceSupplier获取实例
我们在创建Bean的BeanDefinition的时候,可以设置BeanDefinition的instanceSupplier属性,这是一个lambda表达式
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
//设置beanDefintion的该属性
beanDefinition.setInstanceSupplier(() -> new User());
context.registerBeanDefinition("userService",beanDefinition);
当创建Bean实例的时候,首先会去判断当前bean的BeanDefinition中是否设置了instanceSupplier属性,如果设置了,将调用obtainFromSupplier()生成一个实例
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);
// BeanDefinition中添加了Supplier,则调用Supplier来得到对象
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
……
}
在该方法中,会调用instanceSupplier的get()方法,就是执行lambda表达式来生成一个实例对象,如果得到的实例为null,则会去创建一个空实例
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
try {
instance = instanceSupplier.get();
}
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
1.2 通过缓存的构造方法和参数
在通过缓存的构造方法和参数创建实例前,会判断当前的bean是否是通过@Bean来创建,如果是这种方式,将会执行@Bean的构造推断以及生成bean实例
// @Bean对应的BeanDefinition
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
Spring只有在getBean()的时候没有指定参数才会用到缓存的构造方法和参数
resolvedConstructorOrFactoryMethod用于缓存构造方法,其中constructorArgumentsResolved记录是否需要构造注入
如果缓存了构造方法,则判断是否需要进行依赖注入,如果需要则调用autowireConstructor()方法来生成实例,该方法是推断构造方法最核心的方法;如果不需要进行依赖注入,则会直接去调用无参的构造方法直接实例化
// Shortcut when re-creating the same bean...
// 一个原型BeanDefinition,会多次来创建Bean,那么就可以把该BeanDefinition所要使用的构造方法缓存起来,避免每次都进行构造方法推断
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入)
if (autowireNecessary) {
// 方法内会拿到缓存好的构造方法的入参
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化
return instantiateBean(beanName, mbd);
}
}
二、寻找构造方法
如果前面的方式都没法创建一个实例bean,第二步就要去获取所有可用的构造方法
// 如果没有找过构造方法,那么就开始找了
// Candidate constructors for autowiring?
// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法
// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
determineConstructorsFromBeanPostProcessors()的方法名就可以看出,也是调用BeanPostProcessor的方法,这一步调用的是SmartInstantiationAwareBeanPostProcessor实现类的determineCandidateConstructors()方法,只要找到了构造方法就返回
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
return null;
}
SmartInstantiationAwareBeanPostProcessor的实现类中,只有AutowiredAnnotationBeanPostProcessor对determineCandidateConstructors()进行了实现
2.1 缓存@Lookup注解方法
如果当前beanName对应的beanClass没有经过Lookup的检查,则会遍历该类以及父类的所有方法,将有@Lookup注解的方法封装成LookupOverride,并缓存至beanDefinition的methodOverrides中,后续讲解@Lookup的时候会用到
if (!this.lookupMethodsChecked.contains(beanName)) {
// 判断beanClass是不是java.开头的类,比如String
if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
Class<?> targetClass = beanClass;
do {
// 遍历targetClass中的method,查看是否写了@Lookup方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
Assert.state(this.beanFactory != null, "No BeanFactory available");
// 将当前method封装成LookupOverride并设置到BeanDefinition的methodOverrides中
LookupOverride override = new LookupOverride(method, lookup.value());
RootBeanDefinition mbd = (RootBeanDefinition)
this.beanFactory.getMergedBeanDefinition(beanName);
mbd.getMethodOverrides().addOverride(override);
}
});
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
}
this.lookupMethodsChecked.add(beanName);
}
2.2 获取构造方法并判断是否满足规则
2.2.1 获取构造方法
首先会从AutowiredAnnotationBeanPostProcessor的缓存candidateConstructorsCache中根据beanClass来获取构造方法,如果缓存中没有,才会去调用beanClasss的getDeclaredConstructors()获取所有的构造方法(包括非public)
rawCandidates变量存放的是所有未经过处理的构造方法
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
// Fully synchronized resolution now...
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
// 拿到所有的构造方法
rawCandidates = beanClass.getDeclaredConstructors();
}
2.2.2 解析@Autowired的构造方法
用requiredConstructor记录@Autowired的required为true的构造方法,用defaultConstructor记录默认无参的构造方法
candidates变量记录所有加了@Autowired的构造方法
调用findAutowiredAnnotation()判断构造方法是否有@Autowired,如果没有,再判断是否为代理类,如果是代理类再去获取被代理类的构造方法,判断是否有该注解
如果requiredConstructor已经记录了一个@Autowired的required为true的构造方法,如果此时遍历的构造方法也有@Autowired,就直接抛异常
如果当前遍历的构造方法上@Autowired的required为true时,需要判断candidates是否为空,candidates记录的是加了@Autowired的构造方法,如果不为空,则抛异常,与上一步的功能一样,都是为了保证只要有一个@Autowired的required为true构造方法,就不允许再有其他加了@Autowired的构造方法,即使required为false也不行
如果当前遍历的构造方法没有加@Autowired,且参数个数为0,表明这是一个无参的构造方法,用defaultConstructor记录这个构造方法
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
// 用来记录required为true的构造方法,一个类中只能有一个required为true的构造方法
Constructor<?> requiredConstructor = null;
// 用来记录默认无参的构造方法
Constructor<?> defaultConstructor = null;
// 遍历每个构造方法
for (Constructor<?> candidate : rawCandidates) {
// 当前遍历的构造方法是否写了@Autowired
MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
// 如果beanClass是代理类,则得到被代理的类的类型
Class<?> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
try {
Constructor<?> superCtor =
userClass.getDeclaredConstructor(candidate.getParameterTypes());
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {
// Simply proceed, no equivalent superclass constructor found...
}
}
}
// 当前构造方法上加了@Autowired
if (ann != null) {
// 整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法
if (requiredConstructor != null) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructor: " + candidate +
". Found constructor with 'required' Autowired annotation already: " +
requiredConstructor);
}
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
// 记录唯一一个required为true的构造方法
requiredConstructor = candidate;
}
// 记录所有加了@Autowired的构造方法,不管required是true还是false
// 如果默认无参的构造方法上也加了@Autowired,那么也会加到candidates中
candidates.add(candidate);
// 从上面代码可以得到一个结论,在一个类中,要么只能有一个required为true的构造方法,要么只能有一个或多个required为false的方法
}
else if (candidate.getParameterCount() == 0) {
// 记录唯一一个无参的构造方法
defaultConstructor = candidate;
}
// 有可能存在有参、并且没有添加@Autowired的构造方法
}
2.2.3 返回候选的构造方法
candidates存放的是所有加了@Autowired的构造方法,如果candidates不为空,判断是否有required为true的构造方法,如果都是required为false的构造方法,则判断是否有默认无参构造方法,如果有,也将其加入到candidates中,作为候选的构造方法
如果没有加@Autowired的构造方法,只有一个有参的构造方法,则将该构造方法加入到候选构造方法;如果有多个有参的构造方法,则会返回null;如果只有一个默认的无参构造方法也返回null
所有候选的构造方法都存在candidateConstructors变量中,最后会将这些候选的构造方法进行缓存
对于多个有参的构造方法,会在后面推断使用哪一个构造方法时作进一步推断
if (!candidates.isEmpty()) {
// Add default constructor to list of optional constructors, as fallback.
// 如果不存在一个required为true的构造方法,则所有required为false的构造方法和无参构造方法都是合格的
if (requiredConstructor == null) {
if (defaultConstructor != null) {
candidates.add(defaultConstructor);
}
}
// 如果只存在一个required为true的构造方法,那就只有这一个是合格的
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
}
// 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
……
else {
// 如果有多个有参、并且没有添加@Autowired的构造方法,是会返回空的
candidateConstructors = new Constructor<?>[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/153663.html