Spring进阶——Spring使用和Bean创建原理

1. IOC

`Inverse Of Controll`:控制反转

反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)

解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健

2. DI

`Dependency Injection`:依赖注入

全新的依赖满足方式,体现在编码中就是全新的赋值方式 ==> `在工厂中为属性推送值`

如:``

3. IOC 和 DI

在spring中关于IOC和DI的描述是这样的: `IOC(DI)`,即,是一码事

`IOC 是思想`:指导我们在满足依赖时,应该有反转的设计。

`DI 是手段`:实际操作时,就是在一次次的 注入

spring官方文档中,关于[DI](https://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`

4.DI的配置使用

1. DI的方式

  • set注入
  • 借助set方法完成注入
  • 构造注入 (了解)
  • 借助构造方法完成注入
  • 自动注入
  • spring自动识别属性,并注入

2. set注入(使用较为频繁)

<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>

3. 构造注入 (较少使用)

<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>

4.自动注入

不用在配置中 指定为哪个属性赋值,及赋什么值.

由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值


<bean id="xx" class="xxx" autowire="byName">bean>

<bean id="xx" class="xxx" autowire="bytype">bean>

此处,掌握 `byName``byType` 的概念即可。

基于类型 自动注入时,如果存在多个此类型的bean,会报错。

5.Bean细节

1. 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();

2. Bean创建模式

  • singleton:单例 ==> 默认
    • 在同一个spring工厂中,一个bean只会创建一次对象。
    • 多次getBean(),或多次注入使用的是同一个对象
    • 随工厂创建 而创建,随工厂关闭而销毁
  • prototype:多例 (原型)
    • 每次getBean(),或注入都会重新创建对象
    • 不随工厂创建 而创建,不随工厂关闭而销毁
    • 被用到时才会创建对象

对象的状态:对象的成员变量值 即 对象的状态
无状态:不同的用户,不同的请求,对象的属性值不会发生改变
有状态:不同的用户,不同的请求,对象的属性值会发生改变

有状态对象:多例模式
无状态对象:单例模式

3. 生命周期

单例bean:构造(工厂启动)–>set–>init–>User–>destroy(工厂关闭)
多例bean:获取时才创建–>set–>init–>User–>不会随工厂关闭而销毁

6. 工厂Bean

FactoryBean:生产某一类对象
在工厂中有些bean,无法直接通过 简单的生产。

比如:Connection,SqlSessionFactory
FactoryBean:spring工厂中一种特殊的bean,可以生产对象。Spring工厂中的小作坊。

Spring支持如下方式:

6.1 FactoryBean

// 1.实现FactoryBean
public class MySqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>{
    public SqlSessionFactory getObject(){
        //完成SqlSessionFactory的生产,并返回生产的对象
    }
    ...
}

<bean id="sqlSessionFactory" class="com.zhj.factory.MySqlSessionFactoroyBean">bean>

6.2 静态工厂方法

// 2.静态工厂方法
public class MyFactoryBean {
    public static User createUser(){
        return new User();
    }
}
<bean id="user" factory-method="createUser" class="com.zhj.factory.MyFactoryBean" scope="(这里指作用域)">bean>

6.3 工厂方法

// 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");

7. 运行原理

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的原理基本上有了了解,源码还是有些难调试的,由于代码类名以及方法名过长,看着是真痛苦,有些地方自己也没有完全弄明白。

你可能感兴趣的:(Spring,java,JavaEE)