前篇文章传送门
上篇咱们了解了@Autowired、@Value和@Resource、@PostConstruct、@PreDestroy注解的解析,既然解析了,肯定是要使用,那么接下来咱们看看spring是怎么处理的
了解源码之前,咱们先想几个问题
那spring是如何做的呢?属性有哪些类型呢?
咱们继续看看spring源码中是如何进行赋值的
AbstractAutowireCapableBeanFactory.populateBean 从bean定义信息中给bean赋值
前面咱们了解过了,所有的xml,注解等都会被解析成beanDefinition,bean定义信息装载了bean所需要的各种信息,但是注解处理的过程有些不一样,接下来咱们看下注解是如何给属性赋值的
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 验证是否跳过
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}else {
return;
}
}
// 给 InstantiationAwareBeanPostProcessors 一个机会来修改bean信息,返回false即可结束下面的流程
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 取出所有的属性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 可以在xml中指定属性autowire="byName"
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 这里为true
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
// 如果不是xml配置
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// CommonAnnotationBeanPostProcessor.postProcessProperties
// AutowiredAnnotationBeanPostProcessor.postProcessProperties
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 填充xml中的属性
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 这里上篇简单的看过了,就是获取注解信息,如果有重复的配置,删除外部的,沿用注解的,类似合并bean的定义信息
// 返回封装后的元素信息
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
// 执行注入
metadata.inject(bean, beanName, pvs);
}catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
// 这里在获取元素据的时候有可能会删除掉一部分属性配置
return pvs;
}
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) {
element.inject(target, beanName, pvs);
}
}
}
不管是使用属性的方式,还是使用set方法的方式赋值,都需要获取目标对象(需要注入的值)
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {
// 如果是字段的话,直接使用反射的set方法赋值
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
// 获取完对象后,直接给属性赋值
field.set(target, getResourceToInject(target, requestingBeanName));
}else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
// 如果是set方法添加了注解,那么调用对应的set方法
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
// 获取完对象后,直接给属性赋值
method.invoke(target, getResourceToInject(target, requestingBeanName));
}catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
// 如果需要代理那么需要返回代理对象,如果不需要代理,那么直接通过BeanFactory进行获取
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :getResource(this, requestingBeanName));
// 从这里可以看出,这是一个大的递归过程,getBean,doGetBean,createBean,doCreateBean...
resource = factory.getBean(name, element.lookupType);
@Autowired和@Resource很类似,@Value就是解析表达式,然后去掉${},再去配置文件中获取,拿到值直接设置
// 还是熟悉的配方
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}catch (BeanCreationException ex) {
throw ex;
}catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
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) {
element.inject(target, beanName, pvs);
}
}
}
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
// 如果有解析过,直接获取
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}catch (NoSuchBeanDefinitionException ex) {
value = resolveFieldValue(field, bean, beanName);
}
}else {
// 从工厂中获取
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
// 反射赋值
field.set(bean, value);
}
}
其实这里也很简单,就是去spring容器中获取对应的值。但是需要注意下,如果注入的是spring中的bean对象,那么就会直接走spring的获取流程,如果是@Value注解呢
咱们先来想几个问题
spring内容包含三部分
/** System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
spring内容包含三部分,从下图可以看出,spring在获取配置的时候,先去environmentProperties中去获取,系统配置包括两部分,先去系统配置中获取,如果获取不到,再去系统环境中获取,如果再获取不到,去本地配置中获取,不管在哪个环节中获取到了,直接返回。这里可以告诉我们,系统配置的优先级最高,比如咱们在shell脚本中配置了某项,优先级肯定比本地配置文件的要高的原因