Spring 學習

1.什麼是spring

  • spring是一個開源框架,spring爲簡化企業級開發而生,使用spring可以使簡單的java bean 實現以前只有EJG才能實現的功能
  • spring是一個IOC和AOP容器框架

2.spring的特點

  • 輕量級 spring是非侵入性的 - 基於spring應用的開發中的對象可以不依賴於spring的API
  • 依賴注入 DI
  • 面向切面編程 AOP
  • 容器 spring是一個容器,因爲它包含和管理應用對象的生命週期
  • 框架 spring實現了使用簡單的組件配置組合成一個複雜的應用,在spring中可以使用xml和java註解組合這些對象
  • 一站式 在IOC和AOP的基礎上可以整合各種企業應用的開源框架和優秀的第三方類庫

3 Spring容器

在Spring IOC 容器讀取bean配置、創建bean之前,必須對他進行實例化,只有在容器實例化後,才能從IOC容器裏獲取bean實例並使用它 

3.1 spring提供了兩種類型的IOC容器實現

  • BeanFactory: IOC容器的基本實現
  • ApplicationContext: 提供了更多的高級特性,是BeanFactory的子接口 

    BeanFactory是Spring框架的基礎設施,面向Spring本身;ApplicationContext面向Spring框架的開發者,幾乎所有的應用場合都直接使用ApplicationContext而非底層的BeanFactory

4 IOC

4.1 什麼是IOC

IOC(Inversion of Controller)其思想是反轉資源獲取的方向,傳統的資源查找方式要求組件向容器發起請求查找資源,作爲迴應,適時得返回資源。Dog dog = new Dod();而使用了IOC之後,則是容器主動得將資源推送給他所管理的組件,組件所要做的僅是選擇一種合適的方式來接受資源,這種行爲也被稱爲查找的被動方式。

4.2 什麼是DI

DI(Dependency Injection)IOC的另一種表述方式:即組件以一些預定義好的方式(例如:setter方法),接受來自容器的資源注入,相對於IOC而言,這種表述更直接


5 Bean的配置方式

5.1 通過全類名(反射)

<bean id="person1" class="com.example.demo.bean.Person">
    <property name="name" value="dong"/>
    <property name="age" value="12"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

5.2 通過工廠方法(靜態工廠方法&實例工廠方法)

調運靜態工廠方法創建Bean是將對象創建的過程封裝到靜態方法中,當客戶端需要對象時,只需要簡單地調用靜態方法,而不用關心創建對象的細節。 
要聲明通過靜態方法創建的Bean,需要在Bean的class屬性裏指定擁有該工廠的方法的類,同時在factory-method屬性裏指定工廠方法的名稱。最後,使用constrctor-arg元素爲該方法傳遞方法參數。

<bean id="simpleDateFormat" class="java.text.SimpleDateFormat">
    <constructor-arg value="yyyy-MM-dd hh:mm:ss"/>
</bean>
<bean id="date" factory-bean="simpleDateFormat" factory-method="parse">
    <constructor-arg value="2018-11-11 11:11:11"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5.3 FactoryBean

Spring中有兩種類型的Bean,一種是普通Bean,一種是工廠Bean,即FactoryBean。 
工廠Bean和普通Bean不同,其返回的對象不是指定類的一個實例,其返回的是該工廠Bean的getObject方法所返回的對象

public class PersonFactoryBean implements FactoryBean<Person>{
    // 返回對象
    @Override
    public Person getObject() throws Exception {
        Person person = new Person();
        person.setId(2);
        person.setName("zhu");
        person.setAge(20);
        return person;
    }
    //返回類型
    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }
    //是否是單例
    @Override
    public boolean isSingleton() {
        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

5.4 基於註解配置

Spring能夠從classpath下自動掃描,偵測和實例化具有特定註解的Bean組件

<context:component-scan base-package="com.girhub.dge1992.bean"/>
  • 1
  • 1

特定組件包括:

  • @Component:基本註解,表示了一個受Spring管理的Bean組件
  • @Respository:標識持久層Bean組件
  • @Service:標識服務層Bean組件
  • @Controller:標識表現層Bean組件 

自動裝配類型:

  • @Autowired:根據類型自動裝配
  • @Resource:註解要求提供一個Bean名稱的屬性,若該屬性爲空,則自動採用標註處的變量和方法名作爲Bean的名稱
  • @Inject:和@Autowired很像,只是沒有reqired屬性 

對於掃描到的組件,Spring有默認的命名策略:使用非限定類名,第一個字母小寫,也可以在註解中通過value屬性值標識組件的名稱


6 依賴注入的方式

spring支持3種依賴注入的方式

6.1 屬性注入

使用對象的set方法

<bean id="person1" class="com.github.dge1992.bean.Person">
    <property name="name" value="feng"/>
    <property name="age" value="3"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

6.2 構造器注入

使用對象的構造函數

<bean id="person2" class="com.github.dge1992.bean.Person">
        <constructor-arg value="dong" index="0" type="java.lang.String"></constructor-arg>
        <constructor-arg value="23" index="1" type="java.lang.Integer"></constructor-arg>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

6.3 工廠方法注入(很少使用不推薦)


7 注入屬性值細節

7.1 字面值

可以用字符串表示的值,可以通過元素標籤或value屬性進行注入。 
基本數據類型及其封裝類、String等類型都可以採用字面值注入的方式。

若字面值中包含特殊字符,可以通過<![CDATA[]]>把字面值包裹起來。
<bean id="car1" class="com.girhub.dge1992.bean.Car">
    <property name="name">
        <value type="java.lang.String"><![CDATA[<奔馳>]]></value>
    </property>
    <property name="type" value="高檔車"/>
    <property name="price" value="1000"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

7.2 引用其他bean

組成應用程序的bean經常需要相互協助以完成應用程序的功能,要使bean能夠互相訪問,就必須在bean配置文件中指定對bean的引用。 
在bean的配置文件中,可以通過元素或ref屬性爲bean的屬性或構造器參數指定對bean的引用。 
也可以在屬性或構造器裏包含bean的聲明,這樣的bean成爲內部bean.

<bean id="car1" class="com.girhub.dge1992.bean.Car">
    <property name="name">
        <value type="java.lang.String"><![CDATA[<奔馳>]]></value>
    </property>
    <property name="type" value="高檔車"/>
    <property name="price" value="1000"/>
</bean>
<bean id="person1" class="com.girhub.dge1992.bean.Person">
    <property name="name" value="feng"/>
    <property name="age" value="3"/>
    <property name="car" ref="car1"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

7.3 注入參數詳解:null和級聯屬性

可以使用專用的元素標籤爲bean的字符串或其他對象類型的屬性注入null值,spring支持級聯屬性的配置。

<bean id="person1" class="com.girhub.dge1992.bean.Person">
    <property name="name" value="feng"/>
    <property name="age" value="3"/>
    <property name="car" ref="car1"/>
    <property name="car.name" value="奔馳"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

7.4 集合屬性

在spring中可以通過一組內置的xml標籤(例如:,,)來配置集合屬性。通過指定簡單的常量值,通過指定對其他bean的引用,通過指定內置bean定義,通過指定空元素。 
java.util.Map通過標籤定義,標籤裏可以使用多個作爲子標籤,普通常量使用key和value來定義,bean引用通過key-ref和value-ref屬性定義。. 

使用utility scheme 定義集合 
使用p命名空間,簡化xml文件的配置

<bean id="person1" class="com.girhub.dge1992.bean.Person">
    <property name="name" value="feng"/>
    <property name="age" value="3"/>
    <property name="cars">
        <list>
            <bean class="com.girhub.dge1992.bean.Car">
                <property name="name">
                    <value type="java.lang.String"><![CDATA[<奔馳>]]></value>
                </property>
                <property name="type" value="高檔車"/>
                <property name="price" value="1000"/>
            </bean>
            <bean class="com.girhub.dge1992.bean.Car">
                <property name="name">
                    <value type="java.lang.String"><![CDATA[<奔馳111>]]></value>
                </property>
                <property name="type" value="高檔車111"/>
                <property name="price" value="1000111"/>
            </bean>
        </list>
    </property>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

集合引用外部bean

<bean id="person1" class="com.girhub.dge1992.bean.Person">
    <property name="name" value="feng"/>
    <property name="age" value="3"/>
    <property name="cars">
        <list>
            <ref bean="car1"/>
            <ref bean="car2"/>
        </list>
    </property>
    <property name="names">
        <list>
            <value>AAA</value>
            <value>BBB</value>
        </list>
    </property>
    <property name="carMap">
        <map>
            <entry key="first" value-ref="car1"/>
            <entry key="second" value-ref="car2"/>
        </map>
    </property>
    <property name="nameMap">
        <map>
            <entry key="firstName" value="CCC"/>
            <entry key="secondName" value="DDD"/>
        </map>
    </property>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

8 自動裝配

8.1 bean的自動裝配(註解注入時用到)

Spring IOC 容器可以自動配置bean,需要做的僅僅是在的autowite屬性裏指定自動裝配的模式

  • byType(根據類型自動裝配)
  • byName(根據名稱自動裝配)

8.2 bean自動裝配的缺點

在Bean配置文件裏設置autowire屬性進行自動裝配將會裝配bean的所有屬性。然而,若只希望裝配個別屬性時,autowire屬性就不靈活了。 

autowire屬性要麼根據類型自動裝配,要麼根據名稱自動裝配,不能兩者一起使用。


9 bean之間的關係

9.1 繼承

Spring允許繼承bean的配置,被繼承的bean成爲父bean,繼承這個bean的bean成爲子bean,子bean從父bean中繼承配置,也可以覆蓋bean繼承過來的配置。

<bean id="person1" class="com.girhub.dge1992.bean.Person" p:name="dong" p:car-ref="car1"/>
<bean id="person2" class="com.girhub.dge1992.bean.Person" parent="person1"/>
  • 1
  • 2
  • 1
  • 2

9.2 依賴

Spring允許用戶通過 depends-on 屬性設置 bean 前置依賴的bean,前置依賴的bean會在本bean實例化之前創建好。

<bean id="car1" class="com.girhub.dge1992.bean.Car">
    <property name="name" value="寶馬"/>
</bean>
<bean id="person3" class="com.girhub.dge1992.bean.Person" depends-on="car1"/>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

10 bean的作用域

在Spring中,可以在元素的scope屬性裏設置bean的作用域。 
默認情況下,Spring只爲每個在IOC容器裏聲明的Bean創建唯一一個實例,整個IOC容器範圍內都能共享該實例:所有後續的getBean()調用和Bean引用都將返回這個唯一的Bean實例,該作用域被稱爲singleton,他是所有bean的默認作用域。

類別說明
singleton在Spring容器中僅存在一個bean實例,bean以單例是形式存在
prototype每次調用getBean(),都會返回一個新的實例
request每次HTTP請求都會創建一個新的實例,該作用域適用於WebApplicationContxt環境
session同一個HTTP Session共享一個Bean,不同的HTTP Session使用不同的Bean。該作用域只適合WebApplicationContxt環境

11 使用外部屬性文件

11.1 使用外部屬性文件的好處

完成屬性值和bean的配置的分離,實現解耦

11.2 IOC容器如何引用外部文件

<context:property-placeholder location="文件路徑">
  • 1
  • 1

11.3 如何引用外部屬性文件的值

屬性文件一般是 *.properties 數據以key=value的形式 通過${key}獲取


12 Spring表達式語言:SpringEL

12.1 簡介

Spring表達式語言(簡稱SpEL):是一個支持運行時查詢和操作對象圖的強大的表達式語言

12.2 使用方法

使用#{…}作爲定界符

12.3 SpEL的實現

  • 通過bean的id對bean進行引用
  • 調用方法以及引用對象中的屬性
  • 計算表達式的值
  • 正則表達式的匹配 
    <bean id="car1" class="Car">
            <property name="name" value="寶馬"/>
            <property name="price" value="10"/>
        </bean>
        <bean id="person1" class="Person">
            <property name="name" value="dong"/>
            <property name="car" value="#{car1}"/>
            <property name="age" value="10"/>
        </bean>
        <bean id="person2" class="Person">
            <property name="name" value="#{person1.name.toUpperCase()}"/>
            <property name="car" value="#{car1}"/>
            <property name="age" value="#{person1.age + 10}"/>
        </bean>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

13. bean的生命週期

Spring IOC容器可以管理Bean的生命週期,Spring允許在Bean生命週期的特定點執行定製的任務。在Bean的聲明裏設置init-method 和 destroy-method屬性,爲Bean設置初始化和銷燬方法。 

Spring IOC容器對Bean的生命週期進行生命週期管理的過程:

  • 通過構造器或工廠方法創建Bean實例
  • 爲Bean的屬性設置值和對其他Bean的引用
  • (後置處理器前置方法執行)(可選)
  • 調用Bean的初始化方法
  • (後置處理器後置方法執行)(可選)
  • 可以使用Bean了
  • 當容器關閉時,調用Bean的銷燬方法

13.1 Bean後置處理器

Bean後置處理器允許在調用初始化方法前後對Bena進行額外的處理。 

Bean後置處理器對IOC容器裏的所有Bean實例逐一處理,而非單一實例,其典型作用是:檢查Bean屬性的正確性或根據特定的標準更改Bena的屬性。 

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("後置處理器前置方法執行");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("後置處理器後置方法執行");
        return bean;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

14. AOP

14.1 Java中的代理

代理是一種設計模式,提供了對目標對象另外的訪問方式;即通過代理對象訪問目標對象。這樣做的好處是:可以在目標對象實現的基礎上,增強額外的功能操作,即擴展目標對象的功能。 

14.2 Java動態代理

public class CalculateProxy {
    //代理對象
    private Calculate calculate;
    public CalculateProxy(Calculate calculate) {
        this.calculate = calculate;
    }
    public Calculate getCalculateProxy(){
        ClassLoader classLoader = Calculate.class.getClassLoader();
        Class[] interfaces = {Calculate.class};
        InvocationHandler handler = new InvocationHandler() {
            /**
             *
             * @param proxy          代理的對象
             * @param method         被代理對象的方法
             * @param args           方法參數
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Arrays.stream(args).forEach(e -> System.out.println("參數是:" + e));
                //calculate是目標對象
                Object invoke = method.invoke(calculate, args);
                System.out.println("結果是:" + invoke);
                return invoke;
            }
        };
        /**
         * ClassLoader: 指定當前目標對象使用類加載器,獲取加載器的方法是固定的
         *  Class<?>[]: 目標對象實現的接口的類型,使用泛型方式確認類型
         *  InvocationHandler h: 事件處理,執行目標對象的方法時,會觸發事件處理器的方法,
         *                       會把當前執行目標對象的方法作爲參數傳入
         */
        Calculate calculate = (Calculate) Proxy.newProxyInstance(classLoader, interfaces, handler);
        return calculate;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37


14.3 Cglib動態代理

public class ProxyFactory implements MethodInterceptor {
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    public Object getProxyInstance(){
        //1.工具類
        Enhancer en = new Enhancer();
        //2.設置父類
        en.setSuperclass(target.getClass());
        //3.設置回調函數
        en.setCallback(this);
        //4.創建子類(代理對象)
        return en.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("111");
        Object invoke = method.invoke(target, args);
        System.out.println("222");
        return invoke;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23


14.4 AOP簡介

AOP(面向切面編程):是一種新的方法論,是對傳統OOP(面向對象編程)的補充 
AOP的主要編程對象是切面,而切面模塊化橫切關注點 
在應用AOP編程時,仍然需要定義公共功能,但可以明確的定義這個功能在哪裏。這樣一來橫切關注點就被模塊化到特殊的對象裏。 

14.5 AOP的好處

  • 每個事物邏輯位於一個位置,代碼不分散,便於維護和升級
  • 業務模塊更簡潔,只包含核心業務代碼 

14.6 AOP術語

名稱簡介
連接點程序運行的某個特定位置:如類某個方法調用前、調用後、方法拋出異常後等。連接點由兩個信息確定:方法表示的程序執行點,相對點表示的位置。
切點AOP通過切點定位到特殊的連接點。類比:連接點相當於數據庫中的記錄,切點相當於查詢條件。
切面橫切關注點被模塊化的特殊對象。
通知切面必須要完成的工作
目標被通知的對象
代理向目標對象應用通知之後創建的對象
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章