诸如 @Autowired、@Inject、@Resource 是如何将实例注入到属性的。
BookService,给其中用不同注解,注入不同的dao实例
@Service
public class BookService {
@Autowired(required=true)
private BookDao bookDao;
@Inject
private BookDao2 bookDao2;
@Resource
private BookDao3 bookDao3;
@Qualifier("bookDao4")
@Autowired
private BookDao4 bookDao4;
}
随便新建几个dao
@Repository
public class BookDao {
}
@Repository
public class BookDao2 {
}
单元测试 和配置类
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
}
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);
BookService bookService = applicationContext.getBean(BookService.class);
System.out.println(bookService);
}
创建service这种实例,是在 容器refresh方法的最后一步,finishBeanFactoryInitialization,我直接将断点设置在preInstantiateSingletons方法上,将断点调试为创建 BookService,然后一步步看如何依赖注入。
一直debug到doCreateBean.
AbstractAutowireCapableBeanFactory.doCreateBean
首先会创建bean,然后遍历 MergedBeanDefinitionPostProcessor (一种后置处理器)修改bean定义。
其中有两个 MergedBeanDefinitionPostProcessor 需要讲,AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor。
AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata 寻找参数bean有关Autowired注解的元数据,就是bean有哪些属性注解了@Autowired。
buildAutowiringMetadata里面是用反射找,并且放入缓存,后面会用到。
BookService找到了三个有关Autowired的元数据,即三个属性。
对比演示示例,说明@Autowired、@Inject、@Qualifier都是用这个AutowiredAnnotationBeanPostProcessor可以解析。
而CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition完成@Resource元数据的寻找,并放入缓存。
继续doCreateBean创建BookService实例
进入populateBean,直接看 完成成注入的一步。
遍历InstantiationAwareBeanPostProcessor执行postProcessPropertyValues,其中需要看的是CommonAnnotationBeanPostProcessor 和AutowiredAnnotationBeanPostProcessor。
CommonAnnotationBeanPostProcessor.postProcessPropertyValues()完成@Resource 的注入。
进入metadata.inject,遍历elementsToIterate 就是要注入的属性
用反射注入属性值,因为当前要注入的属性是 BookDao3,这个实例还没有,所以继续debug会发现会用工厂创建BookDao3,就会进入创建bean流程。
再看AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues,找到标注Autowired注解的属性,并完成注入。
CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor 分别类上注解解析了@Resource 和@Autowired、@Inject的属性信息,并完成注入,如果容器中没有属性需要的实例,就会创建再注入。
@DependsOn自定义表明当前bean需要依赖些bean,Spring会优先创建依赖bean到容器中。
BookService依赖一个名为color2的bean,配置类中注入了这个bean。
@Service
@DependsOn(value = "color2")
public class BookService{
}
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
@Bean
public Color color2(){
Color color = new Color();
return color;
}
}
依然将断点设置到 创建BookService时,AbstractBeanFactory.doGetBean方法。
其中在bean定义中会寻找到依赖的bean,优先创建注册。
假设有两个实例bean,A和B,A的属性注入了B实例,B的属性又注入了A,互相注入了对方实例,无线套娃,就叫循环依赖。
首先说明,spring中,只支持在属性注入的循环依赖,如果是通过构造方法注入是不支持循环依赖的。
BookService注入了BookDao
@Service
public class BookService {
@Autowired(required=true)
private BookDao bookDao;
}
BookDao注入了BookService
@Repository
public class BookDao {
@Autowired
private BookService bookService;
}
跟上边一样的配置了和单元测试,运行结果:
看原理前先看一个匿名内部类的应用:
一个工厂接口
public interface ObjectFacoryTest {
Object getObject();
}
单元测试, 循环在集合中加入 工厂接口的匿名内部类实现,重写方法调用测试类的getnum方法返回数字,最后遍历工厂将数字打印。结果0-9打印
把断点设置到创建BookService,在 AbstractAutowireCapableBeanFactory的 doCreateBean方法
下图,判断实例单例、允许循环依赖、当前实例正在创建中,则执行 addSingletonFactory 方法,参数是匿名内类,内部类重写方法getObject 其中调用了 AbstractAutowireCapableBeanFactory.getEarlyBeanReference。
注意 getObject 可以得到beanName对应的bean实例,即使是还没初始化的实例。
进入addSingletonFactory,判断当前bean是否在 singletonObjects中(bean如果完整创建就存在),这里还不存在,所以将参数工厂放入singletonFactories,以及其他缓存操作。
这里涉及到几个缓存:
在上边依赖注入中讲过,populateBean会完成注入操作,将BookDao注入BookService,但此时BookDao实例还不在容器中,继续debug会发现流程又走到了 doCreateBean,去创建BookDao。
但BookDao也要注入BookServic实例,刚刚BookService并没有创建成功,但是几个缓存中只有singletonFactories 和registeredSingletons有BookService的信息。
我们来debug 创建BookDao时的populateBean方法,看在BookService没有创建完成的情况下,BookDao是如何创建成功的?
依然是InstantiationAwareBeanPostProcessor遍历执行。因为BookDao中的属性bookService是用@Autowired注入的,所以由 AutowiredAnnotationBeanPostProcessor完成属性注入。
AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues,首先找到了BookDao中由@Autowired注解的属性bookService
断点进入inject方法,由beanFactory.resolveDependency会得到一个实例值。
进入 doResolveDependency方法,里面大概是寻找符合的bean,如果bean数量大于1怎么处理之类的,最后执行流程会进入AbstractBeanFactory.doGetBean,很熟悉,又是从bean工厂获取BookService实例。
但是这次不会再新创建实例,而是在 getSingleton方法直接得到一个bean。
之前将BookService 在创建bean对应的实例工厂缓存起来,这里调用工厂可以得到之前的 正在创建中的BookService bean,
得到后销毁这个BookService实例工厂,并将这个bean放在了 earlySingletonObjects 早期bean缓存中。
getSingleton方法中优先去earlySingletonObjects缓存获取bean,不难想到,如果其他类也循环依赖了BookService 就可以从earlySingletonObjects拿到正在创建的 BookService 实例。
到这步为止,创造BookDao的过程中就将 正在创建的BookService实例拿到了,拿到后继续执行inject方法,就完成了把BookService注入BookDao.
从线程执行流程也可以看到,BookDao的创建流程 是由BookService创建时的populateBean方一步步发起的。
当BookDao创建完成时,继续执行BookService的属性注入
在AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues方法,断点进入inject方法,拿到了BookDao实例,反射将其注入BookService.到此完成了循环依赖
这里的BookService bean和 earlySingletonObjects中的BookService bean是一个bean,可以往前追踪,这里的bean是来自于BeanWrapper,bean的包装。
而earlySingletonObjects的bean来自于singletonFactories,singletonFactories的bean也来自于BeanWrapper。