1、首先明白什麼叫依賴注入、控制反轉,及其作用

控制反轉(Inversion of Control ,Ioc)所謂控制反轉就是應用本身不負責依賴物件的建立及維護,依賴物件的建立及維護由外部容器來負責。這樣控制權就由應用轉移到了外部容器,控制權的轉移就是所謂反轉。   依賴注入(Dependency Injection)所謂依賴注入就是指:在執行期間,有外部容器動態地將依賴物件注入到元件中(構造方法和set方法)

好處:   

1.降低元件之間的耦合度,實現軟體各層之間的解耦.2.可以使容器提供眾多服務如事務管理訊息服務處理等等。當我們使用容器管理事務時,開發人員就不需要手工 控制事務,也不需要處理複雜的事務傳播3.容器提供單例模式支援,開發人員不需要自己編寫實現程式碼.4.容器提供了AOP技術,利用它很容易實現如許可權攔截,執行期監控等功能5.容器提供眾多的輔佐類,使這些類可以加快應用的開發.如jdbcTemplate HibernateTemplate

個人理解依賴注入完全實現了面向介面程式設計,只需定義方法,無需實現,首先面向介面程式設計的好處就是統一編碼風格。由容器建立物件,可以說是低內聚,高耦合。增加了程式碼的可維護性。

2、spring對於程式設計人員最重要的是寫xml配置檔案和使用註解那麼我這裡給幾個簡單的案例

依賴注入配置xml

<bean id="person" class="com.itheima12.spring.di.xml.setter.Person">
   		<!-- 
   			property就是一個bean的屬性
   			  name就是用來描述屬性的名稱
   			  value就是值,如果是一般型別(基本型別和String)
   		 -->
   		<property name="pid" value="1"></property>
   		<property name="name" value="狗蛋"></property>
   		<!-- 
   			spring容器內部建立的student物件給Person的student物件賦值了
   		 -->
   		<property name="student">
   			<ref bean="student"/>
   		</property>
   		
   		<property name="lists">
   			<list>
   				<value>list1</value>
   				<value>list2</value>
   				<ref bean="student"/>
   			</list>
   		</property>
   		<property name="sets">
   			<set>
   				<value>set1</value>
   				<value>set2</value>
   				<ref bean="student"/>
   			</set>
   		</property>
   		<property name="map">
   			<map>
   				<entry key="m1">
   					<value>map1</value>
   				</entry>
   				<entry key="m2">
   					<ref bean="student"/>
   				</entry>
   			</map>
   		</property>
   		<property name="properties">
   			<props>
   				<prop key="p1">prop1</prop>
   				<prop key="p2">prop2</prop>
   			</props>
   		</property>
   		<property name="objects">
   			<list>
   				<value>obj1</value>
   				<ref bean="student"/>
   			</list>
   		</property>
   </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-2.5.xsd">
   <bean id="person" class="com.itheima12.spring.di.xml.constructor.Person">
   		<!-- 
   			constructor-arg指的是構造器中的引數
   			 index 角標  從0開始
   			 value 如果一般型別,用value賦值
   			 ref   引用型別賦值
   		 -->
   		<constructor-arg index="0" value="asdfsafd"></constructor-arg>
   		<constructor-arg index="1" ref="student"></constructor-arg>
   </bean>
   <bean id="student" class="com.itheima12.spring.di.xml.constructor.Student"></bean>
</beans>
註解配置xml
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
   <!-- 
   		component:把一個類放入到spring容器中,該類就是一個component
   		在base-package指定的包及子包下掃描所有的類
    -->
   <context:component-scan base-package="com.itheima12.spring.scan">
   </context:component-scan>
</beans>

好了這裡就主要介紹了這些,還有很多遇到時在看文件吧,百度吧(包括單例,多例,事務 ,aop,繼承,初始化銷燬(
<bean id="helloWorld" class="com.itheima12.spring.initdestroy.HelloWorld"
		init-method="init"
		destroy-method="destroy"></bean>

),懶載入,別名,工廠方法建立物件等等,都可以看案例。

3、我們來學習aop

   切面(Aspect):其實就是共有功能的實現。如日誌切面、許可權切面、事務切面等。在實際應用中通常是一個存放共有功能實現的普通Java類,之所以能被AOP容器識別成切面,是在配置中指定的。

   通知(Advice):是切面的具體實現。以目標方法為參照點,根據放置的地方不同,可分為前置通知(Before)、後置通知(AfterReturning)、異常通知(AfterThrowing)、最終通知(After)與環繞通知(Around5種。在實際應用中通常是切面類中的一個方法,具體屬於哪類通知,同樣是在配置中指定的。

   連線點(Joinpoint):就是程式在執行過程中能夠插入切面的地點。例如,方法呼叫、異常丟擲或欄位修改等,但spring只支援方法級的連線點。

   切入點(Pointcut):用於定義通知應該切入到哪些連線點上。不同的通知通常需要切入到不同的連線點上,這種精準的匹配是由切入點的正則表示式來定義的。

  目標物件(Target):就是那些即將切入切面的物件,也就是那些被通知的物件。這些物件中已經只剩下乾乾淨淨的核心業務邏輯程式碼了,所有的共有功能程式碼等待AOP容器的切入。

  代理物件(Proxy):將通知應用到目標物件之後被動態建立的物件。可以簡單地理解為,代理物件的功能等於目標物件的核心業務邏輯功能加上共有功能。代理物件對於使用者而言是透明的,是程式執行過程中的產物。

  織入(Weaving):將切面應用到目標物件從而建立一個新的代理物件的過程。這個過程可以發生在編譯期、類裝載期及執行期,當然不同的發生點有著不同的前提條件。譬如發生在編譯期的話,就要求有一個支援這種AOP實現的特殊編譯器;發生在類裝載期,就要求有一個支援AOP實現的特殊類裝載器;只有發生在執行期,則可直接通過Java語言的反射機制與動態代理機制來動態實現

  意義:在開發的時候,各個切面和目標類是完全鬆耦合的,但是最終生成的代理物件的方法把這幾個代理物件的內容就結合起來了。

通知介紹

攔截環繞通知

/**
 * 環繞通知
 *   joinPoint.proceed();這個程式碼如果在環繞通知中不寫,則目標方法不再執行
    *	能控制目標方法的執行
   *前置通知和後置通知能在目標方法的前面和後面加一些程式碼,但是不能控制目標方法的執行
 */
public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("begin");
joinPoint.proceed();//呼叫目標方法
System.out.println("end");
}


Spring中最基礎的通知型別是攔截環繞通知interception around advice)。

Spring裡使用方法攔截的環繞通知相容AOP聯盟介面。

 前置通知

個更簡單的通知型別是前置通知before advice)。 它不需要MethodInvocation物件,因為它只是在進入方法之前被呼叫。

前置通知的一個主要優點是它不需要呼叫proceed()方法,因此就不會發生無意間執行攔截器鏈失敗的情況。

/*

 前置通知
         1、在目標方法執行之前
         2、獲取不到目標方法的返回
      <aop:before method="beginTransaction" pointcut-ref="perform"/>

 * 引數:連線點
 */
public void beginTransaction(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("連線點的名稱:"+methodName);
System.out.println("目標類:"+joinPoint.getTarget().getClass());
System.out.println("begin transaction");
}

 異常通知

<!--
      異常通知
       -->
  	    	<aop:after-throwing method="throwingMethod" throwing="ex" pointcut-ref="perform"/>
/**
 * 異常通知
 *    接受目標方法丟擲的異常
 */
public void throwingMethod(JoinPoint joinPoint,Throwable ex){
System.out.println(ex.getMessage());
}


 後置通知

    	/**
 * 後置通知
 *     在目標方法執行之後
  1、後置通知可以獲取到目標方法的返回值
         2、當目標方法丟擲異常,後置通知將不再執行
      <aop:after-returning method="commit" pointcut-ref="perform" returning="val"/>

 */
public void commit(JoinPoint joinPoint,Object val){
System.out.println("目標方法的返回值:"+val);
System.out.println("commit");
}

後置通知可以訪問返回值(但不能進行修改),被呼叫方法,方法引數以及目標物件。

最終通知

/**
 * 最終通知
  無論目標方法是否丟擲異常都將執行
  	    	<aop:after method="finallyMethod" pointcut-ref="perform"/>

 */
public void finallyMethod(){
System.out.println("finally method");
}

引入通知

Spring 把引入通知(introduction advice)作為一種特殊的攔截通知進行處理。

引入通知需要一個IntroductionAdvisor,和一個IntroductionInterceptor,後者實現下面的介面:

Public interface IntroductionInterceptor extends MethodInterceptor {   

                boolean implementsInterface(Class intf);

            }

繼承自AOP聯盟MethodInterceptor 介面的invoke()方法,必須確保實現引入:也就是說,如果被呼叫的方法位於一個已經被引入接口裡,這個引入攔截器將負責完成對這個方法的呼叫--因為它不能呼叫proceed()方法。

引入通知不能和任何切入點一起使用,因為它是應用在類級別而不是方法級別。

xml檔案配置

<aop:config>
		<!-- 面 -->
		<aop:aspect ref="cacheInterceptor">
			
			
			<!-- 點 -->
			<!-- 環繞通知 -->
			<aop:around method="doAround"  pointcut="execution(* cn.itcast.core.service.*.*.get*(..))"/>
			<!-- 變更  -->
			<!-- 後知通知 -->
			<aop:after method="doAfter" pointcut="execution(* cn.itcast.core.service.*.*.update*(..))"/>
			<aop:after method="doAfter" pointcut="execution(* cn.itcast.core.service.*.*.add*(..))"/>
			<aop:after method="doAfter" pointcut="execution(* cn.itcast.core.service.*.*.delete*(..))"/>
			
			<!--前置通知-->
			<!-- <aop:before method="" pointcut-ref=""/> -->
			
		</aop:aspect>
			</aop:config>

切入點表示式一般格式


Spring AOP 使用者可能會經常使用 execution切入點指示符。執行表示式的格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)

          throws-pattern?)

除了返回型別模式(上面程式碼片斷中的ret-type-pattern),名字模式和引數模式以外, 所有的部分都是可選的。

service包或其子包中定義的任意方法的執行:(國家電力)

execution(* com.xyz.service..*.*(..))

service包中定義的任意方法的執行:

execution(* com.xyz.service.*.*(..))

下一個知識點