Spring基础复习-SpringIOC

项目地址:https://gitee.com/chuyunfei/learn.git
一、springIOC和DI的概念
:spring的IOC和DI完成了对对象的创建任务和对象之间的依赖关系的管理任务,实现了对象之间的解耦。

1.因为要对对象,也就是Bean进行管理,所以需一个存放Bean的容器,低级的是:XmlBeanFactory,高级的是:ApplicationContext系列。
2.因为要管理对象,所以需要一个用来描述对象及其依赖关系的一个配置文件,也就是常见的:applicationContext.xml 用于描述对象之间的依赖关系
3.因为需要对配置文件进行解析,所以需要一个解析对应配置的解析器,可能是注解解析器,也可能是XML解析器。
4.容器本身还有自己的生命周期管理,包括容器的刷新,容器及其bean的加载、创建、销毁等。

二、spring容器的构建过程
:spring加载配置文件并创建bean以及维护组件关系的过程,以及bean的生命周期管理

1、加载配置文件-》解析配置文件生成并注册类信息-》生成bean并依赖注入
2、bean的生命周期:构造-》注入属性-》注入环境-》初始化相关方法-》销毁
    1. 执行bean的构造函数构建一个bean。
    2. 为bean的属性注入值
    3. 如果实现了BeanNameAware接口,调用setBeanName(String beanId)方法。
    4. 如果实现了BeanFactoryAware接口,调用setBeanFactory(),传递的是Spring工厂本身。
    5. 如果实现了ApplicationContextAware接口,调用setApplicationContext(ApplicationContext)方法,传入Spring上下文。
    6. 如果关联了BeanPostProcessor接口,调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用After方法,也可用于内存或缓存技术
    7. 如果在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法
    8. 如果关联了BeanPostProcessor接口,会调用postAfterInitialization(Object obj, String s)方法
        注意:以上工作完成以后就可以用这个Bean了,那这个Bean是一个single的,所以一般情况下我们调用同一个ID的Bean会是在内容地址相同的实例
    9. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean接口,会调用其实现的destroy方法
    10. 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法

三、springIOC的配置文件相关配置基础知识
:运用配置文件对spring容器的bean进行关系管理,学会使用spring容器

1.配置文件:
    -》位置:注意classpath是指编译过后的classes路径,不同的框架对这个的定义不同,一定要注意。
    -》名称:最好遵循一些默认规则,但是配置文件的名称是可以随便写的
2.基础语法如下面的配置文件所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-4.0.xsd
     http://www.springframework.org/schema/util
     http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!--
    《bean节点的主要属性注释》
    id和name属性的详细解释:
    https://blog.csdn.net/shjniu3000/article/details/70226182
    1、一个bean可以只有id,只有name或多个name,既有id也有name或多个name,还能id和name都没有(这个bean将是一个匿名的对象,不可见);
    2、id只能有0或者1个,name可以有0或多个,但是多个name不能相同;
    3、当有id时,id作为这个bean在容器内的唯一标识符,name作为这个bean的别名
       当没有id时,第一个name作为这个bean在容器内的唯一标识符,其他的name作为这个bean的别名
    4、可以通过别名和标识符来获取一个bean,因为他们都可以唯一标识一个bean,一个bean可以拥有一个标识符和多个别名
    5、可以显式的为一个bean起别名:<alias name="[一个已经存在的标识符或者别名]" alias="[新的别名]"/>
    6、name可以同时起多个,用 ';',' ',','进行分割,但是id不行,因为id是唯一的

   class属性的详细解释:
   1、springIOC容器使用反射的方法注册bean,所以需要一个默认的无参构造函数(非必须:使用构造注入就不需要默认构造器)
   2、全限定类名用于反射

   scope属性详细解释:
   1、singleton为默认值,即单例,整个容器里面只有一个实例,而prototype会在每一次获取的时候都会创建一个新的实例
   2、singleton的生命周期由容器来管理,但是prototype的生命周期得你自己管理

   primary属性详细解释:
   1、是否首要,当bean在autowired是byType时,如果首选为true就将其作为注入的bean,否则,当找到多余的相同类型的bean时将报错。
   2、如果设置两个首要时也会报错,所以要保证在进行同一种的byType的自动注入时只有一个首要的bean

   depends-on属性详细解释:
   1、标识该bean在进行实例化之前,所依赖的bean必须先实例化,该bean要依赖那个bean,所以当依赖的bean没有时候实例化失败
    -->
    <bean id="person" name="person1;person2 person3,person4" class="springBasic.pojo.basic.Person"
          scope="prototype" primary="true" depends-on="environment">
        <!--
        《使用property节点为bean的属性进行注入》
        1、简单赋值可以使用:
            -》简单的数据类型如字符串、数字可以使用value属性直接进行赋值,name是bean的属性名称
            -》如果有特殊的字符需要使用特殊的赋值方式:<![CDATA[特殊字符]]>
            -》赋值为null需要一节点的方式进行赋值:<value><null/></value>.
            -》value既可以作为属性也可以作为一个子节点:<value>
        2、如果使用<property>进行值注入时,必须为类的相应字段配置setter和getter,将字段变成属性
        -->
        <property name="idCard" value="2016211050"/>
        <property name="name">
            <value><![CDATA[<~^楚云飞^~>]]></value>
        </property>
        <property name="age" value="20"/>
    </bean>
    <!--起别名-->
    <alias name="person" alias="person5"/>
    <!--直接使用P命名空间进行属性赋值,值用属性,引用值用属性值-ref进行赋值-->
    <bean name="personp" class="springBasic.pojo.basic.Person" p:idCard="2016211050" p:name="楚云飞" p:age="20" />

    <!--
    1、与student形成依赖闭环
    2、自动装配
    -->
    <bean name="clazz" class="springBasic.pojo.basic.Clazz" depends-on="student" autowire="byName">
        <property name="id" value="03011603"/>
        <!--引用一个独立的集合:将自动的找到容器里面的域属性名称相同的bean给注入进来-->
        <!--<property name="students" ref="students"/>-->
        <property name="studentMap">
            <!--在内部配置map,也可以在外部配置为一个独立的map,类似的还有set,property-->
            <map>
                <!--spel表达式:https://blog.csdn.net/a1610770854/article/details/51908390-->
                <entry key="#{student.studentNumber != null?'2016211051':'2016211050'}" value-ref="student"/>
            </map>
        </property>
    </bean>

    <bean name="student" class="springBasic.pojo.basic.Student">
        <!--
        《使用指定的构造函数进行实例的构造》
        1、使用<name,value/ref,[index],[type]>属性座标唯一确定一个构造函数
        2、注意依赖回环,所以clazz使用字段依赖,而不是构造器依赖,否则将形成依赖闭环,导致创建失败
        3、依赖闭环的避免:破坏构造器依赖闭环,spring会使用三级缓存来解决字段闭环依赖,但是无法解决构造器闭环依赖
           依赖闭环的解决依赖于提前曝光实例引用的方法,所以必须先构造函数,否则将依赖管理失败。
           https://blog.csdn.net/u010853261/article/details/77940767   //依赖闭环
        -->
        <!--Student(String name,Long idCard,Integer age,Long studentNumber,Double liveCost)-->
        <constructor-arg name="name" value="楚云飞" index="0" type="java.lang.String"/>
        <constructor-arg name="idCard" value="2016211050" index="1" type="java.lang.Long"/>
        <constructor-arg name="age" value="20" index="2" type="java.lang.Integer"/>
        <constructor-arg name="studentNumber" value="2016211050" index="3" type="java.lang.Long"/>
        <constructor-arg name="liveCost" value="1200.20" index="4" type="java.lang.Double"/>
        <!--使用字段依赖,因为和clazz形成了闭环依赖,所以使用字段依赖来解决闭环-->
        <property name="clazz" ref="clazz"/>
        <!--
        为级联属性进行赋值必须先实例化后才能进行级联赋值:这个修改会对clazz本身产生影响
        1、在进行bean注册时,先解析到clazz实例,但是其依赖student实例,所以转移到student实例来进行初始化,同时将clazz的
           引用放置到三级缓存,在实例student的过程中需要依赖clazz实例,于是去一级缓存里面找,没有,于是重新回到clazz实例
           的创建过程,并将student实例的引用放入三级缓存,然后clazz将构建完成并将其放置到一级缓存里面,然后将再次回到student
           的构建过程,于是student的clazz字段将引用一个创建完成的clazz实例,在进行如下的级联赋值时,容器里面的clazz实例的
           属性也将同时改变,至此,clazz的id属性为:03011602而不是03011603
        -->
        <property name="clazz.id" value="03011602"/>
    </bean>
    <!--一个独立的集合,是一个ArrayList,元素是Student-->
    <util:list id="students" scope="singleton" list-class="java.util.ArrayList" value-type="springBasic.pojo.basic.Student">
        <ref bean="student"/>
    </util:list>
    <!--通过一个配置文件配置出一个properties
        id=2016211050;name=楚云飞;age=20
    -->
    <util:properties id="testProperties" location="classpath:test.properties"/>

    <!--加载外部配置文件-->
    <context:property-placeholder location="classpath:database.properties" order="1" file-encoding="UTF-8"/>
    <bean name="database" class="springBasic.pojo.basic.Database">
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
    </bean>
</beans>

类如下:
public class Clazz {
    private Long id;
    private List<Student> students;
    private Map<Long,Student> studentMap;

    public Clazz(){
    }

    public Clazz(Long id,List<Student> students,Map<Long,Student> studentMap){
        this.id = id;
        this.students = students;
        this.studentMap = studentMap;
    }

    /****setter and getter ****/
}

public class Database {
    private String user;
    private String password;
    private String driverClass;
    private String jdbcUrl;

    /****setter and getter ****/
}

public class Person {
    private String name;
    private Long idCard;
    private Integer age;

    public Person(){
    }

    public Person(String name,Long idCard,Integer age){
        this.name = name;
        this.idCard = idCard;
        this.age = age;
    }

    /****setter and getter ****/
}

public class Student extends Person {
    private Long studentNumber;
    private Clazz clazz;
    private Double liveCost;

    public Student(){
    }

    public Student(Long studentNumber,Clazz clazz,Double liveCost){
        this.studentNumber = studentNumber;
        this.clazz = clazz;
        this.liveCost = liveCost;
    }

    public Student(String name,Long idCard,Integer age,Long studentNumber,Clazz clazz,Double liveCost){
        super(name,idCard,age);
        this.studentNumber = studentNumber;
        this.clazz = clazz;
        this.liveCost = liveCost;
    }

    public Student(Long studentNumber,Double liveCost){
        this.studentNumber = studentNumber;
        this.liveCost = liveCost;
    }

    public Student(String name,Long idCard,Integer age,Long studentNumber,Double liveCost){
        super(name,idCard,age);
        this.studentNumber = studentNumber;
        this.liveCost = liveCost;
    }

    /****setter and getter ****/
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章