1. 程式人生 > >Spring必須掌握的技術

Spring必須掌握的技術

Spring框架的概述

    * Spring是一個開源框架
    * Spring是於2003 年興起的一個輕量級的Java開發框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。
    * 它是為了解決企業應用開發的複雜性而建立的。框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個元件,同時為 J2EE 應用程式開發提供整合的框架。
    * Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限於伺服器端的開發。從簡單性、可測試性和鬆耦合的角度而言,任何Java應用都可以   從Spring中受益。
    * Spring的核心是控制反轉(IoC)和麵向切面(AOP)。簡單來說,Spring是一個分層的JavaSE/EEfull-stack(一站式) 輕量級開源框架。


輕量級,面向切面,控制反轉,方便開發,可以把spring看做一個平臺可以搭載其他優秀的框架
    * EE開發分成三層結構
        * WEB層      -- Spring MVC
        * 業務層   -- Bean管理:(IOC)
        * 持久層   -- Spring的JDBC模板.ORM模板用於整合其他的持久層框架


註解和配置檔案都是把需要使用的類提交載入,也就是說把要使用的類配置在xml檔案中

Spring框架的特點

1. 為什麼要學習Spring的框架
    * 方便解耦,簡化開發
        * Spring就是一個大工廠,可以將所有物件建立和依賴關係維護,交給Spring管理
    * AOP程式設計的支援
        * Spring提供面向切面程式設計,可以方便的實現對程式進行許可權攔截、執行監控等功能
    * 宣告式事務的支援
        * 只需要通過配置就可以完成對事務的管理,而無需手動程式設計
    * 方便程式的測試
        * Spring對Junit4支援,可以通過註解方便的測試Spring程式
    * 方便整合各種優秀框架
        * Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支援
    * 降低JavaEE API的使用難度
        * Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠端呼叫等),都提供了封裝,使這些API應用難度大大降低


IOC 
1. 什麼是IOC的功能?
    * IoC       -- Inverse['ɪnvɜːs]  of Control[kən'trəʊl],控制反轉,將物件的建立權反轉給Spring!!
* 使用IOC可以解決的程式耦合性高的問題!!
高內聚,是指讓一個類或者一個方法讓他專注去做一件事情。
低耦合,是類與類之間的聯絡低
 
2. 步驟一:下載Spring框架的開發包
    * 官網:http://spring.io/
    * 下載地址:http://repo.springsource.org/libs-release-local/org/springframework/spring解壓:(Spring目錄結構:)
        * docs      -- API和開發規範
        * libs      -- jar包和原始碼
        * schema    -- 約束


3. 步驟二:建立JavaWEB專案,引入Spring的開發包
    * 引入Spring框架IOC核心功能需要的具體的jar包
        * Spring框架的IOC的功能,那麼根據Spring框架的體系結構圖能看到,只需要引入如下的jar包
            * Beans
            * Core
            * Context
            * Expression Language


        * Spring框架也需要引入日誌相關的jar包
            * 在spring-framework-3.0.2.RELEASE-dependencies/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1
                * com.springsource.org.apache.commons.logging-1.1.1.jar


            * 還需要引入log4j的jar包 spring-framework-3.0.2.RELEASE-dependencies\org.apache.log4j\com.springsource.org.apache.log4j\1.2.15
                * com.springsource.org.apache.log4j-1.2.15.jar


4. 步驟三:建立對應的包結構,編寫Java的類,要注意:以後使用Spring框架做開發,都需要來編寫介面與實現類!!
    * com.itcast.demo1
        * UserService           -- 介面
        * UserServiceImpl       -- 具體的實現類


5. 步驟四:想把UserServiceImpl實現類的建立交給Spring框架來管理,需要建立Spring框架的配置檔案,完成配置
    * 在src目錄下建立applicationContext.xml的配置檔案,名稱是可以任意的,但是一般都會使用預設名稱!!


    * 引入spring的約束,需要先找到具體的約束頭資訊!!
        * spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html
        * 具體的約束如下:      
           
<beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans.xsd">
 </beans>


    * 完成UserService的配置
        <!-- Spring的快速入門 -->
        <bean id="userService" class="com.itcast.demo1.UserServiceImpl"/>


6. 步驟五:編寫測試程式,採用Spring框架的工廠方式來獲取到UserService介面的具體實現類!!
   
 public void demo2(){
        // 使用Spring的工廠:
        ApplicationContext context = 
new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通過工廠獲得類:
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.sayHello();
    }


________________________________________
Spring框架中的工廠(瞭解)
ApplicationContext介面
    * 使用ApplicationContext工廠的介面,使用該介面可以獲取到具體的Bean物件
    * 該介面下有兩個具體的實現類
        * ClassPathXmlApplicationContext            -- 載入類路徑下的Spring配置檔案
當讀取配置檔案時會載入配置檔案中的所有物件
        * FileSystemXmlApplicationContext           -- 載入本地磁碟下的Spring配置檔案


BeanFactory工廠(是Spring框架早期的建立Bean物件的工廠介面)
    * 使用BeanFactory介面也可以獲取到Bean物件
        public void run(){
            BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
            UserService us = (UserService) factory.getBean("us");
            us.sayHello();
        }


BeanFactory和ApplicationContext的區別
        * BeanFactory               -- BeanFactory採取延遲載入,第一次getBean時才會初始化Bean
        * ApplicationContext        -- 在載入applicationContext.xml時候就會建立具體的Bean物件的例項,還提供了一些其他的功能
            * 事件傳遞
            * Bean自動裝配
            * 各種不同應用層的Context實現
________________________________________
入門總結之配置Spring框架編寫XML的提示
1. 步驟一:先複製, http://www.springframework.org/schema/beans/spring-beans.xsd    
2. 步驟二:搜尋XML Catalog,點選Add按鈕
3. 步驟三:先選擇Location的schema的約束地址
    * E:\class\2016\JavaEE28\day35_Spring框架第一天\資料\spring-framework-4.2.4.RELEASE-schema\beans\spring-beans-4.2.xsd
4. 步驟四:注意:Key type要選擇:Schema location
5. 步驟五:Key把http://www.springframework.org/schema/beans/spring-beans.xsd複製上
________________________________________
技術分析之Spring框架的Bean管理的配置檔案方式
________________________________________
技術分析之Spring框架中標籤的配置
1. id屬性和name屬性的區別
    * id        -- Bean起個名字,在約束中採用ID的約束,唯一
        * 取值要求:必須以字母開始,可以使用字母、數字、連字元、下劃線、句話、冒號  id:不能出現特殊字元


    * name      -- Bean起個名字,沒有采用ID的約束(瞭解)
        * 取值要求:name:出現特殊字元.如果<bean>沒有id的話 , name可以當做id使用
        * Spring框架在整合Struts1的框架的時候,Struts1的框架的訪問路徑是以/開頭的,例如:/bookAction


2. class屬性          -- Bean物件的全路徑
3. scope屬性          -- scope屬性代表Bean的作用範圍
    * singleton         -- 單例(預設值)
    * prototype         -- 多例,在Spring框架整合Struts2框架的時候,Action類也需要交給Spring做管理,配置把Action類配置成多例!!
    * request           -- 應用在Web專案中,每次HTTP請求都會建立一個新的Bean
    * session           -- 應用在Web專案中,同一個HTTP Session 共享一個Bean
    * globalsession     -- 應用在Web專案中,多伺服器間的session


4. Bean物件的建立和銷燬的兩個屬性配置(瞭解)
    * 說明:Spring初始化bean或銷燬bean時,有時需要作一些處理工作,因此spring可以在建立和拆卸bean的時候呼叫bean的兩個生命週期方法
    * init-method       -- 當bean被載入到容器的時候呼叫init-method屬性指定的方法
    * destroy-method    -- 當bean從容器中刪除的時候呼叫destroy-method屬性指定的方法
        * 想檢視destroy-method的效果,有如下條件
            * scope= singleton有效
            * web容器中會自動呼叫,但是main函式或測試用例需要手動呼叫(需要使用ClassPathXmlApplicationContext的close()方法)
________________________________________
技術分析之依賴注入(DI)
1. IOC和DI的概念
    * IOC       -- Inverse of Control,控制反轉,將物件的建立權反轉給Spring!!
    * DI        -- Dependency Injection,依賴注入,在Spring框架負責建立Bean物件時,動態的將依賴物件注入到Bean元件中!!


2.  DI(依賴注入)
    * 例如:如果UserServiceImpl的實現類中有一個屬性,那麼使用Spring框架的IOC功能時,可以通過依賴注入把該屬性的值傳入進來!!
    * 具體的配置如下
        <bean id="us" class="com.itheima.demo1.UserServiceImpl">
            <property name="uname" value="小風"/>
        </bean>
________________________________________
技術分析之Spring框架的屬性注入
1. 對於類成員變數,常用的注入方式有兩種
    * 建構函式注入
    * 屬性setter方法注入


2. 在Spring框架中提供了前兩種的屬性注入的方式
    1. 構造方法的注入方式,兩步
        * 編寫Java的類,提供構造方法
            public class Car {
                private String name;
                private double money;
                public Car(String name, double money) {
                    this.name = name;
                    this.money = money;
                }
                @Override
                public String toString() {
                    return "Car [name=" + name + ", money=" + money + "]";
                }
            }


        * 編寫配置檔案
            <bean id="car" class="com.itheima.demo4.Car">
                <constructor-arg name="name" value="大奔"/>
                <constructor-arg name="money" value="100"/>
            </bean>
<!-- 載入properties檔案 -->
<context:property-placeholder location="classpath:mail.properties"/>
    2. 屬性的setter方法的注入方式
        * 編寫Java的類,提供屬性和對應的set方法即可
        * 編寫配置檔案


    3. 如果Java類的屬性是另一個Java的類,那麼需要怎麼來注入值呢?
        * <property name="name" rel="具體的Bean的ID或者name的值"/>
        * 例如:
            <bean id="person" class="com.itheima.demo4.Person">
                <property name="pname" value="美美"/>
                <property name="car2" ref="car2"/>
            </bean>
________________________________________
技術分析之Spring的2.5版本中提供了一種:p名稱空間的注入(瞭解)
1. 步驟一:需要先引入 p 名稱空間
    * 在schema的名稱空間中加入該行:xmlns:p="http://www.springframework.org/schema/p"


2. 步驟二:使用p名稱空間的語法
    * p:屬性名 = ""
    * p:屬性名-ref = ""


3. 步驟三:測試
    * <bean id="person" class="com.itheima.demo4.Person" p:pname="老王" p:car2-ref="car2"/>
________________________________________
技術分析之Spring的3.0提供了一種:SpEL注入方式(瞭解)
1. SpEL:Spring Expression Language是Spring的表示式語言,有一些自己的語法
2. 語法
    * #{SpEL}


3. 例如如下的程式碼
    <!-- SpEL的方式 -->
    <bean id="person" class="com.itheima.demo4.Person">
        <property name="pname" value="#{'小風'}"/>
        <property name="car2" value="#{car2}"/>
    </bean>


4. 還支援呼叫類中的屬性或者方法
    * 定義類和方法,例如
        public class CarInfo {
            public String getCarname(){
                return "奇瑞QQ";
            }
        }
________________________________________

技術分析之陣列,集合(List,Set,Map),Properties等的注入

1. 如果是陣列或者List集合,注入配置檔案的方式是一樣的
   
<bean id="collectionBean" class="com.it.demo5.CollectionBean">
        <property name="arrs">
            <list>
                <value>美美</value>
                <value>小風</value>
            </list>
        </property>
 </bean>




2. 如果是Set集合,注入的配置檔案方式如下:
   
<bean id="collectionBean" class="com.itheima.demo5.CollectionBean">
        <property name="sets">
        <set>
            <value>哈哈</value>
            <value>呵呵</value>
        </set>
    </property>
 </bean>




3. 如果是Map集合,注入的配置方式如下:
 
<bean id="collectionBean" class="com.it.demo5.CollectionBean">
       <property name="map">
        <map>
            <entry key="老王2" value="38"/>
            <entry key="鳳姐" value="38"/>
            <entry key="如花" value="29"/>
        </map>
    </property>
 </bean>


4. 如果是properties屬性檔案的方式,注入的配置如下:
   
<bean id="collectionBean" class="com.it.demo5.CollectionBean">
       <bean id="collectionBean" class="com.it.demo5.CollectionBean">
       <property name="map">
        <map>
            <entry key="老王2" value="38"/>
            <entry key="鳳姐" value="38"/>
            <entry key="如花" value="29"/>
        </map>
    </property>
 </bean>

將map list set 抽離

list:
<bean id="names" class="java.util.ArrayList">  
        <constructor-arg>  
        <list>  
            <value>倩倩</value>  
  	    <value>夕夕</value>  
        </list>  
        </constructor-arg>  
</bean>
map:
<bean id="map" class="java.util.HashMap">  
	        <constructor-arg>  
	        <map>  
	            <entry key="name" value="倩倩"/>
	            <entry key="age" value="20"/> 
	        </map>  
	        </constructor-arg>  
</bean>

set:
<bean id="set" class="java.util.TreeSet">  
         <constructor-arg>  
        <set>  
            <value>倩倩</value>  
  	    <value>夕夕</value>  
        </set>  
        </constructor-arg>  
</bean>


________________________________________
技術分析之Spring框架的配置檔案分開管理(瞭解)
1. 例如:在src的目錄下又多建立了一個配置檔案,現在是兩個核心的配置檔案,那麼載入這兩個配置檔案的方式有兩種!
    * 主配置檔案中包含其他的配置檔案:
        <import resource="applicationContext2.xml"/>


    * 工廠建立的時候直接載入多個配置檔案:
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                    "applicationContext.xml","applicationContext2.xml");
________________________________________
Spring框架整合WEB
________________________________________
Spring框架整合WEB(不是最終的方案)
1. 建立JavaWEB專案,引入Spring的開發包。編寫具體的類和方法。
    * 環境搭建好後,啟動伺服器來測試專案,傳送每訪問一次都會載入一次配置檔案,這樣效率會非常非常慢!!


2. 解決上面的問題
    * 將工廠建立好了以後放入到ServletContext域中.使用工廠的時候,從ServletContext中獲得.
        * ServletContextListener:用來監聽ServletContext物件的建立和銷燬的監聽器.
        * 當ServletContext物件建立的時候:建立工廠 , 將工廠存入到ServletContext


3. Spring整合Web專案
    * 引入spring-web-4.2.4.RELEASE.jar包
    * 配置監聽器
       
 <!-- 配置Spring的核心監聽器: -->
         <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
         </listener>
         <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
         </context-param>



4. 修改servlet的程式碼
    * 從ServletContext中獲得工廠
    * 具體程式碼如下
        ServletContext servletContext = ServletActionContext.getServletContext();
        // 需要使用WEB的工廠的方式
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        CustomerService cs = (CustomerService) context.getBean("customerService");
        cs.save();  
________________________________________
Spring第二講
IOC(註解方式)
IOC之註解的快速入門
1. 步驟一:匯入註解開發所有需要的jar包
    * 引入IOC容器必須的6個jar包
    * 多引入一個:Spring框架的AOP的jar包,spring-aop的jar包


2. 步驟二:建立對應的包結構,編寫Java的類
    * UserService           -- 介面
    * UserServiceImpl       -- 具體的實現類


3. 步驟三:在src的目錄下,建立applicationContext.xml的配置檔案,然後引入約束。注意:因為現在想使用註解的方式,那麼引入的約束髮生了變化
    * 需要引入context的約束,具體的約束如下
 < beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
4. 步驟四:在applicationContext.xml配置檔案中開啟元件掃描
    * Spring的註解開發:元件掃描
       <context:component-scan base-package="com.itheima "/> 
執行了兩步:開啟註解   掃描包
       意思是掃描com.itheima包下所有的內容
注意:不加掃描註解也可以用,只是啟動時沒有建立物件
5. 步驟五:在ServiceImpl的實現類上添加註解
@Component("service")   -- 相當於在XML的配置方式中 
<bean id="service " class="全限定名"/>
可省略為: @Component 等於 @Component("類名")


Bean管理的常用註解

@Component[kəm'pəʊnənt]:元件.(作用在pojo類上)

Spring中提供@Component的三個衍生註解:(功能目前來講是一致的)
    * @Controller         -- 作用在WEB層
   * @Service          -- 作用在業務層
   * @Repository      -- 作用在持久層

    * 說明:這三個註解是為了讓標註類本身的用途清晰,Spring在後續版本會對其增強


屬性注入的註解

(說明:使用註解注入的方式,可以不用提供set方法)

    * 如果是注入的普通型別,可以使用value註解
        * @Value            -- 用於注入普通型別(基本資料型別和字串)


    * 如果注入的是物件型別,使用如下註解:
        * @Autowired        -- 預設按型別進行自動裝配(去IOC容器去找他註解的物件實現的類,自動裝配注入)
        * 如果想按名稱注入:    @Qualifier    -- 強制使用名稱注入

必須一塊使用: 

                        @Autowired

                        @Qualifier("dao")

    * @Resource             -- 相當於@Autowired和@Qualifier一起使用
        * 強調:Java提供的註解
        * 屬性使用name屬性


Bean的作用範圍和生命週期的註解

1. Bean的作用範圍註解
    * 註解為@Scope[skəʊp] (value="prototype"),作用在類上。值如下:
        * singleton['sɪŋg(ə)lt(ə)n]     -- 單例,預設值
        * prototype['prəʊtətaɪp]      -- 多例


2. Bean的生命週期的配置(瞭解)
    * 註解如下(作用在方法上):
        * @PostConstruct    -- 相當於init-method(當bean被載入到容器的時候呼叫)
        * @PreDestroy       -- 相當於destroy-method


整合JUnit單元測試

1. 為了簡化了JUnit的測試,使用Spring框架也可以整合測試
2. 具體步驟
    * 要求:必須先有JUnit的環境(即已經匯入了JUnit4的開發環境)!!


    * 步驟一:在程式中引入:spring-test.jar
    * 步驟二:在具體的測試類上添加註解
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:applicationContext.xml")   
多個  @ContextConfiguration(locations = {"classpath:/spring/*.xml", "classpath:/spring/*.xml })   
           作用在類上,可以載入配置檔案.第二個註解是載入配置檔案



AOP的概述



1. 什麼是AOP的技術?
    * 在軟體業,AOP為Aspect  Oriented  Programming 的縮寫,意為:面向切面程式設計
    * AOP是一種程式設計正規化,隸屬於軟工範疇,指導開發者如何組織程式結構
    * AOP最早由AOP聯盟的組織提出的,制定了一套規範.Spring將AOP思想引入到框架中,必須遵守AOP聯盟的規範
    * 通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術
    * AOP是OOP(面向物件)的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數語言程式設計的一種衍生範型
    * 利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率


2. AOP:面向切面程式設計.(思想.---解決OOP遇到一些問題)
3. AOP採取橫向抽取機制,取代了傳統縱向繼承體系重複性程式碼(效能監視、事務管理、安全檢查、快取)


4. 為什麼要學習AOP
    * 可以在不修改原始碼的前提下,對程式進行增強!!   

AOP的底層實現

1. Srping框架的AOP技術底層也是採用的代理技術,代理的方式提供了兩種
    1. 基於JDK的動態代理
        * 必須是面向介面的,只有實現了具體介面的類才能生成代理物件


    2. 基於CGLIB動態代理
        * 對於沒有實現了介面的類,也可以產生代理,產生這個類的子類的方式


2. Spring的傳統AOP中根據類是否實現介面,來採用不同的代理方式
    1. 如果實現類介面,使用JDK動態代理完成AOP
    2. 如果沒有實現介面,採用CGLIB動態代理完成AOP
________________________________________
JDK的動態代理(程式碼瞭解,理解原理)
1. 使用Proxy類來生成代理物件的一些程式碼如下:
   
 public class MyProxyUtils {
	public static Service getProxy(final Service s){
		Service service = (Service) Proxy.newProxyInstance(MyProxyUtils.class.getClassLoader() ,s.getClass().getInterfaces() ,new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method , Object[] args ) throws Throwable {
				System.out.println("代理執行了執行了");
				if (method.getName().equals("save")) {
					s.save();
				}
				return null;
			}
		} );
		
		return service;
	}
} 
MyProxyUtils.class.getClassLoader()  : 當前類的類載入器

s.getClass().getInterfaces() :被裝飾者實現的所有介面

new InvocationHandler() {}介面的實現類,是個匿名內部類;

Method method :通過反射傳來的被代理物件的方法物件,用來實現代理功能

 Object[] args 通過反射傳來的被代理物件的方法物件,被代理物件傳來方法物件的引數

使用:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath :applicationContext.xml")
public class Demo {
@Resource(name="service")
private Service s;
   @Test
   public void method(){
     Service proxy = MyProxyUtils.getProxy(s);
    proxy.save();
   }
}


CGLIB的代理技術(程式碼瞭解)
當被代理物件沒有實現介面是spring框架會預設使用CGLIB實現代理
1. 引入CBLIB的開發包
    * 如果想使用CGLIB的技術來生成代理物件,那麼需要引入CGLIB的開發的jar包,在Spring框架核心包中已經引入了CGLIB的開發包了。所以直接引入Spring核心開發包即可!


2. 編寫相關的程式碼
 
 public static ServiceImpl2 getcglibProxy(){
//建立cglib核心類
Enhancer enhancer = new Enhancer();
// 設定父類
enhancer.setSuperclass(ServiceImpl2.class);
// 設定回撥函式
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args,
                    MethodProxy methodProxy) throws Throwable {
                if("save".equals(method.getName())){
                    // 記錄日誌
                    System.out.println("記錄日誌了...");
                }
                return methodProxy.invokeSuper(obj, args);
            }
        });
        // 生成代理物件
        ServiceImpl2 proxy = (ServiceImpl2) enhancer.create();
        return proxy;
}

Spring基於AspectJ的AOP的開發



AOP的相關術語
1. Join point (連線點)   -- 所謂連線點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支援方法型別的連線點(被代理物件的所有方法)
2. Point cut(切入點)        -- 所謂切入點是指我們要對哪些Joinpoint進行攔截的定義(被代理物件加強的方法)
3. Advice (通知/增強)    -- 所謂通知是指攔截到Joinpoint之後所要做的事情就是通知.通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
4. Introduction (引介) -- 引介是一種特殊的通知在不修改類程式碼的前提下, Introduction可以在執行期為類動態地新增一些方法或Field
5. Target  (目標物件)     -- 代理的目標物件
6. Weaving(織入)      -- 是指把增強應用到目標物件來建立新的代理物件的過程(生成代理物件的過程)
7. Proxy(代理)        -- 一個類被AOP織入增強後,就產生一個結果代理類
8. Aspect (切面)           -- 是切入點和通知的結合,以後咱們自己來編寫和配置的
 
AspectJ的XML方式完成AOP的開發
1. 步驟一:建立JavaWEB專案,引入具體的開發的jar包
    * 先引入Spring框架開發的基本開發包
    * 再引入Spring框架的AOP的開發包
        * spring的傳統AOP的開發的包
            * spring-aop-4.2.4.RELEASE.jar
            * com.springsource.org.aopalliance -1.0.0.jar


        * aspectJ的開發包
            * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
            * spring-aspects-4.2.4.RELEASE.jar


2. 步驟二:建立Spring的配置檔案,引入具體的AOP的schema約束
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
</beans>




3. 步驟三:建立包結構,編寫具體的介面和實現類
    * com.itheima.demo2
        * CustomerDao           -- 介面
        * CustomerDaoImpl       -- 實現類


4. 步驟四:將目標類配置到Spring中
    <bean id="customerDao" class="com.itheima.demo3.CustomerDaoImpl"/>


5. 步驟五:定義切面類
    public class MyAspectXml {
        // 定義通知
        public void log(){
            System.out.println("記錄日誌...");
        }
    }


6. 步驟六:在配置檔案中定義切面類
    <bean id="myAspectXml" class="com.itheima.demo3.MyAspectXml"/>


7. 步驟七:在配置檔案中完成aop的配置
<bean id="service" class="com.itheima.service.ServiceImpl"/>
   <aop:config>
        <!-- 引入切面類 -->
        <aop:aspect ref="service">
            <!-- 定義通知型別:切面類的方法和切入點的表示式 -->
            <aop:before method="log" pointcut="execution(public * com.itheima.demo3.CustomerDaoImpl.save(..))"/>
        </aop:aspect>
    </aop:config>


   


切入點的表示式

1. 再配置切入點的時候,需要定義表示式,重點的格式如下:execution(public * *(..)),具體展開如下:
    * 切入點表示式的格式如下:
         execution([修飾符] 返回值型別 包名.類名.方法名(引數))


    * 修飾符可以省略不寫,不是必須要出現的。
    * 返回值型別是不能省略不寫的,根據你的方法來編寫返回值。可以使用 * 代替。
    * 包名例如:com.itheima.demo3.BookDaoImpl
        * 首先com是不能省略不寫的,但是可以使用 * 代替
        * 中間的包名可以使用 * 號代替
        * 如果想省略中間的包名可以使用 ..  例:*..*


    * 類名也可以使用 * 號代替,也有類似的寫法:*DaoImpl
    * 方法也可以使用 * 號代替 例:*()  add*()
    * 引數如果是一個引數可以使用 * 號代替,如果想代表任意引數使用 ..
________________________________________
AOP的通知型別
1. 前置通知
    * 在目標類的方法執行之前執行。
    * 配置檔案資訊:<aop: before[bɪ'fɔː] method="before" pointcut-ref="myPointcut3"/>
    * 應用:可以對方法的引數來做校驗


2. 最終通知
    * 在目標類的方法執行之後執行,如果程式出現了異常,最終通知也會執行。
    * 在配置檔案中編寫具體的配置:<aop:after method="after" pointcut-ref="myPointcut3"/>
    * 應用:例如像釋放資源


3. 後置通知
    * 方法正常執行後的通知。       
    * 在配置檔案中編寫具體的配置:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>
    * 應用:可以修改方法的返回值


4. 異常丟擲通知
    * 在丟擲異常後通知
    * 在配置檔案中編寫具體的配置:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/> 
    * 應用:包裝異常的資訊


5. 環繞通知
    * 方法的執行前後執行。
    * 在配置檔案中編寫具體的配置:<aop:around method="around" pointcut-ref="myPointcut2"/>
    * 要注意:目標的方法預設不執行,需要使用ProceedingJoinPoint對來讓目標物件的方法執行。
環繞通知:
public void around(ProceedingJoinPoint joinPoint){
System.out.println("環繞通知1...");
try {
// 手動讓目標物件的方法去執行
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("環繞通知2...");
}


環繞通知使用靈活.其他方式都能用環繞方式實現








. 使用Spring框架的AOP技術對DAO層的功能進行增強

Classpath:    spring特有的
________________________________________
AOP(註解方式)
1. 步驟一:建立JavaWEB專案,引入具體的開發的jar包
    * 先引入Spring框架開發的基本開發包
    * 再引入Spring框架的AOP的開發包
        * spring的傳統AOP的開發的包
            * spring-aop-4.2.4.RELEASE.jar
            * com.springsource.org.aopalliance-1.0.0.jar


        * aspectJ的開發包
            * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
            * spring-aspects-4.2.4.RELEASE.jar


2. 步驟二:建立Spring的配置檔案,引入具體的AOP的schema約束
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 </beans>


3. 步驟三:建立包結構,編寫具體的介面和實現類
    * com.itheima.demo1
        * UserDao           -- 介面
        * UserDaoImpl       -- 實現類


4. 步驟四:將目標類配置到Spring中
    <bean id ="userDao1" class="com.itheima.demo.UserDaoImpl"/>
切面類中的註解
5. 步驟五:定義切面類
    * 新增切面和通知的註解
        * @Aspect                   -- 定義切面類的註解


        * 通知型別(註解的引數是切入點的表示式)
             * @Before        -- 前置通知
   * @AfterReturing  -- 後置通知
    *@Around        -- 環繞通知(目標物件方法預設不執行的,需要手動執行)
   * @After          -- 最終通知
   * @AfterThrowing  -- 異常丟擲通知


    * 具體的程式碼如下
        @Aspect 
public class MyAspectAnno {
@Before ("execution(public * com.itheima.demo.UserDaoImpl.save(..))" )
public void log(){
System.out.println("切面執行了..");
}

6. 步驟六:在配置檔案中定義切面類
    <bean id ="myAspectAnno" class="com.itheima.demo.MyAspectAnno"/>


7. 步驟七:在配置檔案中開啟自動代理
    <aop:aspectj-autoproxy />


8. 完成測試
    
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo01 {
@Resource(name="userDao1")
private UserDao userDao; 
@Test
public void method01(){
System.out.println(userDao);
userDao.save();
userDao.update();
}
}
________________________________________
注意測試類不需要在ioc容器中載入,所以不要為了給Deme01中的屬性賦值而配置測試類

Spring載入properties配置檔案

 Spring中有個<context:property-placeholder location=""/>標籤,可以用來載入properties配置檔案,location是配置檔案的路徑,我們現在在工程目錄的src下新建一個conn.properties檔案,裡面寫上上面dataSource的配置:

  1. dataSource=com.mchange.v2.c3p0.ComboPooledDataSource  
  2. driverClass=com.mysql.jdbc.Driver  
  3. jdbcUrl=jdbc\:mysql\://localhost\:3306/shop  
  4. user=root  
  5. password=root  
        現在只需要在beans.xml中做如下修改即可:
  1. <context:property-placeholderlocation="classpath:conn.properties"/><!-- 載入配置檔案 -->
  2. <!-- com.mchange.v2.c3p0.ComboPooledDataSource類在c3p0-0.9.5.1.jar包的com.mchange.v2.c3p0包中 -->
  3.  <beanid="dataSource"class="${dataSource}"><!-- 這些配置Spring在啟動時會去conn.properties中找 -->
  4.     <propertyname="driverClass"value="${driverClass}"/>
  5.     <propertyname="jdbcUrl"value="${jdbcUrl}"/>
  6.     <propertyname="user"value="${user}"/>
  7.     <propertyname="password"value="${password}"/>
  8.  </bean>
        <context:property-placeholder location=""/>標籤也可以用下面的<bean>標籤來代替,<bean>標籤我們更加熟悉,可讀性更強:
  1. <!-- 與上面的配置等價,下面的更容易理解 -->
  2. <beanclass="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  3.     <propertyname="locations"><!-- PropertyPlaceholderConfigurer類中有個locations屬性,接收的是一個數組,即我們可以在下面配好多個properties檔案 -->
  4.         <array>
  5.             <value>classpath:conn.properties</value>
  6.         </array>
  7.     </property>
  8. </bean>
        雖然看起來沒有上面的<context:property-placeholder location=""/>簡潔,但是更加清晰,建議使用後面的這種。但是這個只限於xml的方式,即在beans.xml中用${key}獲取配置檔案中的值value。

通過註解方式載入properties檔案

        還有一種就是通過註解的方式,在java程式碼中使用@Value註解來載入配置檔案中的值。

        我們來看一個例子:假如我們要在程式中獲取某個檔案的絕對路徑,我們很自然會想到不能在程式中寫死,那麼我們也可以解除安裝properties檔案中。還是在src目錄下新建一個public.properties檔案,假設裡面寫了一條記錄:

  1. filePath=E\:\\web\\apache-tomcat-8.0.26\\webapps\\E_shop\\image  
        如果想在java程式碼中通過註解來獲取這個filePath的話,首先得在beans.xml檔案中配置一下註解的方式(載入多個properties):
  1. <!-- 第二種方式是使用註解的方式注入,主要用在java程式碼中使用註解注入properties檔案中相應的value值 -->
  2. <beanid="prop"class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  3.     <propertyname="locations"><!-- 這裡是PropertiesFactoryBean類,它也有個locations屬性,也是接收一個數組,跟上面一樣  
  4.         <array>
  5.             <value>classpath:public.properties</value>
  6.             <value>classpath:db.properties</value>