如何构造一个对象?
1、默认情况下,或者只有一个构造方法的情况下,就会使用默认构造方法或者唯一的一个构造方法
2、由程序员指定构造方法入参值,通过getBean()的方式获取,可以指定参数类型以及个数,但是该bean需要为LazyBean或者原型bean,否则在spring启动的时候就已经创建好存入单例池中,getBean()也只会取到单例池种的bean。
UserService userService = applicationContext.getBean("userService", UserService.class);
3、由程序员自己注册Bean然后指定参数个数以及类型
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanNameAutoProxyCreatorDemo.class);
AbstractBeanDefinition rawBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
rawBeanDefinition.setBeanClass(UserService.class);
rawBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new User());
applicationContext.registerBeanDefinition("userService",rawBeanDefinition);
applicationContext.refresh();
UserService userService = (UserService)applicationContext.getBean("userService");
4、由程序员自己指定第N+1个参数的类型或bean名字
类型
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanNameAutoProxyCreatorDemo.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
rawBeanDefinition.setBeanClass(UserService.class);
//指定第二个参数的类型是User
beanDefinition .getConstructorArgumentValues().addIndexedArgumentValue(1,new User());
applicationContext.registerBeanDefinition("userService",beanDefinition );
applicationContext.refresh();
UserService userService = (UserService)applicationContext.getBean("userService");
名字
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1,new RuntimeBeanNameReference("orderService"));
5、通过指定spring自己选择构造方法
<bean id="userService" class="com.tuling.UserService" autowire="constructor"></bean>
6、通过程序员添加@autowire注解选择指定的构造方法
@Autowired
public UserService(User user) {
this.user = user;
}
7、(这一点功能比较鸡肋,但是在推断构造方法中有用到,就顺带提一下)注册bean的时候可以直接指定返回的实例对象
AbstractBeanDefinition rawBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
rawBeanDefinition.setBeanClass(UserService.class);
rawBeanDefinition.setInstanceSupplier(new Supplier<Object>() {
@Override
public Object get() {
return new User();
}
});
applicationContext.registerBeanDefinition("userService",rawBeanDefinition);
applicationContext.refresh();
User userService = (User)applicationContext.getBean("userService");
8.
核心代码
createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 加载beanName所对应的类
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//这个bean不是公共类或者没有开启访问私有成员的权限,则抛出异常
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());
}
// BeanDefinition中添加了Supplier,则调用Supplier来得到对象
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// @Bean对应的BeanDefinition
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 一个原型BeanDefinition,会多次来创建Bean,那么就可以把该BeanDefinition所要使用的构造方法缓存起来,避免每次都进行构造方法推断
boolean resolved = false;
boolean autowireNecessary = false;
//当getBean的方式没有传入参数,则尝试走缓存
if (args == null) {
//doublecheck加锁
synchronized (mbd.constructorArgumentLock) {
//resolvedConstructorOrFactoryMethod代表缓存的构造方法
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);
}
}
/**推断构造方法*/
// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法
// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点
//下面有详细代码
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入
// 如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法
// 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了
// 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了
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.getPreferredConstructor