Spring框架基礎

1         Spring框架

1.1           Spring的基本概念

是一個輕量級的框架,提供基礎的開發包,包括消息、web通信、數據庫、大數據、受權、手機應用、session管理等。html

Mavenjava

Maven是用來管理項目的依賴、編譯、文檔等信息。之前使用第三方類庫須要複製類庫到指定的目錄下,可能此jar包還要依賴於其餘的jar包,須要不斷的去下載複製。Maven經過一個配置文件配置類庫的groupid組件惟一標識,artifactId項目的惟一標識,version項目的版本信息等。Marven會根據pom.xml中配置的denpendency依賴項,從marven中心庫下載相關依賴包到.m2。web

AOP(Aspect Oriented Programming)面向切面編程spring

       面前切面編程其實一種封裝機制,一個切面提供輸入和輸出接口,程序的流程通過切面。例如銀行的轉帳、查詢、取款流程中都有一個驗證的操做,能夠將驗證操做獨立成一個切面,轉帳、查詢、取款流程都要通過這個切面去驗證。數據庫

依賴注入(dependency injection)和控制反轉(Inversion of Controlexpress

控制反轉其實是一種解耦的機制,在開發大型項目時,確定要建立多個類,並且類之間相互依賴錯綜複雜,每每牽一髮而動全身,爲了解除類之間的耦合,而採用IOC進行解耦,實現各個模塊之間的獨立開發,協同工做。例如機械手錶中各個齒輪之間相互耦合,是一種強耦合的關係,作一個齒輪要考慮其餘的齒輪怎麼的設計參數,稍有誤差就會出現很大的偏差。而電子手錶中則是解耦成各個模塊:顯示、供電、計算模塊等。各個模塊能夠單獨開發,再經過通用的接口鏈接在一塊兒。這就是一種解耦的思路。IOC至關於在各個類之間的鏈接器,實現將各個類的對象注入到其餘類的對象中。編程

                       

例如在 Class A 中,有 Class B 的實例,則稱 Class A 對 Class B 有一個依賴。例以下面類 Human 中用到一個 Father 對象,咱們就說類 Human 對類 Father 有一個依賴。微信

public class Human {session

    ...app

    Father father;

    ...

    public Human() {

        father = new Father();

    }

}

仔細看這段代碼咱們會發現存在一些問題:

(1). 若是如今要改變 father 生成方式,如須要用new Father(String name)初始化 father,須要修改 Human 代碼;

(2). 若是想測試不一樣 Father 對象對 Human 的影響很困難,由於 father 的初始化被寫死在了 Human 的構造函數中;

(3). 若是new Father()過程很是緩慢,單測時咱們但願用已經初始化好的 father 對象 Mock 掉這個過程也很困難。

 

依賴注入 上面將依賴在構造函數中直接初始化是一種 Hard init 方式,弊端在於兩個類不夠獨立,不方便測試。咱們還有另一種 Init 方式,以下:

 

public class Human {

    ...

    Father father;

    ...

    public Human(Father father) {

        this.father = father;

    }

}

 

上面代碼中,咱們將 father 對象做爲構造函數的一個參數傳入。在調用 Human 的構造方法以前外部就已經初始化好了 Father 對象。像這種非本身主動初始化依賴,而經過外部來傳入依賴的方式,咱們就稱爲依賴注入

如今咱們發現上面 1 中存在的兩個問題都很好解決了,簡單的說依賴注入主要有兩個好處:

(1). 解耦,將依賴之間解耦。

(2). 由於已經解耦,因此方便作單元測試,尤爲是 Mock 測試。

控制反轉的名稱由來

軟件系統在沒有引入IOC容器以前,對象human依賴於對象father,那麼對象human在初始化或者運行到某一點的時候,本身必須主動去建立對象father或者使用已經建立的對象father。不管是建立仍是使用對象father,控制權都在本身手上。軟件系統在引入IOC容器以後,這種情形就徹底改變了,因爲IOC容器的加入,對象human與對象father之間失去了直接聯繫,而是經過接口傳入對象。至關因而把已經建立好的對象father經過接口注入human中,human對象失去了建立對象father的權利,反而是一種被動的接收別人建立好的對象,因此稱爲控制反轉。也被稱爲依賴注入。

Spring爲了下降對象之間的耦合關係,採用了一個bean工廠來建立bean對象,經過配置文件或者註解去聲明須要做爲bean對象的類,以及類之間的依賴關係。Bean工廠建立bean對象,並根據配置的從屬關係,將對象注入到另一個對象屬性中。

 

1.2           註解

註解(Annotation)至關於一種標記,在程序中加入註解就等於爲程序打上某種標記,javac編譯器、開發工具和其餘程序能夠經過反射來了解你的類及各類元素上有無何種標記,看你的程序有什麼標記,就去幹相應的事,標記能夠加在包、類,屬性、方法,方法的參數以及局部變量上。假設不少人考駕照,教練在有些學員身上貼一些綠牌子、黃牌子,貼綠牌子的表示送禮送得比較多的,貼黃牌子的學員表示送禮送得比較少的,不貼牌子的學員表示沒有送過禮的,經過這個牌子就能夠標識出不一樣的學員教官在考覈時一看,哦,這個學員是有牌子的,是送過禮給他的,優先讓有牌子的學員過,此時這個牌子就是一個註解一個牌子就是一個註解的實例對象,實實在在存在的牌子就是一個實實在在的註解對象。

1.2.1            JDK1.5以後內部提供的三個註解

(1)@Deprecated 意思是「廢棄的,過期的」

(2)@Override 意思是「重寫、覆蓋」

(3)@SuppressWarnings 意思是「壓縮警告」

註解實例:

package cn.gacl.annotation;

public class AnnotationTest {

    /* @param args*/

   (1) @SuppressWarnings(":deprecation")

    //這裏就是註解,稱爲壓縮警告,這是JDK內部自帶的一個註解,一個註解就是一個類,在這裏使用了這個註解就是建立了SuppressWarnings類的一個實例對象

    public static void main(String[] args) {

        System.runFinalizersOnExit(true);

        //The method runFinalizersOnExit(boolean) from the type System is deprecated(過期的,廢棄的)

        //這裏的runFinalizersOnExit()方法畫了一條橫線表示此方法已通過時了,不建議使用了

    }

   (2) @Deprecated //這也是JDK內部自帶的一個註解,意思就是說這個方法已經廢棄了,不建議使用了

    public static void sayHello(){

        System.out.println("hi,孤傲蒼狼");

    }

    (3)@Override //這也是JDK1.5以後內部提供的一個註解,意思就是要重寫(覆蓋)JDK內部的toString()方法

    public String toString(){

        return "孤傲蒼狼";

    }

}

1.2.2            自定義註解

定義註解

package cn.gacl.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)//設置註解的生命週期

//Retention註解決定MyAnnotation註解的生命週期

/*

 * @Retention(RetentionPolicy.SOURCE)

 * 這個註解的意思是讓MyAnnotation註解只在java源文件中存在,編譯成.class文件後註解就不存在了

 * @Retention(RetentionPolicy.CLASS)

 * 這個註解的意思是讓MyAnnotation註解在java源文件(.java文件)中存在,編譯成.class文件後註解也還存在,

 * 被MyAnnotation註解類標識的類被類加載器加載到內存中後MyAnnotation註解就不存在了

 */

@Target( { ElementType.METHOD, ElementType.TYPE })//設置註解的做用域

//Target註解決定MyAnnotation註解能夠加在哪些成分上,如加在類身上,或者屬性身上,或者方法身上等成分

public @interface MyAnnotation {}//定義註解

使用註解

package cn.gacl.annotation;

@MyAnnotation

//這裏是將新建立好的註解類MyAnnotation標記到AnnotaionTest類上

public class AnnotationUse {

    public static void main(String[] args) {

        // 這裏是檢查Annotation類是否有註解,這裏須要使用反射才能完成對Annotation類的檢查

        if (AnnotationUse.class.isAnnotationPresent(MyAnnotation.class)) {

            /*

             * MyAnnotation是一個類,這個類的實例對象annotation是經過反射獲得的,這個實例對象是如何建立的呢?

             * 一旦在某個類上使用了@MyAnnotation,那麼這個MyAnnotation類的實例對象annotation就會被建立出來了

             */

            MyAnnotation annotation = (MyAnnotation) AnnotationUse.class

                    .getAnnotation(MyAnnotation.class);

            System.out.println(annotation);// 打印MyAnnotation對象,這裏輸出的結果爲:@cn.itcast.day2.MyAnnotation()

        }

    }

}

1.2.3            爲註解增長屬性

定義添加屬性

package cn.gacl.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

//Retention註解決定MyAnnotation註解的生命週期

@Target( { ElementType.METHOD, ElementType.TYPE })

public @interface MyAnnotation {

    /* 定義基本屬性* @return*/

String color();//新增屬性color

String name() default "blues";//新增屬性name並設置默認值blues

}

package cn.gacl.annotation;

 

@MyAnnotation(color="red")//應用MyAnnotation註解的color屬性

//@MyAnnotation(color="red",name=」blues」)

public class MyAnnotationTest {

    public static void main(String[] args) {

        /**

         * 用反射方式得到註解對應的實例對象後,在經過該對象調用屬性對應的方法

         */

        MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class);

        System.out.println(annotation.color());//輸出color屬性:red

        System.out.println(annotation.name());//輸出默認屬性blues

       

    }

}

1.2.4            Java API中三種註解的定義

(1)@Deprecated

Java API中是這樣定義的@Deprecated的

@Documented

2 @Retention(value=RUNTIME)

3 public @interface Deprecated

 

(2)@Override

Java API中是這樣定義的@Override的

1 @Target(value=METHOD)

2 @Retention(value=SOURCE)

3 public @interface Override

 

@Override是給javac(java編譯器)看的,編譯完之後就@Override註解就沒有價值了,@Override註解在源代碼中有用,編譯成.class文件後@Override註解就沒有用了,所以@Override的Retention的屬性值是RetentionPolicy.SOURCE

 

(3)@SuppressWarnings

Java API中是這樣定義的@SuppressWarnings的

@Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})

 @Retention(value=SOURCE)

public @interface SuppressWarnings

1.3           spring經常使用註解

1.3.1            spring使用配置文件的問題

傳統的spring是定義類和和類中定義成員類的引用和set、get接口。同時在配置文件中配置類和成員類之間的依賴關係。要傳統的Spring作法是使用.xml文件來對bean進行注入或者是配置aop、事物,這麼作有兩個缺點:
一、若是全部的內容都配置在.xml文件中,那麼.xml文件將會十分龐大;若是按需求分開.xml文件,那麼.xml文件又會很是多。總之這將致使配置文件的可讀性與可維護性變得很低。
二、在開發中在.java文件和.xml文件之間不斷切換,是一件麻煩的事,同時這種思惟上的不連貫也會下降開發的效率。
爲了解決這兩個問題,Spring引入了註解,經過"@XXX"的方式,讓註解與Java Bean緊密結合,既大大減小了配置文件的體積,又增長了Java Bean的可讀性與內聚性。

不使用註解:

先看一個不使用註解的Spring示例,在這個示例的基礎上,改爲註解版本的,這樣也能看出使用與不使用註解之間的區別,先定義一個老虎:

 

package com.spring.model;

 

public class Tiger {

   

    private String tigerName="TigerKing";

   

    public String toString(){

        return "TigerName:"+tigerName;

    }

}

 

再定義一個猴子:

 

package com.spring.model;

 

public class Monkey {

   

    private String monkeyName = "MonkeyKing";

   

    public String toString(){

        return "MonkeyName:" + monkeyName;

    }

 

}

 

定義一個動物園:

 

package com.spring.model;

 

public class Zoo {

    private Tiger tiger;

    private Monkey monkey;

   

    public Tiger getTiger() {

        return tiger;

    }

    public void setTiger(Tiger tiger) {

        this.tiger = tiger;

    }

    public Monkey getMonkey() {

        return monkey;

    }

    public void setMonkey(Monkey monkey) {

        this.monkey = monkey;

    }

   

    public String toString(){

        return tiger + "\n" + monkey;

    }

   

}

 

spring的配置文件這麼寫:

 

<?xml version="1.0" encoding="UTF-8"?>

<beans

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.0.xsd

    ">

   

     <bean id="zoo" class="com.spring.model.Zoo" >

        <property name="tiger" ref="tiger" />

        <property name="monkey" ref="monkey" />

    </bean>

   

    <bean id="tiger" class="com.spring.model.Tiger" />

    <bean id="monkey" class="com.spring.model.Monkey" />

 

</beans>

 

測試方法:

 

public class TestAnnotation {

    /**

     * 不使用註解

     */

    @Test

    public void test(){

        //讀取配置文件

        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml");

        Zoo zoo=(Zoo) ctx.getBean("zoo");

        System.out.println(zoo.toString());

    }

}

 

1.3.2            採用spring註解自動裝備bean

採用註解以後,不須要再配置文件中配置類之間的依賴關係,也無需定義set和get接口,只需將類定義爲bean,讓spring可以識別bean,而後在須要注入的引用前面加上@Autowired註解,IOC就會自動的按照類型匹配的方式查找bean,將bean對象注入到引用中。

@Autowired

@Autowired顧名思義,就是自動裝配,其做用是爲了消除代碼Java代碼裏面的getter/setter與bean屬性中的property。固然,getter看我的需求,若是私有屬性須要對外提供的話,應當予以保留。

@Autowired默認按類型匹配的方式,在容器查找匹配的Bean,當有且僅有一個匹配的Bean時,Spring將其注入@Autowired標註的變量中。

所以,引入@Autowired註解,先看一下spring配置文件怎麼寫:

 

 1 <?xml version="1.0" encoding="UTF-8"?>

 2 <beans

 3     xmlns="http://www.springframework.org/schema/beans"

 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 5     xmlns:p="http://www.springframework.org/schema/p"

 6     xmlns:context="http://www.springframework.org/schema/context"

 7     xsi:schemaLocation="http://www.springframework.org/schema/beans

 8     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

 9     http://www.springframework.org/schema/context

10     http://www.springframework.org/schema/context/spring-context-3.0.xsd

11     ">

12    

13     <context:component-scan base-package="com.spring" />

14    

15     <bean id="zoo" class="com.spring.model.Zoo" />

16     <bean id="tiger" class="com.spring.model.Tiger" />

17     <bean id="monkey" class="com.spring.model.Monkey" />

18

19 </beans>

 

注意第13行,使用必須告訴spring一下我要使用註解了,告訴的方式有不少,<context:component-scan base-package="xxx" />是一種最簡單的,spring會自動掃描xxx路徑下的註解。

看到第15行,原來zoo裏面應當注入兩個屬性tiger、monkey,如今不須要注入了。再看下,Zoo.java也很方便,把getter/setter均可以去掉:

 

package com.spring.model;

 

import org.springframework.beans.factory.annotation.Autowired;

 

public class Zoo {

   

    @Autowired

    private Tiger tiger;//自動注入對象

   

    @Autowired

    private Monkey monkey;// //自動注入對象

   

    public String toString(){

        return tiger + "\n" + monkey;

    }

   

}

 

這裏@Autowired註解的意思就是,當Spring發現@Autowired註解時,將自動在代碼上下文中找到和其匹配(默認是類型匹配)的Bean,並自動注入到相應的地方去。

若是將16.17行去掉,ioc就沒法找到tiger和monkey的bean。@Autowired註解要去尋找的是一個Bean,Tiger和Monkey的Bean定義都給去掉了,天然就不是一個Bean了,Spring容器找不到也很好理解。那麼,若是屬性找不到我不想讓Spring容器拋出異常,而就是顯示null,能夠嗎?能夠的,其實異常信息裏面也給出了提示了,就是將@Autowired註解的required屬性設置爲false便可:

 

package com.spring.model;

 

import org.springframework.beans.factory.annotation.Autowired;

 

public class Zoo {

   

    @Autowired(required=false)

    private Tiger tiger;

   

    @Autowired(required=false)

    private Monkey monkey;

   

    public String toString(){

        return tiger + "\n" + monkey;

    }

   

}

 

此時,找不到tiger、monkey兩個屬性,Spring容器再也不拋出異常而是認爲這兩個屬性爲null。

1.3.3            Qualifier(指定注入Bean的名稱)

定義一個接口,有兩個類實現了它,在使用接口引用自動注入時,由於有兩個實現類,因此沒法知道注入哪一個類,因此要用Qualifier指定實現類的名稱。那麼若是容器中有一個以上匹配的Bean,則能夠經過Qualifier註解限定Bean的名稱,看下面的例子:

定義一個Car接口:

package com.spring.service;

 

public interface ICar {

   

    public String getCarName();

}

兩個實現類BMWCar和BenzCar:

 

package com.spring.service.impl;

 

import com.spring.service.ICar;

 

public class BMWCar implements ICar{

   

    public String getCarName(){

        return "BMW car";

    }

}

 

 

package com.spring.service.impl;

 

import com.spring.service.ICar;

 

public class BenzCar implements ICar{

   

    public String getCarName(){

        return "Benz car";

    }

}

 

再寫一個CarFactory,引用car(這裏先不用@Qualifier註解):

 

package com.spring.model;

 

import org.springframework.beans.factory.annotation.Autowired;

 

import com.spring.service.ICar;

 

public class CarFactory {

   

    @Autowired

    private ICar car;

   

    public String toString(){

        return car.getCarName();

    }

   

}

 

配置文件:

 

<?xml version="1.0" encoding="UTF-8"?>

<beans

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.0.xsd

    ">

   

    <context:component-scan base-package="com.spring" />

   

    <!-- Autowired註解配合Qualifier註解 -->

    <bean id="carFactory" class="com.spring.model.CarFactory" />

    <bean id="bmwCar" class="com.spring.service.impl.BMWCar" />

    <bean id="benz" class="com.spring.service.impl.BenzCar" />

   

</beans>

 

測試方法:

 

/**

 * Autowired註解配合Qualifier註解

 */

@Test

public void test1(){

    //讀取配置文件

    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml");

    CarFactory carFactory=(CarFactory) ctx.getBean("carFactory");

    System.out.println(carFactory.toString());

}

 

運行一下,不用說,必定是報錯的,Car接口有兩個實現類,Spring並不知道應當引用哪一個實現類。因此要用Qualifier指定。

package com.spring.model;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import com.spring.service.ICar;

 

public class CarFactory {

   

    @Autowired

    @Qualifier("bmwCar")

    private ICar car;

   

    public String toString(){

        return car.getCarName();

    }

   

}

1.3.4            @Resource與@Autowired的異同

@Resource註解與@Autowired註解做用很是類似,這個就簡單說了,看例子:

 

package com.spring.model;

 

import javax.annotation.Resource;

 

public class Zoo1 {

   

    @Resource(name="tiger")

    private Tiger tiger;

   

    @Resource(type=Monkey.class)

    private Monkey monkey;

   

    public String toString(){

        return tiger + "\n" + monkey;

    }

}

 

這是詳細一些的用法,說一下@Resource的裝配順序:
(1)、@Resource後面沒有任何內容,默認經過name屬性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type則根據指定的類型去匹配bean
(3)、指定了name和type則根據指定的name和type去匹配bean,任何一個不匹配都將報錯而後,區分一下@Autowired和@Resource兩個註解的區別:
(1)、@Autowired默認按照byType方式進行bean匹配,@Resource默認按照byName方式進行bean匹配
(2)、@Autowired是Spring的註解,@Resource是J2EE的註解,這個看一下導入註解的時候這兩個註解的包名就一清二楚了
Spring屬於第三方的,J2EE是Java本身的東西,所以,建議使用@Resource註解,以減小代碼和Spring之間的耦合。

1.3.5            @Service註解申明類爲bean

上面這個例子, spring的配置文件裏面還有15行~17行申明三個類爲bean,若是直接在類的定義前面使用註解@service,ioc就會將該類標記爲bean。還可使用下一步的簡化是把這三個bean也給去掉,使得spring配置文件裏面只有一個自動掃描的標籤,加強Java代碼的內聚性並進一步減小配置文件。

要繼續簡化,可使用@Service。先看一下配置文件,固然是所有刪除了:

 

<?xml version="1.0" encoding="UTF-8"?>

<beans

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.0.xsd

    ">

   

    <context:component-scan base-package="com.spring" />

   

</beans>

 

而後在類的定義前面加上註解@Service

 

package com.spring.model;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

 

@Service//申明爲bean,默認標識爲小寫的zoo

public class Zoo {

   

    @Autowired

    private Tiger tiger;

   

    @Autowired

    private Monkey monkey;

   

    public String toString(){

        return tiger + "\n" + monkey;

    }

   

}

 

默認是在Spring容器中Zoo.java存在的形式就是"zoo",便可以經過ApplicationContext的getBean("zoo")方法來獲得Zoo.java。@Service註解,其實作了兩件事情:
(1)、聲明Zoo.java是一個bean,這點很重要,由於Zoo.java是一個bean,其餘的類纔可使用@Autowired將Zoo做爲一個成員變量自動注入。
(2)、Zoo.java在bean中的id是"zoo",即類名且首字母小寫。

若是,我不想用這種形式怎麼辦,就想讓Zoo.java在Spring容器中的名字叫作"Zoo",能夠的:

 

package com.spring.model;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Scope;

import org.springframework.stereotype.Service;

 

@Service("Zoo")//申明bean的標識爲指定的名稱Zoo

@Scope("prototype")

public class Zoo {

   

    @Autowired

    private Tiger tiger;

   

    @Autowired

    private Monkey monkey;

   

    public String toString(){

        return tiger + "\n" + monkey;

    }

   

}

 

這樣,就能夠經過ApplicationContext的getBean("Zoo")方法來獲得Zoo.java了。

這裏我還多加了一個@Scope註解,應該很好理解。由於Spring默認產生的bean是單例的,假如我不想使用單例怎麼辦,xml文件裏面能夠在bean裏面配置scope屬性。註解也是同樣,配置@Scope便可,默認是"singleton"即單例,"prototype"表示原型即每次都會new一個新的出來。

1.3.6            Scope註解建立bean的方式和生命週期

做用

Scope設置對象在spring容器(IOC容器)中的生命週期,也能夠理解爲對象在spring容器中的建立方式。

取值說明

有singleton、prototype、request,session和global session五種取值。 

(1)singleton (單一實例)

 此取值時代表容器中建立時只存在一個實例,全部引用此bean都是單一實例。singleton類型的bean定義從容器啓動到第一次被請求而實例化開始,只要容器不銷燬或退出,該類型的bean的單一實例就會一直存活。生命週期爲IOC存在週期。

(2)prototype每次從新建立

spring容器在進行輸出prototype的bean對象時,會每次都從新生成一個新的對象給請求方,生命週期爲對象的使用週期。 

(3)request

web程序給每個http request新建一個Bean實例,一般是和XmlWebApplicationContext共同使用。

<bean id ="requestPrecessor" class="...RequestPrecessor"   scope="request" />

Spring容器,即XmlWebApplicationContext 會爲每一個HTTP請求建立一個全新的RequestPrecessor對象,當請求結束後,該對象的生命週期即告結束,如同java webrequest的生命週期。簡單來說,request能夠看作prototype的一種特例,除了場景更加具體以外,語意上差很少。

 4session

Web程序中用於保存用戶的登陸信息對象,對於這種放到session中的信息,咱們可使用以下形式的制定scope爲session:

<bean id ="userPreferences" class="...UserPreferences"   scope="session" />

Spring容器會爲每一個獨立的session建立屬於本身的全新的UserPreferences實例,比request scope的bean會存活更長的時間,其餘的方面沒區別,如java web中session的生命週期。

 (5)global session

<bean id ="userPreferences" class="...UserPreferences"   scope="globalsession" />

global session只有應用在基於porlet的web應用程序中才有意義,它映射到porlet的global範圍的session,若是普通的servlet的web 應用中使用了這個scope,容器會把它做爲普通的session的scope對待。

 scope配置方式

(1)    使用配置文件配置

<bean id ="userPreferences" class="...UserPreferences"   scope="session" />

(2)    使用註解配置

@Scope默認狀況使用的是singleton,如果其餘類型須要指定。

@Scope(」prototype」)

 

1.3.7            @Value註解

@Value的做用是經過註解將常量、配置文件中的值、其餘bean的屬性值注入到變量中,做爲變量的初始值。

(1)常量注入

@Value("normal")

    private String normal; // 注入普通字符串

    @Value("classpath:com/hry/spring/configinject/config.txt")

    private Resource resourceFile; // 注入文件資源

 

    @Value("http://www.baidu.com")

private Resource testUrl; // 注入URL資源

 

bean屬性、系統屬性、表達式注入@Value("#{}")

bean屬性注入須要注入者和被注入者屬於同一個IOC容器,或者父子IOC容器關係,在同一個做用域內。

    @Value("#{beanInject.another}")

private String fromAnotherBean; // 注入其餘Bean屬性:注入beanInject對象的屬性another,類具體定義見下面

@Value("#{systemProperties['os.name']}")

    private String systemPropertiesName; // 注入操做系統屬性

 

    @Value("#{ T(java.lang.Math).random() * 100.0 }")

private double randomNumber; //注入表達式結果

 

(3)配置文件屬性注入@Value("${}")

@Value("#{}")讀取配置文件中的值,注入到變量中去。配置文件分爲默認配置文件application.properties和自定義配置文件。

•application.properties。application.properties在spring boot啓動時默認加載此文件

•自定義屬性文件。自定義屬性文件經過@PropertySource加載。@PropertySource能夠同時加載多個文件,也能夠加載單個文件。若是相同第一個屬性文件和第二屬性文件存在相同key,則最後一個屬性文件裏的key啓做用。加載文件的路徑也能夠配置變量,以下文的${anotherfile.configinject},此值定義在第一個屬性文件config.properties

第一個屬性文件config.properties內容以下: 
${anotherfile.configinject}做爲第二個屬性文件加載路徑的變量值

book.name=bookName

anotherfile.configinject=placeholder

第二個屬性文件config_placeholder.properties內容以下:

book.name.placeholder=bookNamePlaceholder

下面經過@Value(「${app.name}」)語法將屬性文件的值注入bean屬性值,詳細代碼見:

 

@Component

// 引入自定義配置文件。

@PropertySource({"classpath:com/hry/spring/configinject/config.properties",

 // 引入自定義配置文件。${anotherfile.configinject}則是config.properties文件中的第二個屬性值,會被替換爲config_placeholder.properties。

   "classpath:com/hry/spring/configinject/config_${anotherfile.configinject}.properties"})

public class ConfigurationFileInject{

    @Value("${app.name}")

    private String appName; // 這裏的值來自application.properties,spring boot啓動時默認加載此文件

 

    @Value("${book.name}")

    private String bookName; // 注入第一個配置文件config.properties的第一個屬性

    @Value("${book.name.placeholder}")

    private String bookNamePlaceholder; // 注入第二個配置外部文件屬性

}

 

1.3.8            @profile和@activeprofile

程序在不一樣的測試環境中,使用的配置信息可能不同,例如採用不一樣的數據庫。在不一樣的環境中使用不一樣的數據庫配置,須要修改配置文件,全部能夠直接寫成多個配置文件,經過註解@Profile(value = "dev")來申明不一樣的配置類,經過註解@ActiveProfiles("dev")來指定採用的是哪個配置類,經過註解的形式選用不一樣的環境配置。

(1)經過設定Environment的ActiveProfiles來設定當前Context須要使用的配置環境,在開發中使用@Profile註解類或者方法,達到不一樣狀況實例化不一樣的bean。

(2)經過設定jvm的spring.profiles.active參數來配置環境(例如:application-dev.properties/application-pro.properties,而後只須要在application.properties中制定dev仍是pro就能夠了)

(3)web項目的話,通常在servlet的context parameter中設置。

1.4           spring 事件(Application Event)

 

1.5           Spring的AOP配置文件和註解實例解析

AOP它利用一種稱爲"橫切"的技術,將那些與核心業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減小系統的重複代碼,下降模塊之間的耦合度,並有利於將來的可操做性和可維護性。例如打印日誌。與核心業務邏輯無關,可是卻貫穿整個程序當中。因此使用AOP切面技術將日誌和核心業務邏輯分離開來,經過配置文件或者註解配置切面,併爲切面設置過濾條件,過濾條件是程序中的方法,表示調用程序中的這些方法時會調用日誌切面的方法來打印日誌,至關因而一種過濾符合條件就觸發打印日誌的機制。而不是將日誌和程序中的方法寫在一塊兒。

1.5.1            AOP配置文件方式

經過配置文件設置切面,切入點,設置與切入點關聯的觸發方法,配置核心業務函數與觸發函數之間的映射關係。一旦觸發方法調用,就會進入切面,在觸發方法前、後、異常等狀況下執行相關函數。

(1)爲日誌類LogAop配置切面信息,配置applicationContext.xml 中logAopBean是配置日誌的bean,提供給IOC調用。aop:aspect id="logAspect"則是定義一個切面。

<!-- 配置日誌類logAopBean爲bean ,提供給IOC使用-->

<bean id="logAopBean" class="com.demo.common.aop.LogAop"></bean>

<aop:config>

<!—設置切面,logAopBean是日誌類的名稱 -->

        <aop:aspect id="logAspect" ref="logAopBean">

<!—設置切入點, expression指定過濾條件,表示com.demo 內部的全部方法,id指定切入的方法,這個方法是一個空函數,只是用於後面關聯日誌類中要調用的其餘方法-->

            <aop:pointcut expression="execution(* com.demo..*(..))" id="allMethod"/>

<!—com.demo中的方法,在調用時,就會觸發日誌類中的函數,下面四個方法分別是調用前打日誌,調用異常打日誌,調用返回打日誌,調用結束打日誌,切入點allMethod和核心業務類中的方法關聯,日誌類中的方法和切入點方法關聯。核心方法調用時,觸發切入點,切入點根據方法的執行狀況去執行對應的日誌方法。 -->

            <aop:before method="before" pointcut-ref="allMethod" />

            <aop:after-throwing method="afterThrowing" pointcut-ref="allMethod" />

            <aop:after-returning method="afterReturn" pointcut-ref="allMethod" />

            <aop:after method="after" pointcut-ref="allMethod" />

        </aop:aspect>

    </aop:config>

(2)定義日誌類,實現日誌類中前置、後置、異常、返回等方法。

package com.demo.common.aop;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

public class LogAop {

    public void before(JoinPoint call){

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println("開始執行:"+className+"."+methodName+"()方法...");

    }

    public void afterThrowing(JoinPoint call){

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println(className+"."+methodName+"()方法拋出了異常...");

    }

    public void afterReturn(JoinPoint call){

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println(className+"."+methodName+"()方法正常執行結束...");

    }

    public void after(JoinPoint call){

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println(className+"."+methodName+"()最終執行步驟(finally)...");

    }

    /*//用來作環繞通知的方法能夠第一個參數定義爲org.aspectj.lang.ProceedingJoinPoint類型 

    public Object doAround(ProceedingJoinPoint call) throws Throwable { 

        Object result = null; 

        this.before(call);//至關於前置通知 

        try { 

            result = call.proceed(); 

            this.afterReturn(call); //至關於後置通知 

        } catch (Throwable e) { 

            this.afterThrowing(call); //至關於異常拋出後通知 

            throw e;

        }finally{ 

            this.after(call);  //至關於最終通知 

        } 

        return result; 

    }*/

}

1.5.2            AOP註解方式

使用註解去代替配置文件,告訴IOC容器,切面、切入點、觸發函數和核心業務方法之間的映射關係。前置方法、後置方法、異常方法、正常返回方法。

在配置文件中聲明LogAnnotationAspect爲logAspectBean,告訴IOC容器這是一個bean。

<bean id="logAspectBean" class="com.demo.common.aop.LogAnnotationAspect"></bean>

    <aop:aspectj-autoproxy/>

package com.demo.common.aop;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

@Aspect  //定義切面類 

public class LogAnnotationAspect { 

    @SuppressWarnings("unused") 

    //定義切入點,提供一個方法,這個方法的名字就是切入點的id 

    @Pointcut("execution(* com.demo..*(..))")  //關聯核心業務函數

    private void allMethod(){} 

    //針對指定的切入點表達式選擇的切入點應用前置通知 

    @Before("allMethod()")   

    public void before(JoinPoint call) { 

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println("開始執行:"+className+"."+methodName+"()方法...");

    } 

    //訪問命名切入點來應用後置通知 

    @AfterReturning("allMethod()") 

    public void afterReturn(JoinPoint call) { 

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println(className+"."+methodName+"()方法正常執行結束...");

    } 

    //應用最終通知 

    @After("allMethod()") 

    public void after(JoinPoint call) { 

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println(className+"."+methodName+"()最終執行步驟(finally)...");

    } 

    //應用異常拋出後通知 

    @AfterThrowing("allMethod()") 

    public void afterThrowing(JoinPoint call) { 

        String className = call.getTarget().getClass().getName();

        String methodName = call.getSignature().getName();

        System.out.println(className+"."+methodName+"()方法拋出了異常...");

    } 

    //應用周圍通知 

    //@Around("allMethod()") 

    public Object doAround(ProceedingJoinPoint call) throws Throwable{ 

        Object result = null; 

        this.before(call);//至關於前置通知 

        try { 

            result = call.proceed(); 

            this.afterReturn(call); //至關於後置通知 

        } catch (Throwable e) { 

            this.afterThrowing(call);  //至關於異常拋出後通知 

            throw e; 

        }finally{ 

            this.after(call);  //至關於最終通知 

        } 

        return result; 

    } 

}

 

 

本身開發了一個股票智能分析軟件,功能很強大,須要的點擊下面的連接獲取:

http://www.javashuo.com/article/p-kahdodke-ge.html

百度雲盤下載地址:

連接:https://pan.baidu.com/s/1swkQzCIKI3g3ObcebgpIDg

提取碼:mc8l

微信公衆號獲取最新的軟件和視頻介紹

QStockView

相關文章
相關標籤/搜索