初识Spring源码(4) -- initializeBean | @PostConstruct | afterPropertiesSet | @Resource

0. 栗子:

@Component
public class SetterBean implements BeanNameAware, InitializingBean {

    private String beanName;

    @Resource(name = "beanService1")
    private BeanService beanService;

    @Override
    public void setBeanName(String name) {
        beanName = name;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("SetterBean run afterPropertiesSet");
    }

    @PostConstruct
    public void testPostConstruct() {
        System.out.println("SetterBean run PostConstruct");
        System.out.println("this beanName : " + beanName);
    }
}

@Configuration
public class ConfigurationBean {

    @Bean(initMethod = "initMethodTest")
    public BeanServiceInitMethod beanService1() {
        return new BeanServiceInitMethod();
    }

    @Bean
    public BeanService beanService() {
        BeanServiceImpl beanService = new BeanServiceImpl();
        beanService.setName("zhangsan");
        return beanService;
    }
}

@Component
public class BeanServiceInitMethod implements BeanService {
    private String name;

    public void initMethodTest() throws Exception {
        System.out.println("BeanServiceInitMethod run initMethodTest");
    }
}

4.1 initializeBean:

上一篇文章介绍了bean生命周期的属性填充populateBean方法的一些细节,至此,doCreateBean经历以下步骤:

 bean的初始化,整体包括下方添加注释的四点

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 {
		// 4.1. 调用Aware扩展接口
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		// 4.2. 引用初始化前后置处理器,@PostConstruct的方法便是此处调用的
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
		// 4.3. 调用初始化方法,afterPropertiesSet方法便是此处调用
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}
	if (mbd == null || !mbd.isSynthetic()) {
		// 4.4. 引用初始化后后置处理器
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}
 4.1. invokeAwareMethods:

 为了让我们的bean可以感知到容器内的一些东西,所以Spring为我们提供了Aware接口
`
 这里分别是让bean能够感知到beanName、ClassLoader、BeanFactory

private void invokeAwareMethods(String beanName, Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			// 实现BeanNameAware接口的类可以感知到beanName
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			// 实现BeanClassLoaderAware接口的类可以感知到beanClassLoader
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			// 实现BeanFactoryAware接口的类可以感知到BeanFactory
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

 像本栗子SetterBean是实现了BeanNameAware,SetterBean便可以感知到beanName,像本栗子只是简单赋值。

在这里插入图片描述

 4.2. applyBeanPostProcessorsBeforeInitialization:

  调用所有BeanPostProcessor 的 postProcessBeforeInitialization 方法,来对bean进行初始化前处理
·
 好比常用的@PostConstruct便是此处进行调用的,详情见下文4.6

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		// 调用postProcessBeforeInitialization方法来对bean进行初始化前处理
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}
 4.3. invokeInitMethods:

 开始执行bean的初始化方法,主要处理afterPropertiesSet和initMethod

  • 如果要初始化的bean实现了InitializingBean接口,就会去调用afterPropertiesSet方法;像本栗子的SetterBean
  • 如果像xml配置init-method,或者本栗中beanService1的@Bean(initMethod = “initMethodTest”),则取执行指定自定义初始化方法
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
		throws Throwable {
	// 判断初始化的bean是不是实现了InitializingBean接口
	boolean isInitializingBean = (bean instanceof InitializingBean);
	// 实现了InitializingBean接口&&重写了afterPropertiesSet方法
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
		}
		// 这个getSecurityManager一直不知道是什么,默认都不会走这里
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
					((InitializingBean) bean).afterPropertiesSet();
					return null;
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		// 执行bean重写的afterPropertiesSet方法
		else {
			((InitializingBean) bean).afterPropertiesSet();
		}
	}

	// 初始化的bean没有实现了InitializingBean接口,像本栗子beanService1这个bean
	if (mbd != null && bean.getClass() != NullBean.class) {
		// 获取bean的初始化方法名
		String initMethodName = mbd.getInitMethodName();
		// 存在初始化方法&&
		// (没有实现了InitializingBean接口&&初始化方法名不是afterPropertiesSet&&是外部管理的初始化方法)
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			// 执行自定义的初始化方法,像本栗子的initMethodTest方法
			// 如果初始化方法名为空则默认抛异常,否则通过反射来调用自定义的初始化方法
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}
 4.4. applyBeanPostProcessorsAfterInitialization:

 调用所有BeanPostProcessor 的 postProcessAfterInitialization 方法,来对bean进行初始化后处理
·
 这里如果有AOP会进行代理对象的处理,后面再介绍

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}
 4.5. @Resource:

 在之前的文章2.3节中介绍了@Autowired注入过程,@Resource其实也类似,主要有以下步骤

  4.5.1. 封装注入属性元数据metadata:

 关于标注 @Resource的属性元数据封装,可以查看文章1.2节内容

  4.5.2. CommonAnnotationBeanPostProcessor#postProcessProperties:

 在属性填充时,调用后置处理器的postProcessProperties方法进行注入
·
 处理@Resource的后置处理器是CommonAnnotationBeanPostProcessor

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	// 对@Resource标注的属性/方法的元数据之前就预解析封装了,这里可以直接获取
	InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
	try {
		// 根据属性方法元数据metadata,进行注入
		metadata.inject(bean, beanName, pvs);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
	}
	return pvs;
}
  4.5.3. metadata.inject:

 属性和方法元数据封装到ResourceElement,最后都封装到InjectionMetadata

在这里插入图片描述

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()) {
		for (InjectedElement element : elementsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Processing injected element of bean '" + beanName + "': " + element);
			}
			element.inject(target, beanName, pvs);
		}
	}
}

 循环遍历属性、方法元数据进行注入;同@Autowired一样会先进行属性注入,再进行方法注入。

  4.5.4. element.inject:
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
		throws Throwable {

	// 属性注入的处理
	if (this.isField) {
		Field field = (Field) this.member;
		ReflectionUtils.makeAccessible(field);
		// 直接反射进行注入,重点方法getResourceToInject获取注入的属性实例
		field.set(target, getResourceToInject(target, requestingBeanName));
	}
	// 方法注入的处理
	else {
		if (checkPropertySkipping(pvs)) {
			return;
		}
		try {
			Method method = (Method) this.member;
			ReflectionUtils.makeAccessible(method);
			method.invoke(target, getResourceToInject(target, requestingBeanName));
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}
}
  4.5.5. getResourceToInject:
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
	// 如果标注@,Resource的属性/方法,还标注了@Lazy即懒加载的,则lazyLookup=true,通过代理获取注入属性的实例
	// 否则通过getResource方法进行获取
	return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
			getResource(this, requestingBeanName));
}
  4.5.6. getResource:

 默认mappedName为空,alwaysUseJndiLookup为false

protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
		throws NoSuchBeanDefinitionException {

	if (StringUtils.hasLength(element.mappedName)) {
		return this.jndiFactory.getBean(element.mappedName, element.lookupType);
	}
	if (this.alwaysUseJndiLookup) {
		return this.jndiFactory.getBean(element.name, element.lookupType);
	}
	// 上面是jndi的处理,默认是不会走的,除非注解设置了lookup或mappedName属性
	// resourceFactory不为空,默认是DefaultListableBeanFactory类型
	if (this.resourceFactory == null) {
		throw new NoSuchBeanDefinitionException(element.lookupType,
				"No resource factory configured - specify the 'resourceFactory' property");
	}
	// 默认是走这个方法获取实例
	return autowireResource(this.resourceFactory, element, requestingBeanName);
}
  4.5.7. autowireResource:
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
		throws NoSuchBeanDefinitionException {

	Object resource;
	Set<String> autowiredBeanNames;
	// 注解中name属性值,不写name则默认是注入的属性名
	String name = element.name;

	// DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory 默认条件成立
	if (factory instanceof AutowireCapableBeanFactory) {
		AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
		// 封装依赖描述器DependencyDescriptor
		DependencyDescriptor descriptor = element.getDependencyDescriptor();
		// fallbackToDefaultTypeMatch默认true&&注解不写name属性&&工厂不包含属性名的bean
		if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
			autowiredBeanNames = new LinkedHashSet<>();
			// 条件成立则通过resolveDependency获取实例,在第三篇文章接介绍过
			// 一般我们都会指定name属性,所以这里一般成立
			resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
			if (resource == null) {
				throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
			}
		}
		// @Resource(name = "beanService1")指定name,会通过name来解析出实例
		// resolveBeanByName内部通过getBean获取实例
		else {
			resource = beanFactory.resolveBeanByName(name, descriptor);
			autowiredBeanNames = Collections.singleton(name);
		}
	}
	// 默认不成立
	else {
		resource = factory.getBean(name, element.lookupType);
		autowiredBeanNames = Collections.singleton(name);
	}

	// DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory
	// 默认条件成立
	if (factory instanceof ConfigurableBeanFactory) {
		ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
		for (String autowiredBeanName : autowiredBeanNames) {
			if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
			 	// 注册依赖bean
				beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
			}
		}
	}

	return resource;
}
  4.5.8. 小结:

 对于常用的@Resource(name = “beanService1”)属性注入,即指定name属性

  • 从预解析的缓存中获取封装了属性、方法元数据的对象InjectionMetadata
  • 循环遍历各元数据,进行注入;先进行属性,再进行方法注入,属性注入会存在被覆盖的可能
  • 通过resolveBeanByName来解析出依赖的属性bean对象,
     内部通过getBean获取实例,指定name当然就是获取唯一bean,不会像@Autowired那样有那么多过滤
  • 最后通过反射修改bean,实现属性注入
 4.6. @PostConstruct:

 @PostConstruct的调用在上述4.2节中也提到,调用postProcessBeforeInitialization进行初始化前处理

  4.6.1. 封装注入方法元数据metadata:

 关于标注 @PostConstruct的方法元数据封装,可以查看文章1.3节内容

  4.6.2. InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization

 CommonAnnotationBeanPostProcessor继承InitDestroyAnnotationBeanPostProcessor

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	// 对@Resource标注的方法的元数据之前就预解析封装了,这里可以直接获取
	LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
	try {
		// 根据方法元数据metadata,进行注入
		metadata.invokeInitMethods(bean, beanName);
	}
	catch (InvocationTargetException ex) {
		throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
	}
	return bean;
}
  4.6.3. metadata.invokeInitMethods:

 方法元数据封装到LifecycleElement,最后都封装到LifecycleMetadata

在这里插入图片描述

public void invokeInitMethods(Object target, String beanName) throws Throwable {
	Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
	Collection<LifecycleElement> initMethodsToIterate =
			(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
	if (!initMethodsToIterate.isEmpty()) {
		for (LifecycleElement element : initMethodsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
			}
			// 遍历执行方法,就是反射调用@PostConstruct标注的方法
			element.invoke(target);
		}
	}
}
  4.6.4. element.invoke:

 有目标对象,又知道目标对象@PostConstruct标注的方法,就通过反射去调用方法

public void invoke(Object target) throws Throwable {
	ReflectionUtils.makeAccessible(this.method);
	// 反射调用
	this.method.invoke(target, (Object[]) null);
}
  4.6.5. 小结:
  • 从预解析的缓存中获取封装了属性、方法元数据的对象LifecycleMetadata
  • 循环遍历各方法元数据,进行方法调用;实际就是对象的反射来进行方法的调用
 4.7. 小结:
  • 从上面的分析可以知道@PostConstruct 会比afterPropertiesSet先调用
  • @PostConstruct通过对象反射调用方法,afterPropertiesSet是通过bean直接调用
  • @Resource推荐指定name,不指定默认是标注的属性name
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值