我们会经常使用@Autowired、@Resource、@Value 这些注解给属性赋值。
那么这几个注解是怎么给属性赋值的呢?还有其他的方法可以给属性赋值吗?
使用@Bean注解+set方法,设置依赖注入方式(byName,byType)。
配置类
bean
测试
上面几张图:在配置类中使用@Bean 注解并设置注入方式, 配置bean。
这种方式在spring中已经被定义为过期的方法,但是还能用,只是spring不建议使用。
person类的属性上并没有加@Autowired,但是也能注入成功。
上图这段代码就是记录这种注入方式的代码,记住是记录,意思是说:只要用这种方式注入bean的spring都会在这个地方记录,就是将这些bean的名字存到一个集合中,方便后续注入。
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
PropertyDescriptor:属性描述器, 是javaBean 里自带的。在这个属性描述器里会记录属性的名字,属性的set 方法 ,get方法,等等。
前提是必须要有set方法或是get方法,如果一个类里只定义了属性,没有set方法或则是getf方法,那么也是拿不到这个属性的。
PropertyDescriptor中的name属性是通过解析set方法获取的。例如:setOr123 , 那么name属性的值就是 or123。
spring 在拿到所有属性后进行循环遍历
for (PropertyDescriptor pd : pds) {
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
result.add(pd.getName());
}
}
- pd.getWriteMethod() != null : 将没有set方法的属性给过滤掉。
- !pvs.contains(pd.getName()) : 将在MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition方法中赋值过的属性过滤掉。
- !BeanUtils.isSimpleProperty(pd.getPropertyType()): 将简单类型的属性过滤掉。
上图这个方法的最后面,就是下面这段代码
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
将记录属性进行赋值。
@Autowired,@Value,@Resource给属性赋值
上图中的1是处理 @Autowired,@Value ,2是处理@Resource。
以下主要看是AutowiredAnnotationBeanPostProcessor 这个实现类。
上图中可以看到 AutowiredAnnotationBeanPostProcessor 实现了SmartInstantiationAwareBeanPostProcessor 和 MergedBeanDefinitionPostProcessor 这两个接口。
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition寻找注入点
根据类找到注入点
注入点:加了@Autowired 的属性或者方法。
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
上述代码就是拿到类的所有属性,然后循环判断属性上面有没有加注解(@Autowired或@Value只要有一个注解就行)如果有注解且不是静态属性,就会加入到缓存中 currElements。
1.静态的属性属于类的,不依赖于某个对象,也可以称为类属性。不同的对象都可以访问到类的属性。带参数的构造方法中不能包含静态的属性。 它的生命随着类的消亡而消亡。
2.非静态属性只能属于某个对象,其它的对象不能访问它的属性。随着对象的消亡而消亡。
boolean required = determineRequiredStatus(ann);
这行代码的作用 就是处理 required 的,如果等于true 就是必须要给该属性赋值,如果没有值就会报异常。
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
上述这段代码是处理方法的,和上面的属性大致差不多。
唯一不同的是:
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
这个就是处理桥接方法,有兴趣的可以搜一下。
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
这段代码就是判断这个bean 的类型。如果是String等基础数据类型则不需要寻找注入点,就会直接返回。
SmartInstantiationAwareBeanPostProcessor.postProcessProperties 主要是处理属性
在拿到注入点后就会执行这个方法,这个方法中会找到注入点的值,并给注入点赋值。
标号1的地方是找值,找到值后,就会执行标号2 ,给注入点赋值。