Spring中你要给属性赋值通常有三种方式
1.@Bean注解中自带的属性@Bean(autowire = Autowire.BY_TYPE/Autowire.BY_NAME)
2.通过@Autowired/@Resource注解
3.在Bean实例化完成之后重写postProcessMergedBeanDefinition方法手动为BeanDefinition注入值;
1.@Bean注解更多的作用是在Spring容器中添加一个Bean,但是如果设置了autowire = Autowire.BY_NAME/Autowire.BY_TYPE这个属性,那么Spring在生成这个Bean的时候会去扫描当前Bean中的set方法,如果是Autowire.BY_NAME,比如是setxxx方法,那么会去singletonObjects(单例池)中找到name = xxx的Bean并将其注入到setxxx方法中的参数中,如果是Autowired.BY_TYPE,那么会解析setxxx(Type1 name1,Type2 name2)中的Type1,Type2的类型,然后根据这两种类型去寻找Bean然后将其注入到name1,name2中,代码如下。
public class AppConfig {
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService(){
return new UserService();
}
}
public class UserService {
private OrderService orderService;
private MyService myService;
public void test() {
System.out.println("orderService: "+this.orderService);
System.out.println("myService: "+this.myService);
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void setMyService111(MyService myService) {
this.myService = myService;
}
}
public class Test {
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
}
}
可以看出,上述的代码并没有在OrderService和MyService上加@Autowired或者@Resource等注解去注入,但是打印出的结果却不是null,而是有值的,Spring中对应的源码如下,autowireByName方法的逻辑如下->根据setxxx方法解析出xxxBeanName,然后从Spring中去找,然后再将其放到MutablePropertyValues中->pvs.add(propertyName, bean);type也是同理,最后会在applyPropertyValues(beanName, mbd, bw, pvs)方法中处理pvs中的值,并且通过这种方式的赋值会覆盖@Autowired注解的赋值,因为这行代码是放在最后的,在这之前会先通过调用AutowiredAnnotationBeanPostProcessor.postProcessProperties方法解析@Autowired注解和CommonAnnotationBeanPostProcessor.postProcessProperties方法解析@Resouce注解,通过这两个BeanPostProcessor来为添加了@Autowired和@Resouce的属性赋值
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// MutablePropertyValues是PropertyValues具体的实现类
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
//遍历属性并将其设置到pvs中去,然后记录在dependencyMap中,这个Bean依赖了某些属性的Bean,但不会将遍历得到的Bean注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
2.解析@Autowired注解和@Resource注解来为属性赋值,Spring中分成了四个BeanPostProcessor,其中有一个是InstantiationAwareBeanPostProcessor,每一个Spring的Bean在执行他的生命周期的时候都会调用这些BeanPostProcessor里面的方法,以下是执行和属性赋值相关的逻辑代码,在AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor中的postProcessProperties方法中会处理和@Autowired和@Resource这两注解
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值
// AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
}
这边就挑Autowired注解相关的逻辑看一下,主要就是分为两步,第一步是找到注入点(就是加了@Autowired注解的属性和在setxxx方法上加@Autowired注解),并且缓存下来,第二步是给这些注入点注入值,以下是核心的两个方法
//找注入点,加了@Autowired/@Inject/@Value注解的属性和方法
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
//注入值
metadata.inject(bean, beanName, pvs);
解析注入点的代码如下,这边就拿属性来举个栗子,方法那边其实也是同理,不过有一个桥接,可能比较特殊(这块自己去了解一下,本文不做其他概述),下面的代码就是会去通过反射一个个找当前属性上是否有@Autowired/@Value/@Inject注解,但是会过滤静态属性/方法(你如果是这个Bean是原型Bean,那么你每次都会去创建新的Bean,然后你这个属性也会跟着创建一个新的,这样和静态的原理是相违背的),然后找到了就直接构造成一个注入点,放到一个list中,在方法中也是一样,最终这些注入点都会加到list里面。然后调用inject方法进行属性赋值
// 遍历targetClass中的所有Field
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// field上是否存在@Autowired、@Value、@Inject中的其中一个
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// static filed不是注入点,不会进行自动注入
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));
}
});
以下是属性注入的核心逻辑,就是通过反射拿到他的field,然后给target的field属性注入getResourceToInject方法返回的值,target就是我们正在创造的Bean,requestingBeanName就是beanName,此方法中会根据你传入的beanName去BeanFactory里面找到唯一的值(这是核心逻辑,但是代码很长)
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
3.在Spring中你可以通过实现MergedBeanDefinitionPostProcessor接口中的postProcessMergedBeanDefinition方法来为正在创建的Bean中的属性手动赋值,使用方法如下,如果你正在创建的Bean中有OrderService这个属性,那么他会为其赋值,这种形式的赋值其实和第一种差不多,都是放到了PropertyValues中,最后调用applyPropertyValues方法解析PropertyValues存放的注入点并且赋值
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
MutablePropertyValues orderService = beanDefinition.getPropertyValues().add("orderService", new OrderService());
}