1. 程式人生 > >java中spring的使用

java中spring的使用

java中spring的使用

 Spring是一個開源框架,框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個元件,同時為 J2EE 應用程式開發提供整合的框架。Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限於伺服器端的開發。從簡單性、可測試性和鬆耦合的角度而言,任何Java應用都可以從Spring中受益。Spring的核心是控制反轉(IoC)和麵向切面(AOP)。

Spring 特點

 ①、方便解耦,簡化開發

  通過Spring提供的IoC容器,我們可以將物件之間的依賴關係交由Spring進行控制,避免硬編碼所造成的過度程式耦合。有了Spring,使用者不必再為單例項模式類、屬性檔案解析等這些很底層的需求編寫程式碼,可以更專注於上層的應用。

  ②、AOP程式設計的支援

  通過Spring提供的AOP功能,方便進行面向切面的程式設計,許多不容易用傳統OOP實現的功能可以通過AOP輕鬆應付。

  ③、宣告式事務的支援

  在Spring中,我們可以從單調煩悶的事務管理程式碼中解脫出來,通過宣告式方式靈活地進行事務的管理,提高開發效率和質量。

  ④、方便程式的測試

  可以用非容器依賴的程式設計方式進行幾乎所有的測試工作,在Spring裡,測試不再是昂貴的操作,而是隨手可做的事情。例如:Spring對Junit4支援,可以通過註解方便的測試Spring程式。

  ⑤、方便整合各種優秀框架

  Spring不排斥各種優秀的開源框架,相反,Spring可以降低各種框架的使用難度,Spring提供了對各種優秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支援。

  ⑥、降低Java EE API的使用難度

  Spring對很多難用的Java EE API(如JDBC,JavaMail,遠端呼叫等)提供了一個薄薄的封裝層,通過Spring的簡易封裝,這些Java EE API的使用難度大為降低。

  ⑦、Java 原始碼是經典學習範例

  Spring的原始碼設計精妙、結構清晰、匠心獨運,處處體現著大師對Java設計模式靈活運用以及對Java技術的高深造詣。Spring框架原始碼無疑是Java技術的最佳實踐範例。如果想在短時間內迅速提高自己的Java技術水平和應用開發水平,學習和研究Spring原始碼將會使你收到意想不到的效果。

Spring 框架結構

     1、核心容器:核心容器提供 Spring 框架的基本功能(Spring Core)。核心容器的主要元件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉(IOC) 模式將應用程式的配置和依賴性規範與實際的應用程式程式碼分開。

  2、Spring 上下文:Spring 上下文是一個配置檔案,向 Spring框架提供上下文資訊。Spring 上下文包括企業服務,例如JNDI、EJB、電子郵件、國際化、校驗和排程功能。

  3、Spring AOP:通過配置管理特性,Spring AOP 模組直接將面向切面的程式設計功能整合到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何物件支援AOP。Spring AOP 模組為基於 Spring 的應用程式中的物件提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 元件,就可以將宣告性事務管理整合到應用程式中。

  4、Spring DAO:JDBCDAO抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同資料庫供應商丟擲的錯誤訊息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常程式碼數量(例如開啟和關閉連線)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。

  5、Spring ORM:Spring 框架插入了若干個ORM框架,從而提供了 ORM 的物件關係工具,其中包括JDO、Hibernate和iBatisSQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。

  6、Spring Web 模組:Web 上下文模組建立在應用程式上下文模組之上,為基於 Web 的應用程式提供了上下文。所以,Spring框架支援與 Jakarta Struts 的整合。Web 模組還簡化了處理多部分請求以及將請求引數繫結到域物件的工作。

  7、Spring MVC 框架:MVC框架是一個全功能的構建 Web應用程式的 MVC 實現。通過策略介面,MVC框架變成為高度可配置的,MVC 容納了大量檢視技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。模型由javabean構成,存放於Map;檢視是一個介面,負責顯示模型;控制器表示邏輯程式碼,是Controller的實現。Spring框架的功能可以用在任何J2EE伺服器中,大多數功能也適用於不受管理的環境。Spring 的核心要點是:支援不繫結到特定 J2EE服務的可重用業務和資料訪問物件。毫無疑問,這樣的物件可以在不同J2EE 環境(Web 或EJB)、獨立應用程式、測試環境之間重用。

Spring 框架特徵 

輕量——從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小隻有1MB多的JAR檔案裡釋出。並且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的物件不依賴於Spring的特定類。

  控制反轉——Spring通過一種稱作控制反轉(IoC)的技術促進了低耦合。當應用了IoC,一個物件依賴的其它物件會通過被動的方式傳遞進來,而不是這個物件自己建立或者查詢依賴物件。你可以認為IoC與JNDI相反——不是物件從容器中查詢依賴,而是容器在物件初始化時不等物件請求就主動將依賴傳遞給它。

  面向切面——Spring提供了面向切面程式設計的豐富支援,允許通過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發。應用物件只實現它們應該做的——完成業務邏輯——僅此而已。它們並不負責(甚至是意識)其它的系統級關注點,例如日誌或事務支援。

  容器——Spring包含並管理應用物件的配置和生命週期,在這個意義上它是一種容器,你可以配置你的每個bean如何被建立——基於一個可配置原型(prototype),你的bean可以建立一個單獨的例項或者每次需要時都生成一個新的例項——以及它們是如何相互關聯的。然而,Spring不應該被混同於傳統的重量級的EJB容器,它們經常是龐大與笨重的,難以使用。

  框架——Spring可以將簡單的元件配置、組合成為複雜的應用。在Spring中,應用物件被宣告式地組合,典型地是在一個XML檔案裡。Spring也提供了很多基礎功能(事務管理、持久化框架整合等等),將應用邏輯的開發留給了你。

  MVC——Spring的作用是整合,但不僅僅限於整合,Spring 框架可以被看做是一個企業解決方案級別的框架。客戶端傳送請求,伺服器控制器(由DispatcherServlet實現的)完成請求的轉發,控制器呼叫一個用於對映的類HandlerMapping,該類用於將請求對映到對應的處理器來處理請求。HandlerMapping 將請求對映到對應的處理器Controller(相當於Action)在Spring 當中如果寫一些處理器元件,一般實現Controller 介面,在Controller 中就可以呼叫一些Service 或DAO 來進行資料操作 ModelAndView 用於存放從DAO 中取出的資料,還可以存放響應檢視的一些資料。 如果想將處理結果返回給使用者,那麼在Spring 框架中還提供一個檢視元件ViewResolver,該元件根據Controller 返回的標示,找到對應的檢視,將響應response 返回給使用者。

Spring 優點

Spring能有效地組織你的中間層物件,無論你是否選擇使用了EJB。如果你僅僅使用了Struts或其他的包含了J2EE特有APIs的framework,你會發現Spring關注了遺留下的問題。Spring能消除在許多工程上對Singleton的過多使用。根據我的經驗,這是一個主要的問題,它減少了系統的可測試性和麵向物件特性。

  Spring能消除使用各種各樣格式的屬性定製檔案的需要,在整個應用和工程中,可通過一種一致的方法來進行配置。曾經感到迷惑,一個特定類要查詢迷幻般的屬性關鍵字或系統屬性,為此不得不讀Javadoc乃至源編碼嗎?有了Spring,你可很簡單地看到類的JavaBean屬性。

  Spring能通過介面而不是類促進好的程式設計習慣,減少程式設計代價到幾乎為零。

  Spring被設計為讓使用它建立的應用盡可能少的依賴於他的APIs。在Spring應用中的大多數業務物件沒有依賴於Spring。所以使用Spring構建的應用程式易於單元測試。

  Spring能使EJB的使用成為一個實現選擇,而不是應用架構的必然選擇。你能選擇用POJOs或local EJBs來實現業務介面,卻不會影響呼叫程式碼。

  Spring幫助你解決許多問題而無需使用EJB。Spring能提供一種EJB的替換物,它們適於許多web應用。例如,Spring能使用AOP提供宣告性事務而不通過使用EJB容器,如果你僅僅需要與單個的資料庫打交道,甚至不需要JTA實現。

  Spring為資料存取提供了一致的框架,不論是使用JDBC或O/R mapping產品(如Hibernate)。

  總結:

  1.低侵入式設計,程式碼汙染極低

  2.獨立於各種應用伺服器,基於Spring框架的應用,可以真正實現Write Once,Run Anywhere的承諾

  3.Spring的DI機制降低了業務物件替換的複雜性,提高了元件之間的解耦

  4.Spring的AOP支援允許將一些通用任務如安全、事務、日誌等進行集中式管理,從而提供了更好的複用

  5.Spring的ORM和DAO提供了與第三方持久層框架的良好整合,並簡化了底層的資料庫訪問

  6.Spring並不強制應用完全依賴於Spring,開發者可自由選用Spring框架的部分或全部

IOC-Inversion of Control,即控制反轉。它不是什麼技術,而是一種設計思想。

  傳統的建立物件的方法是直接通過 new 關鍵字,而 spring 則是通過 IOC 容器來建立物件,也就是說我們將建立物件的控制權交給了 IOC 容器。我們可以用一句話來概括 IOC:

  IOC 讓程式設計師不在關注怎麼去建立物件,而是關注與物件建立之後的操作,把物件的建立、初始化、銷燬等工作交給spring容器來做。

Spring 容器建立物件的三種方式

//這是測試物件,我們通過 IOC 來建立物件
public class HelloIoc {
     
    public void sayHello(){
        System.out.println("Hello IOC");
    }
}

傳統的建立物件的方法:new 關鍵字

//傳統的建立物件方法----new
    @Test
    public void testTradition(){
        HelloIoc hello = new HelloIoc();
        hello.sayHello();
    }

這裡通過 Spring 容器怎麼來建立呢?

  第一種方法:利用預設的構造方法

  在 src 目錄下新建 applicationContext.xml 檔案,這是 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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
    建立物件的第一種方式:利用無參構造器
    id:唯一識別符號
    class:類的全類名
      -->
    <bean id="helloIoc" class="com.my.ioc.HelloIoc" ></bean>  
    <!-- 別名屬性  name:和bean的 id 屬性對應 -->
    <alias name="helloIoc" alias="helloIoc2"/>
     
</beans>
/**
     *  Spring 容器利用建構函式建立物件
     */
    @Test
    public void testCreateObjectByConstrutor(){
        //1、啟動 spring 容器
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、從 spring 容器中取出資料
        HelloIoc IOC = (HelloIoc) context.getBean("helloIoc");
        //3、通過物件呼叫方法
        IOC.sayHello();
         
        //利用配置檔案 alias 別名屬性建立物件
        HelloIoc IOC2 = (HelloIoc) context.getBean("helloIoc2");
        IOC2.sayHello();
    }

HelloIoc.java 中手動新增無參的構造方法,然後執行上面的測試程式碼,會發現構造方法會在 sayHello()方法執行之前呼叫。

<?xml version="1.0" encoding="UTF-8"?>
<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">

	<bean id="zhangsan" class="com.java.service.ZhangSan"></bean>
	
	<bean id="lisi" class="com.java.service.Lisi"></bean>
	
	<bean id="javaWork" class="com.java.service.JavaWork">
		<property name="tester" ref="lisi"></property>
	</bean>
  
</beans>
	public static void main(String[] args) {
		ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
		JavaWork javaWork=(JavaWork)ac.getBean("javaWork");
		javaWork.doTest();
	}
public class JavaWork {
	
	private Tester tester;
	
	public void setTester(Tester tester) {
		this.tester = tester;
	}

	public void doTest(){
		/*ZhangSan zhangsan=new ZhangSan();
		zhangsan.test();*/
		tester.test();
	}
}

第二種方法:利用靜態工廠方法

  首先建立靜態工廠類 HelloStaticFactory.java

public class HelloStaticFactory {
    public HelloStaticFactory(){
        System.out.println("HelloStaticFactory constructor");
    }
    //靜態工廠方法
    public static HelloIoc getInstances(){
        return new HelloIoc();
    }
 
}

接著在 applicationContext.xml 中進行如下配置:

<!--
        建立物件的第二種方式:利用靜態工廠方法
        factory-method:靜態工廠類的獲取物件的靜態方法
        class:靜態工廠類的全類名
      -->   
    <bean id="helloStaticFactory" factory-method="getInstances" class="com.my.ioc.HelloStaticFactory"></bean>
/**
     * Spring 容器利用靜態工廠方法建立物件
     */
    @Test
    public void createObjectStaticFactory(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloIoc staticFactory =
                (HelloIoc) context.getBean("helloStaticFactory");
        staticFactory.sayHello();
    }

spring容器只負責呼叫靜態工廠方法,而這個靜態工廠方法內部實現由程式設計師完成

利用例項工廠方法

  首先建立例項工廠類 HelloInstanceFactory .java

public class HelloInstanceFactory {
    public HelloInstanceFactory(){
        System.out.println("例項工廠方法建構函式");
    }
 
    //利用例項工廠方法建立物件
    public HelloIoc getInstance(){
        HelloIoc instanceIoc = new HelloIoc();
        return instanceIoc;
    }
}

接著在 applicationContext.xml 中進行如下配置:

<!--
        建立物件的第三種方式:利用例項工廠方法
        factory-bean:指定當前Spring中包含工廠方法的beanID
        factory-method:工廠方法名稱
      --> 
    <bean id="instanceFactory" class="com.my.ioc.HelloInstanceFactory"></bean> 
    <bean id="instance" factory-bean="instanceFactory" factory-method="getInstance"></bean> 
/**
     * Spring 容器利用例項工廠方法建立物件
     */
    @Test
    public void createObjectInstanceFactory(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloIoc staticFactory =
                (HelloIoc) context.getBean("instance");
        staticFactory.sayHello();
    }

Spring 容器建立物件的時機

預設情況下,啟動 spring 容器便建立物件

在spring的配置檔案bean中有一個屬性 lazy-init="default/true/false"

     ①、如果lazy-init為"default/false"在啟動spring容器時建立物件(預設情況)

     ②、如果lazy-init為"true",在context.getBean時才要建立物件

 <bean id="helloIoc" lazy-init=“true” class="com.my.ioc.HelloIoc" ></bean>  

在第一種情況下可以在啟動spring容器的時候,檢查spring容器配置檔案的正確性,如果再結合tomcat,如果spring容器不能正常啟動,整個tomcat就不能正常啟動。但是這樣的缺點是把一些bean過早的放在了記憶體中,如果有資料,則對記憶體來是一個消耗。

  反過來,在第二種情況下,可以減少記憶體的消耗,但是不容易發現錯誤

spring的bean中的scope:"singleton/prototype/request/session/global session" 

 一、預設scope的值是singleton,即產生的物件是單例的

   applicationContext.xml 檔案中配置:

<bean id="helloIoc" scope="singleton" class="com.my.ioc.HelloIoc" ></bean>
//spring 容器預設產生物件是單例的 scope="singleton"
    @Test
    public void test_scope_single_CreateObject(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloIoc hello1 = (HelloIoc) context.getBean("helloIoc");
        HelloIoc hello2 = (HelloIoc) context.getBean("helloIoc");
        System.out.println(hello1.equals(hello2)); //true
    }

scope=“prototype”

  多例模式,並且spring容器啟動的時候並不會建立物件,而是在得到 bean 的時候才會建立物件

   applicationContext.xml 檔案中配置:

 總結:在單例模式下,啟動 spring 容器,便會建立物件;在多例模式下,啟動容器並不會建立物件,獲得 bean 的時候才會建立物件

scope=“request” 每次HTTP請求都會建立一個新的bean

scope=“session”同一個HTTP Session共享一個Bean

scope=“global session” 同一個全域性Session共享一個Bean,一般用於portlet應用環境

scope=“application”同一個Application 共享一個Bean 

Spring 容器生命週期

/**
 * Spring 容器的生命週期
 * @author hadoop
 *
 */
public class SpringLifeCycle {
    public SpringLifeCycle(){
        System.out.println("SpringLifeCycle");
    }
    //定義初始化方法
    public void init(){
        System.out.println("init...");
    }
    //定義銷燬方法
    public void destroy(){
        System.out.println("destroy...");
    }
     
    public void sayHello(){
        System.out.println("say Hello...");
    }
}

applicationContext.xml 

<!-- 生命週期 -->
    <bean id="springLifeCycle" init-method="init" destroy-method="destroy" class="com.my.ioc.SpringLifeCycle"></bean>
    public void testSpringLifeCycle(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        SpringLifeCycle hello = (SpringLifeCycle) context.getBean("springLifeCycle");
         
        hello.sayHello();
         
        //銷燬spring容器
        ClassPathXmlApplicationContext classContext = (ClassPathXmlApplicationContext) context;
        classContext.close();
    }

spring 容器的宣告週期

       1、spring容器建立物件
          2、執行init方法
          3、呼叫自己的方法
          4、當spring容器關閉的時候執行destroy方法

  注意:當scope為"prototype"時,呼叫 close() 方法時是不會呼叫 destroy 方法的

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class T {

	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		People people=(People)ac.getBean("people1");
		People people2=(People)ac.getBean("people1");
		System.out.println(people.getDog()==people2.getDog());
		
		System.out.println(ac.getBean("dog")==ac.getBean("dog"));
	}
	

}
<?xml version="1.0" encoding="UTF-8"?>
<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">

	
	<bean id="dog" class="com.java1234.entity.Dog" scope="prototype">
		<property name="name" value="Jack"></property>
	</bean>
	
	
	
	<bean id="people1" class="com.java.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="張三"></property>
		<property name="age" value="11"></property>
		<lookup-method name="getDog" bean="dog"/>//方法動態注入
	</bean>
	
</beans>


public abstract class People {

	private int id;
	private String name;
	private int age;
	private Dog dog;
	public abstract Dog getDog();
	
	public void setDog(Dog dog) {
		this.dog = dog;
	}
	@Override
	public String toString() {
		return "People [id=" + id + ", name=" + name + ", age=" + age
				+ ", dog=" + dog.getName() + "]";
	}

}

方法替換

public class People {

	private int id;
	private String name;
	private int age;
	private Dog dog;

	public Dog getDog() {
		Dog dog=new Dog();
		dog.setName("Jack");
		return dog;
	}
	public void setDog(Dog dog) {
		this.dog = dog;
	}
}

public class People2 implements MethodReplacer {

	@Override
	public Object reimplement(Object arg0, Method arg1, Object[] arg2)
			throws Throwable {
		Dog dog=new Dog();
		dog.setName("Tom");
		return dog;
	}

}


<?xml version="1.0" encoding="UTF-8"?>
<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">

	
	<bean id="people1" class="com.java.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="張三"></property>
		<property name="age" value="11"></property>
		<replaced-method name="getDog" replacer="people2"></replaced-method>
	</bean>
	
	<bean id="people2" class="com.java.entity.People2"></bean>
</beans>

DI依賴注入

spring動態的向某個物件提供它所需要的其他物件。這一點是通過DI(Dependency Injection,依賴注入)來實現的。比如物件A需要操作資料庫,以前我們總是要在A中自己編寫程式碼來獲得一個Connection物件,有了 spring我們就只需要告訴spring,A中需要一個Connection,至於這個Connection怎麼構造,何時構造,A不需要知道。在系統執行時,spring會在適當的時候製造一個Connection,然後像打針一樣,注射到A當中,這樣就完成了對各個物件之間關係的控制。A需要依賴 Connection才能正常執行,而這個Connection是由spring注入到A中的,依賴注入的名字就這麼來的。

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
 
public class Person {
    private Long pid;
    private String pname;
    private Student students;
    private List lists;
    private Set sets;
    private Map maps;
    private Properties properties;
}

在 applicationContext.xml 中進行賦值

<!--
    property是用來描述一個類的屬性
    基本型別的封裝類、String等需要值的型別用value賦值
    引用型別用ref賦值
-->
<bean id="person" class="com.my.di.Person">
    <property name="pid" value="1"></property>
    <property name="pname" value="vae"></property>
    <property name="students">
        <ref bean="student"/>
    </property>
  <property name="students" ref="student">//注入bean
<property name="students.name" value="jack">//級聯private Student students=new Student()

    </property>
     
    <property name="lists">
        <list>
            <value>1</value>
            <ref bean="student"/>
            <value>vae</value>
        </list>
    </property>
     
    <property name="sets">
        <set>
            <value>1</value>
            <ref bean="student"/>
            <value>vae</value>
        </set>
    </property>
     
    <property name="maps">
        <map>
            <entry key="m1" value="1"></entry>
            <entry key="m2" >
                <ref bean="student"/>
            </entry>
        </map>
    </property>   
     
    <property name="properties">
        <props>
            <prop key="p1">p1</prop>
            <prop key="p2">p2</prop>
        </props>
    </property>  
     
</bean>
 
 
<bean id="student" class="com.my.di.Student"></bean>
//利用 set 方法給物件賦值
    @Test
    public void testSet(){
        //1、啟動 spring 容器
        //2、從 spring 容器中取出資料
        //3、通過物件呼叫方法
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) context.getBean("person");
        System.out.println(person.getPname());//vae
    }

利用 建構函式 給屬性賦值

在實體類 Person.java 中新增兩個構造方法:有參和無參

//預設建構函式
    public Person(){}
    //帶參建構函式
    public Person(Long pid,Student students){
        this.pid = pid;
        this.students = students;
    }

在 applicationContext.xml 中進行賦值

<!-- 根據建構函式賦值 -->
    <!--
        index  代表引數的位置  從0開始計算
        type   指的是引數的型別,在有多個建構函式時,可以用type來區分,要是能確定是那個建構函式,可以不用寫type
        value  給基本型別賦值
        ref    給引用型別賦值
      -->
    <bean id="person_con" class="com.my.di.Person">
        <constructor-arg index="0" type="java.lang.Long" value="1">
        </constructor-arg>       
        <constructor-arg index="1" type="com.my.di.Student" ref="student_con"></constructor-arg>
    </bean>
    <bean id="student_con" class="com.my.di.Student"></bean>
//利用 建構函式 給物件賦值
    @Test
    public void testConstrutor(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) context.getBean("person_con");
        System.out.println(person.getPid());//1
    }

  1、如果spring的配置檔案中的bean中沒有<constructor-arg>該元素,則呼叫預設的建構函式

  2、如果spring的配置檔案中的bean中有<constructor-arg>該元素,則該元素確定唯一的建構函式

構造方法通過型別注入

public class People {

	private int id;
	private String name;
	private int age;
	
	
	
	public People() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	
	
	
	public People(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
}


	<bean id="people3" class="com.java.entity.People">
		<constructor-arg type="int" value="2"></constructor-arg>
		<constructor-arg type="String" value="李四"></constructor-arg>
		<constructor-arg type="int" value="22"></constructor-arg>
	</bean>

自動裝配

byName通過名稱自動匹配

<?xml version="1.0" encoding="UTF-8"?>
<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"
        default-autowire="byName">


	<bean id="dog" class="com.java.entity.Dog">
		<property name="name" value="Jack"></property>
	</bean>

	
	<bean id="dog2" class="com.java.entity.Dog">
		<property name="name" value="Tom"></property>
	</bean>
	
	
	
	<bean id="people1" class="com.java.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="張三"></property>
		<property name="age" value="11"></property>
	
	</bean>
	
</beans>


public class People {

	private int id;
	private String name;
	private int age;
	private Dog dog;
}

byType:通過型別進行自動匹配

constructor;根據型別,自動注入

<?xml version="1.0" encoding="UTF-8"?>
<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"
        default-autowire="constructor">

	<bean id="dog" class="com.java.entity.Dog">
		<property name="name" value="Jack"></property>
	</bean>
	
	
	
	<bean id="people1" class="com.java.entity.People">
		<property name="id" value="1"></property>
		<property name="name" value="張三"></property>
		<property name="age" value="11"></property>
	
	</bean>
	
</beans>


public class People {

	private int id;
	private String name;
	private int age;
	private Dog dog;

	public People() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	
	public People(Dog dog) {
		super();
		System.out.println("constructor");
		this.dog = dog;
	}
}

bean之間的關係

繼承

<?xml version="1.0" encoding="UTF-8"?>
<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">
	
	<bean id="dog" class="com.java.entity.Dog">
		<property name="name" value="jack"></property>
	</bean>
	
	<bean id="abstractPeople" class="com.java.entity.People" abstract="true">
		<property name="className" value="高三5班"></property>
		<property name="age" value="19"></property>
	</bean>
	
	<bean id="zhangsan" parent="abstractPeople" depends-on="autority">
		<property name="id" value="1"></property>
		<property name="name" value="張三"></property>
	</bean>
	
	<bean id="lisi" parent="abstractPeople">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name="age" value="20"></property>
		<property name="dog" ref="dog"></property>
	</bean>
	
	
	<bean id="autority" class="com.java.service.Authority"></bean>
</beans>
public class T {

	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		People zhangsan=(People)ac.getBean("zhangsan");
		System.out.println(zhangsan);
		
		People lisi=(People)ac.getBean("lisi");
		System.out.println(lisi);
	}
	

}

依賴

​
<?xml version="1.0" encoding="UTF-8"?>
<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">
	
	<bean id="dog" class="com.java.entity.Dog">
		<property name="name" value="jack"></property>
	</bean>

	<bean id="zhangsan" parent="abstractPeople" depends-on="autority">
		<property name="id" value="1"></property>
		<property name="name" value="張三"></property>
	</bean>
	
	<bean id="lisi" parent="abstractPeople">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name="age" value="20"></property>
		<property name="dog" ref="dog"></property>
	</bean>
	
	
	<bean id="autority" class="com.java.service.Authority"></bean>
</beans>

​

使用註解,讓 Spring 容器幫我們產生 Person 物件

使用註解

在 applicationContext.xml 中引入名稱空間

引入的名稱空間,簡單來說就是用來約束xml檔案格式的。第一個 xmlns:context ,這表示標籤格式應該是 <context:標

在 applicationContext.xml 檔案中引入註解掃描器

<!-- 元件掃描,掃描含有註解的類 -->
    <context:component-scan base-package="com.my.annotation"></context:component-scan>

base-package:表示含有註解類的包名

     如果掃描多個包,則上面的程式碼書寫多行,改變 base-package 裡面的內容即可!

  @Component

  如果一個類上加了@Component註解,就會進行如下的法則

              如果其value屬性的值為""

                    @Component

                    public class Person {}

                      等價於

                    <bean id="person" class="..Person">

             如果其value屬性的值不為""

                    @Component("p")

                    public class Person {}

                     等價於
 
                   <bean id="p" class="..Person">

在 Person 類中添加註解@Component

    public void testAnnotation(){
        //1、啟動 spring 容器
        //2、從 spring 容器中取出資料
        //3、通過物件呼叫方法
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) context.getBean("person");
        System.out.println(person.getPname());
    }
@Repository :dao層
@Service:service層
@Controller:web層

註解 @Resource

@Resource 註解,它可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作。 通過 @Resource 的使用來消除 set ,get方法。

  @Resource註解以後,判斷該註解name的屬性是否為""(name沒有寫)

    ①、如果沒有寫name屬性,則會讓屬性的名稱的值和spring配置檔案bean中ID的值做匹配(如果沒有進行配置,也和註解@Component進行匹配),如果匹配成功則賦值,如果匹配不成功,則會按照spring配置檔案class型別進行匹配,如果匹配不成功,則報錯

    ②、如果有name屬性,則會按照name屬性的值和spring的bean中ID進行匹配,匹配成功,則賦值,不成功則報錯

不使用註解:

<property name="students">
    <ref bean="student"/>
</property>
<bean id="student" class="com.my.annotation_di.Student"></bean>

使用註解:

註解 @Autowired

功能和註解 @Resource 一樣,可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作。只不過註解@Resource 是按照名稱來進行裝配,而@Autowired 則是按照型別來進行裝配。

 在使用@Autowired時,首先在容器中查詢對應型別的bean

    如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的資料

    如果查詢的結果不止一個,那麼@Autowired會根據名稱來查詢。

    如果查詢的結果為空,那麼會丟擲異常。解決方法時,使用required=false

建立介面 PersonDao

public interface PersonDao {
     
    public void savePerson();
 
}

建立一個介面實現類 PersonDaoImplOne

import org.springframework.stereotype.Component;
 
@Component("personDaoImplOne")
public class PersonDaoImplOne implements PersonDao{
 
    @Override
    public void savePerson() {
        System.out.println("save Person One");
         
    }
 
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service("personService")
public class PersonService{
    @Autowired
    private PersonDao personDao;
     
    public void savePerson() {
        this.personDao.savePerson();
    }
 
}

  注意:這裡我們在 private PesronDao personDao 上面添加了註解 @Autowired,它首先會根據型別去匹配,PersonDao 是一個介面,它的實現類是 PesronDaoImpOne,那麼這裡的意思就是:

  PersonDao personDao = new PersonDaoImpOne();

  那麼問題來了,如果 PersonDao 的實現類有多個呢?我們建立第一個實現類 PersonDaoImpTwo

第一種方法:更改名稱

 第二種方法:@Autowired 和 @Qualifier("名稱") 配合使用

AOP(Aspect Oriented Programming),通常稱為面向切面程式設計。它利用一種稱為"橫切"的技術,剖解開封裝的物件內部,並將那些影響了多個類的公共行為封裝到一個可重用模組,並將其命名為"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻為業務模組所共同呼叫的邏輯或責任封裝起來,便於減少系統的重複程式碼,降低模組之間的耦合度,並有利於未來的可操作性和可維護性。

靜態代理

增加和刪除操作都必須要開啟事務,操作完成之後要提交事務。

public interface UserService {
    //新增 user
    public void addUser(User user);
    //刪除 user
    public void deleteUser(int uid);
}

建立 UserService的實現類

public class UserServiceImpl implements UserService{
    @Override
    public void addUser(User user) {
        System.out.println("增加 User");
    }
    @Override
    public void deleteUser(int uid) {
        System.out.println("刪除 User");
    }
}

建立事務類 MyTransaction

public class MyTransaction {
    //開啟事務
    public void before(){
        System.out.println("開啟事務");
    }
    //提交事務
    public void after(){
        System.out.println("提交事務");
    }
}

建立代理類 ProxyUser.java

public class ProxyUser implements UserService{
    //真實類
    private UserService userService;
    //事務類
    private MyTransaction transaction;
    //使用建構函式例項化
    public ProxyUser(UserService userService,MyTransaction transaction){
        this.userService = userService;
        this.transaction = transaction;
    }
    @Override
    public void addUser(User user) {
        transaction.before();
        userService.addUser(user);
        transaction.after();
    }
    @Override
    public void deleteUser(int uid) {
        transaction.before();
        userService.deleteUser(uid);
        transaction.after();       
    }
}
@Test
    public void testOne(){
        MyTransaction transaction = new MyTransaction();
        UserService userService = new UserServiceImpl();
        //產生靜態代理物件
        ProxyUser proxy = new ProxyUser(userService, transaction);
        proxy.addUser(null);
        proxy.deleteUser(0);
    }

業務類UserServiceImpl 只需要關注業務邏輯本身,保證了業務的重用性,這也是代理類的優點

這樣寫的缺點:

 ①、代理物件的一個介面只服務於一種型別的物件,如果要代理的方法很多,勢必要為每一種方法都進行代理,靜態代理在程式規模稍大時就無法勝任了。

  ②、如果介面增加一個方法,比如 UserService 增加修改 updateUser()方法,則除了所有實現類需要實現這個方法外,所有代理類也需要實現此方法。增加了程式碼維護的複雜度。

使用JDK動態代理

 動態代理就不要自己手動生成代理類了,我們去掉 ProxyUser.java 類,增加一個 ObjectInterceptor.java 類

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
import com.my.aop.one.MyTransaction;
 
public class ObjectInterceptor implements InvocationHandler{
    //目標類
    private Object target;
    //切面類(這裡指事務類)
    private MyTransaction transaction;
     
    //通過構造器賦值
    public ObjectInterceptor(Object target,MyTransaction transaction){
        this.target = target;
        this.transaction = transaction;
    }
     
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //開啟事務
        this.transaction.before();
        //呼叫目標類方法
        method.invoke(this.target, args);
        //提交事務
        this.transaction.after();
        return null;
    }
     
}
@Test
    public void testOne(){
        //目標類
        Object target = new UserServiceImpl();
        //事務類
        MyTransaction transaction = new MyTransaction();
        ObjectInterceptor proxyObject = new ObjectInterceptor(target, transaction);
        /**
         * 三個引數的含義:
         * 1、目標類的類載入器
         * 2、目標類所有實現的介面
         * 3、攔截器
         */
        UserService userService = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), proxyObject);
        userService.addUser(null);
    }

後期在 UserService 中增加業務方法,都不用更改程式碼就能自動給我們生成代理物件。而且將 UserService 換成別的類也是可以的。

  也就是做到了代理物件能夠代理多個目標類,多個目標方法。

  注意:我們這裡使用的是 JDK 動態代理,要求是必須要實現介面。與之對應的另外一種動態代理實現模式 Cglib,則不需要,我們這裡就不講解 cglib 的實現方式了。

AOP 關鍵術語

 1.target:目標類,需要被代理的類。例如:UserService

  2.Joinpoint(連線點):所謂連線點是指那些可能被攔截到的方法。例如:所有的方法

  3.PointCut 切入點:已經被增強的連線點。例如:addUser()

  4.advice 通知/增強,增強程式碼。例如:after、before

  5. Weaving(織入):是指把增強advice應用到目標物件target來建立新的代理物件proxy的過程.

  6.proxy 代理類:通知+切入點

  7. Aspect(切面): 是切入點pointcut和通知advice的結合

  具體可以根據下面這張圖來理解:

AOP 的通知型別  

  Spring按照通知Advice在目標類方法的連線點位置,可以分為5類

  • 前置通知 org.springframework.aop.MethodBeforeAdvice
    • 在目標方法執行前實施增強,比如上面例子的 before()方法
  • 後置通知 org.springframework.aop.AfterReturningAdvice
    • 在目標方法執行後實施增強,比如上面例子的 after()方法
  • 環繞通知 org.aopalliance.intercept.MethodInterceptor
    • 在目標方法執行前後實施增強
  • 異常丟擲通知 org.springframework.aop.ThrowsAdvice
    • 在方法丟擲異常後實施增強
  • 引介通知 org.springframework.aop.IntroductionInterceptor

      在目標類中新增一些新的方法和屬性

 我們只需要在Spring 的配置檔案 applicationContext.xml 進行如下配置

<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">
    <!--1、 建立目標類 -->
    <bean id="userService" class="com.my.aop.UserServiceImpl"></bean>  
    <!--2、建立切面類(通知)  -->
    <bean id="transaction" class="com.my.aop.one.MyTransaction"></bean>
     
    <!--3、aop程式設計 
        3.1 匯入名稱空間
        3.2 使用 <aop:config>進行配置
                proxy-target-class="true" 宣告時使用cglib代理
                如果不宣告,Spring 會自動選擇cglib代理還是JDK動態代理
            <aop:pointcut> 切入點 ,從目標物件獲得具體方法
            <aop:advisor> 特殊的切面,只有一個通知 和 一個切入點
                advice-ref 通知引用
                pointcut-ref 切入點引用
        3.3 切入點表示式
            execution(* com.my.aop.*.*(..))
            選擇方法         返回值任意   包             類名任意   方法名任意   引數任意
     
    -->
    <aop:config>
        <!-- 切入點表示式 -->
        <aop:pointcut expression="execution(* com.my.aop.*.*(..))" id="myPointCut"/>
        <aop:aspect ref="transaction">
            <!-- 配置前置通知,注意 method 的值要和 對應切面的類方法名稱相同 -->
            <aop:before method="before" pointcut-ref="myPointCut"></aop:before>
            <aop:after-returning method="after" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>
@Test
    public void testAop(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService useService = (UserService) context.getBean("userService");
        useService.addUser(null);
    }

 ①、 切入點表示式,一個完整的方法表示如下:

execution(modifiers-pattern? ref-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
                類修飾符           返回值           方法所在的包                  方法名                     方法丟擲的異常

那麼根據上面的對比,我們就很好理解:

execution(* com.my.aop.*.*(..))
選擇方法         返回值任意   包             類名任意   方法名任意   引數任意

 那麼它表達的意思是 返回值任意,包名為 com.ys.aop 下的任意類名中的任意方法名,引數任意。

如果切入點表示式有多個不同目錄呢?

<aop:pointcut expression="execution(* com.my.*Service1.*(..)) ||
                          execution(* com.my.*Service2.*(..))" id="myPointCut"/>

表示匹配 com.my包下的,以 Service1結尾或者以Service2結尾的類的任意方法。

 AOP 切入點表示式支援多種形式的定義規則:

1、execution:匹配方法的執行(常用)
        execution(public *.*(..))
2.within:匹配包或子包中的方法(瞭解)
    within(com.my.aop..*)
3.this:匹配實現介面的代理物件中的方法(瞭解)
    this(com.my.aop.user.UserDAO)
4.target:匹配實現介面的目標物件中的方法(瞭解)
    target(com.my.aop.user.UserDAO)
5.args:匹配引數格式符合標準的方法(瞭解)
    args(int,int)
6.bean(id)  對指定的bean所有的方法(瞭解)
    bean('userServiceId')

②、springAOP 的具體載入步驟:

  1、當 spring 容器啟動的時候,載入了 spring 的配置檔案

  2、為配置檔案中的所有 bean 建立物件

  3、spring 容器會解析 aop:config 的配置

       1、解析切入點表示式,用切入點表示式和納入 spring 容器中的 bean 做匹配

           如果匹配成功,則會為該 bean 建立代理物件,代理物件的方法=目標方法+通知

           如果匹配不成功,不會建立代理物件

  4、在客戶端利用 context.getBean() 獲取物件時,如果該物件有代理物件,則返回代理物件;如果沒有,則返回目標物件

    說明:如果目標類沒有實現介面,則 spring 容器會採用 cglib 的方式產生代理物件,如果實現了介面,則會採用 jdk 的方式

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class StudentServiceAspect {

	public void doBefore(JoinPoint jp){
		System.out.println("類名:"+jp.getTarget().getClass().getName());
		System.out.println("方法名:"+jp.getSignature().getName());
		System.out.println("開始新增學生:"+jp.getArgs()[0]);
	}
	
	public void doAfter(JoinPoint jp){
		System.out.println("類名:"+jp.getTarget().getClass().getName());
		System.out.println("方法名:"+jp.getSignature().getName());
		System.out.println("學生新增完成:"+jp.getArgs()[0]);
	}
	
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("新增學生前");
		Object retVal=pjp.proceed();
		System.out.println(retVal);
		System.out.println("新增學生後");
		return retVal;
	}
	
	public void doAfterReturning(JoinPoint jp){
		System.out.println("返回通知");
	}
	
	public void doAfterThrowing(JoinPoint jp,Throwable ex){
		System.out.println("異常通知");
		System.out.println("異常資訊:"+ex.getMessage());
	}
}
<?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: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">
	
	<bean id="studentServiceAspect" class="com.java.advice.StudentServiceAspect"></bean>
	
	<bean id="studentService" class="com.java.service.impl.StudentServiceImpl"></bean>
	
	<aop:config>
		<aop:aspect id="studentServiceAspect" ref="studentServiceAspect">
			<aop:pointcut expression="execution(* com.java.service.*.*(..))" id="businessService"/>
			<aop:before method="doBefore" pointcut-ref="businessService"/>
			<aop:after method="doAfter" pointcut-ref="businessService"/>
			<aop:around method="doAround" pointcut-ref="businessService"/>
			<aop:after-returning method="doAfterReturning" pointcut-ref="businessService"/>
			<aop:after-throwing method="doAfterThrowing" pointcut-ref="businessService" throwing="ex"/>
		</aop:aspect> 
	</aop:config>
</beans>
public class StudentServiceImpl implements StudentService{

	@Override
	public void addStudent(String name) {
		// System.out.println("開始新增學生"+name);
		System.out.println("新增學生"+name);
		System.out.println(1/0);
		// System.out.println("完成學生"+name+"的新增");
	}

}

AspectJ是一個面向切面的框架,它擴充套件了Java語言。

Aspect 通知型別,定義了型別名稱以及方法格式。型別如下:

    before:前置通知(應用:各種校驗)
    在方法執行前執行,如果通知丟擲異常,阻止方法執行
afterReturning:後置通知(應用:常規資料處理)
    方法正常返回後執行,如果方法中丟擲異常,通知無法執行
    必須在方法執行後才執行,所以可以獲得方法的返回值。
around:環繞通知(應用:十分強大,可以做任何事情)
    方法執行前後分別執行,可以阻止方法的執行
    必須手動執行目標方法
afterThrowing:丟擲異常通知(應用:包裝異常資訊)
    方法丟擲異常後執行,如果方法沒有丟擲異常,無法執行
after:最終通知(應用:清理現場)
    方法執行完畢後執行,無論方法中是否出現異常

這裡最重要的是around,環繞通知,它可以代替上面的任意通知。

在程式中表示的意思如下:

try{
     //前置:before
    //手動執行目標方法
    //後置:afterRetruning
} catch(){
    //丟擲異常 afterThrowing
} finally{
    //最終 after
}

AOP具體例項

public interface UserService {
    //新增 user
    public void addUser();
    //刪除 user
    public void deleteUser();
}

建立實現類

public class UserServiceImpl implements UserService{
    @Override
    public void addUser() {
        System.out.println("增加 User");
    }
    @Override
    public void deleteUser() {
        System.out.println("刪除 User");
    }
}

建立切面類(包含各種通知)

import org.aspectj.lang.JoinPoint;
 
 
public class MyAspect {
    /**
     * JoinPoint 能獲取目標方法的一些基本資訊
     * @param joinPoint
     */
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知 : " + joinPoint.getSignature().getName());
    }
     
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("後置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
    }
     
    public void myAfter(){
        System.out.println("最終通知");
    }
 
}

建立spring配置檔案applicationContext.xml

<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">
    <!--1、 建立目標類 -->
    <bean id="userService" class="com.my.aop.UserServiceImpl"></bean>  
    <!--2、建立切面類(通知)  -->
    <bean id="myAspect" class="com.my.aop.MyAspect"></bean>
     
    <!--3、aop程式設計 
        3.1 匯入名稱空間
        3.2 使用 <aop:config>進行配置
                proxy-target-class="true" 宣告時使用cglib代理
                如果不宣告,Spring 會自動選擇cglib代理還是JDK動態代理
            <aop:pointcut> 切入點 ,從目標物件獲得具體方法
            <aop:advisor> 特殊的切面,只有一個通知 和 一個切入點
                advice-ref 通知引用
                pointcut-ref 切入點引用
        3.3 切入點表示式
            execution(* com.my.aop.*.*(..))
            選擇方法         返回值任意   包             類名任意   方法名任意   引數任意
     
    -->
    <aop:config>
        <aop:aspect ref="myAspect">
        <!-- 切入點表示式 -->
        <aop:pointcut expression="execution(* com.my.aop.*.*(..))" id="myPointCut"/>
        <!-- 3.1 前置通知
                <aop:before method="" pointcut="" pointcut-ref=""/>
                    method : 通知,及方法名
                    pointcut :切入點表示式,此表示式只能當前通知使用。
                    pointcut-ref : 切入點引用,可以與其他通知共享切入點。