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 ****/
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章