Spring源码(十五)createBean方法

Spring源码(十五)createBean方法

createBean

	protected 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.
		// 锁定class,根据设置的class属性或者根据className来解析class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		// 进行条件筛选,重新赋值RootBeanDefinition,并设置BeanClass属性
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			// 重新创建一个RootBeanDefinition对象
			mbdToUse = new RootBeanDefinition(mbd);
			// 设置BeanClass属性值
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		// 验证及准备覆盖的方法,lookup-method  replace-method,当需要创建的bean对象中包含了lookup-method和replace-method标签的时候,会产生覆盖操作
		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.
			// 给BeanPostProcessors一个机会来返回代理来替代真正的实例,应用实例化前的前置处理器,用户自定义动态代理的方式,针对于当前的被代理类需要经过标准的代理流程来创建对象
			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);
		}
	}

进入到resolveBeanClass方法中。beanClass为String类型的。

protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
			throws CannotLoadBeanClassException {

		try {
			// 判断mbd的定义信息中是否包含beanClass,并且是Class类型的,如果是直接返回,否则的话进行详细的解析
			if (mbd.hasBeanClass()) {
				// 如果mbd指定了bean类
				return mbd.getBeanClass();
			}
			// 判断是否有安全管理器
			if (System.getSecurityManager() != null) {
				return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
						() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
			}
			else {
				// 进行详细的处理解析过程
				return doResolveBeanClass(mbd, typesToMatch);
			}
		}

这里进行了判断是否有安全检查管理器,如果有,那么就获取权限,并用doResolveBeanClass,这个方法里面是native,用C写的,就略过;如果没有,这里的resolveBeanClass方法就不一样了,此方法调用了resolveBeanClass方法,这里就是ForName,将String类型的class转换为类。

然后有了这个Class对象,如果我们想反射,那么就要用new Instance,可以直接返回对象了。但是这里并没有这么做。

下面,mdbToUse.prepareMethodOverrides方法,这里有两个标签,一个lookup-method,一个replace-method。
在这里插入图片描述
这里设置了标志位,标记methodOverride暂未被覆盖,避免参数类型检查的开销。只是标识了一下,在后面实例化时,再调用。
当需要创建bean对象,包含了lookup method与replace-method,回产生覆盖操作。

接下来继续,到doCreateBean方法了,然后调用了createBeanInstance方法,再调用了instantiateBean方法,再调用instantiate方法。到了fasle,再进入instantiateWithMethodInjection方法。再进入CglibSubclassCreator.instance方法,

通过拦截器方式每次需要的时候创建最新的对象,而不会把原型对象缓存起来。
如果不用这种方式,虽然取得的原型,但是每次拿的都是一样的。因为创建的apple会被缓存,而原型bean也会被缓存去,不能每次获得新的banana对象,而配了lookup的话,每次获取到的就是最新的结果,get重新获取,因为缓存中没有。

用gebean的获取的时候,实际上一级缓存中放的是cglib的拦截器。用getFruit方法进去时,直接到iCGLIBSubClassing方法的ntercept方法中了,lo包括apple与方法getFruit,这里会用getBean去创建apple对象了。
在这里插入图片描述
继续往下,resolveBeforeInstantiation,使用代理的方式返回bean,可以在这里自己实现动态代理的东西。

这里自定义了实现此方法,后续的doCreateBean就不用走了,直接走上面代理出来的bean对象。(取决于BPP是否包含InstantiationAwareBeanPostProcessor)。一般这里不会进行处理的,为空。
在这里插入图片描述
下面就要进入到doCreateBean核心创建对象方法中了。

总结

在这里插入图片描述

上面流程需要注意的是lookup-method与replace-method的使用。它们的作用是处理单例情况下引用了多例的方式。
resolveBeforeInstantiation这种方法可以提前创建用户自定义的代理对象。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值