Inverse Of Controll
:控制反转反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
Dependency Injection
:依赖注入全新的依赖满足方式,体现在编码中就是全新的赋值方式 ==>
在工厂中为属性推送值
如:
IOC(DI)
,即,是一码事
IOC 是思想
:指导我们在满足依赖时,应该有反转的设计。
DI 是手段
:实际操作时,就是在一次次的 注入
spring官方文档中,关于DIhttps://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-collaborators的解释:
This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes or the Service Locator pattern
- set注入:
- 借助set方法完成注入
- 构造注入 (了解)
- 借助构造方法完成注入
- 自动注入
- spring自动识别属性,并注入
<bean id="setDI" class="x.xx.XXX">
<property name="age" value="18">property>
<property name="name" value="zhj">property>
<property name="gender" value="true">property>
<property name="userDAO" ref="ud">property>
<property name="list">
<list>
<value>18value>
<ref bean="ud"/>
list>
property>
<property name="xxx">
<set>
<value>xxvalue>
set>
property>
<property name="map">
<map>
<entry key="name" value="zhj">entry>
<entry key="userDAO" value-ref="ud">entry>
map>
property>
<property name="prop">
<props>
<prop key="url">jdbc:oracle:xxxxprop>
props>
property>
bean>
<bean id="consDI" class="com.test.TestConstrutorDIComponent">
<constructor-arg index="0" type="java.lang.Integer" value="18">constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="zhj">constructor-arg>
<constructor-arg index="2" type="java.lang.Boolean" value="true">constructor-arg>
bean>
由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值
<bean id="xx" class="xxx" autowire="byName">bean>
<bean id="xx" class="xxx" autowire="bytype">bean>
此处,掌握
byName
和byType
的概念即可。基于类型 自动注入时,如果存在多个此类型的bean,会报错。
反射,加载类对象,默认调用无参构造,创建对象。
<bean class="xx.xx.xxx.XXX" id="xxx">
// 反射
String classpath="com.zhj.domain.User";
Class user = Class.forName(classpath);
Constructor constructor = user.getConstructor();
User o = (User)constructor.newInstance();
对象的状态:对象的成员变量值 即 对象的状态
无状态:不同的用户,不同的请求,对象的属性值不会发生改变
有状态:不同的用户,不同的请求,对象的属性值会发生改变
有状态对象:多例模式
无状态对象:单例模式
单例bean:构造(工厂启动)–>set–>init–>User–>destroy(工厂关闭)
多例bean:获取时才创建–>set–>init–>User–>不会随工厂关闭而销毁
FactoryBean
:生产某一类对象
在工厂中有些bean,无法直接通过 简单的
生产。
比如:Connection,SqlSessionFactory
FactoryBean:spring工厂中一种特殊的bean,可以生产对象。Spring工厂中的小作坊。
Spring支持如下方式:
// 1.实现FactoryBean
public class MySqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>{
public SqlSessionFactory getObject(){
//完成SqlSessionFactory的生产,并返回生产的对象
}
...
}
<bean id="sqlSessionFactory" class="com.zhj.factory.MySqlSessionFactoroyBean">bean>
// 2.静态工厂方法
public class MyFactoryBean {
public static User createUser(){
return new User();
}
}
<bean id="user" factory-method="createUser" class="com.zhj.factory.MyFactoryBean" scope="(这里指作用域)">bean>
// 3.工厂方法
public class MyFactoryBean {
public User createUser(){
return new User();
}
}
<bean id="userFactory" class="com.zhj.factory.bean.MyFactoryBean">bean>
<bean id="user" factory-bean="userFactory" factory-method="createUser" scope="xx">bean>
定义了如上任何一种后,测试:
//获取bean,此时获取的并不是FactoryBean,而是其生产的对象。
SqlSessionFactory sqlSessionFactory = (sqlSessionFactory)context.getBean("sqlSessionFactory");
//获取bean,此时获取的并不是FactoryBean,而是其生产的对象。
User user = (User)context.getBean("user");
Bean创建过程:运行过程,对应核心API,直到反射层面。
这里为了有想下去自己调试代码给予方便,AbstractApplicationContext#refresh这段代码表示意思:“#”号前面是类名 ,后面则为方法名。
new ClassPathXmlApplicationContext(String[] configLocations,boolean refresh,ApplicationContext parent){
//...;
refresh();//创建主流程
//...;
}
AbstractApplicationContext#refresh(){
//...;
// 创建BeanFactory,(DefaultListableBeanFactory)
// 并解析spring配置文件,进而加载BeanDefinitions
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//...;
finishBeanFactoryInitialization(beanFactory);//创建所有单例的bean
//...;
}
AbstractApplicationContext#obtainFreshBeanFactory() {
...
// 解析xml文件,加载BeanDefinitions
refreshBeanFactory();
...
}
AbstractApplicationContext#refreshBeanFactory(){
...
// 加载BeanDefinitions
loadBeanDefinitions(beanFactory);
...
}
AbstractApplicationContext#finishBeanFactoryInitialization(){
//...;
beanFactory.preInstantiateSingletons();//创建所有单例的bean
//...;
}
DefaultListableBeanFactory#preInstantiateSingletons(){
for (String beanName : beanNames) {//遍历所有的beanName,挨个创建对象
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//非抽象+单例+非延迟,则创建
if (isFactoryBean(beanName)) {//是否为工厂bean
FactoryBean fb = getBean("&"+beanName);//获得工厂Bean对象本身
//....
getBean(beanName);//创建实际对象,此中会通过工厂Bean获得
}else{
getBean(beanName);//普通bean,直接创建对象
}
}
}
}
AbstractBeanFactory#getBean(){
return doGetBean(...);
}
AbstractBeanFactory#doGetBean(){
//....
if (mbd.isSingleton()) {
//注意:此处有回调 ObjectFactory#getObject()
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {//获得或创建单例的bean
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);//回调方法,创建bean
}
//...
}
}
}
DefaultSingletonBeanRegistry#getSingleton(beanName,singletonFactory){
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);//尝试获取,如果有则不再创建
//....
singletonObject = singletonFactory.getObject();//回调doGetBean中内部类的方法,创建单例bean
//....
//记录当前bean的 ObjectFactory,ObjectdFactory中调用了createBean(...)方法可以创建当前bean
//createBean(...)方法是AbstractBeanFactory的父类AbstractAutowireCapableBeanFactory中的方法
addSingleton(beanName, singletonObject);//记录当前bean的 ObjectFactory
}
}
//回调doGetBean中内部类“ObjectFactory”的getObject方法,创建单例beanAbstractAutowireCapableBeanFactory#createBean(){ //..... doCreateBean(beanName, mbdToUse, args);//创建单例bean}
AbstractAutowireCapableBeanFactory#doCreateBean(){
//.....
if (instanceWrapper == null) {
// 创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
}
AbstractAutowireCapableBeanFactory#createBeanInstance(){
//.....
return instantiateBean(beanName, mbd);//使用无参构造创建bean
}
AbstractAutowireCapableBeanFactory#instantiateBean(){
//.....
// 创建bean实例
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
SimpleInstantiationStrategy#instantiate(){
//....
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);//获得构造方法对象
//....
return BeanUtils.instantiateClass(constructorToUse);//反射构建bean
}
看到这里,大家对构建bean的原理基本上有了了解,源码还是有些难调试的,由于代码类名以及方法名过长,看着是真痛苦,有些地方自己也没有完全弄明白。