1. 程式人生 > >spring工作原理

spring工作原理

模塊 反射機制 spa oca .class 關聯 sso 三種方式 +=

對spring原理以前寫過類似的博客,地址:點擊打開鏈接。

但是經過一些時間後,盡管天天用著spring,但一提到原理方面,就遺忘了呢?就記得AOP和IOC,但是沒有清楚的講出來呢?

思考了一下這個問題,總結例如以下。

1、對於美食的喜愛,以後學習技術的過程中,多和美食相關聯,和忘不掉的那些相關聯。

2、總是想著抓住最後一根稻草,卻從來沒有想過怎樣學會遊泳。


IOC(inversion of control)控制反轉

概念:控制權有對象本身轉向容器。由容器依據配置文件區創建實例並創建各個實例之間的依賴關系。

核心:spring封裝了抽象工廠模式;bean工廠創建的各個實例稱作為bean。

理解:喜歡吃的東西不一定自己親自去做。交給食品加工廠去做不是更好嗎。spring讓一個對象不用創建new了。能夠自己主動生產。這就是利用java的反射機制動態創建、調用對象,spring就是在執行時,根xml 是pring配置文件動態創建對象,和調用對象裏的方法的。

spring IOC 應用了單例模式,一次new一個全局對象,也能夠在配置文件裏進行配置,配置為不使用單例模式。


AOP(aspect oriented programming)面向切面編程

1、不使用代理方式

我們以這個為實例(http://blog.csdn.net/lovesummerforever/article/details/22668947),分別畫出類圖例如以下所看到的:

技術分享

2、代理的兩種方式

靜態代理

針對每一個詳細類分別編寫代理類。針對一個接口編寫一個代理類;

技術分享

動態代理

針對一個方面編程寫一個invocationHandler。然後借用JDK反射包中的proxy類為各個接口動態生成對應的代理類。

技術分享

http://blog.csdn.net/lovesummerforever/article/details/22664647

本篇文章有非常好的解釋。比方針對調用接口的一些安全性檢查,非常多的類的方法都要改動,假設使用靜態代理的話,建立代理類並繼承真實的類,我們把安全性檢查抽象出一個方法,這樣每次調用接口方法前,都進行安全性檢查,可是這樣的方法在代碼編譯的時候就創建代理類了,而且對原始類的改動,就要更改代理類,這樣不符合類的開閉原則(軟件設計應該對擴展開放,對改動關閉)。那如何動態的創建這個代理類(執行時)。於是我們能夠使用JDK自帶的動態代理,在使用這個類的時候創建。


怎樣使用JDK動態代理呢?

1、實現InvocationHandler接口。

2、通過Proxy,依據目標來生成代理。


3、invoke方法,該方法中調用詳細的切入方法。

動態代理與靜態代理差別

靜態代理:由程序猿創建,再對其編譯。在程序執行之前.class文件已經存在了。靜態代理:在程序執行時。運用反射的機制動態創建而完畢。無需程序猿手動編寫代碼,利用jdk的動態代理機制就可以。不僅簡化了編程工作,且提高了軟件的可擴展性,由於java的反射機制能夠生成隨意類型的動態代理。


動態代理使用場景:不同意直接訪問某些類,對訪問要做特殊處理;或者對原始方法進行統一的擴展,比如日誌的記錄。



springAOP

springAOP核心也是動態代理,spring採用三種方式實現代理功能。

1、java的動態代理方式。2、CGlib方式。3、Aspectj方式。

默認模式

spring使用java動態代理和CGlib的混合方式提供服務。即若對象實現了接口則spring自己主動採用java動態代理進行支持。否則則採用CGlib方式進行支持;也能夠強制制定使用cglib方式代理,在配置文件裏進行配置。

(http://my.oschina.net/coldlemon/blog/178586)

比如spring aop控制事務代碼例如以下

	<!--事務相關控制-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">     
          <property name="dataSource" ref="dataSource"></property>
    </bean>     
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    	<tx:attributes>
    		<tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="Exception" />
      		<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception" />  		
		    <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="Exception" />
		    <tx:method name="find*" read-only="true"/>
    	</tx:attributes>
    </tx:advice>
    <!--把事務控制在Service層-->
    <aop:config>    
	    <aop:pointcut id="pc" expression="execution(public * com.msc.biz.service.*.*(..))" /> 
	    <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
    </aop:config>

通過spring AOP特性來加入日誌模塊


日誌類:

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
  
  
/** 
 * 日誌記錄,加入、刪除、改動方法AOP 
 * @author HotStrong 
 *  
 */  
public class LogAspect {  
	private static final Logger logger = Logger.getLogger(LogAspect.class);
          
	//在類裏面寫方法,方法名詩能夠隨意的。此處我用標準的before和after來表示  
    //此處的JoinPoint類能夠獲取,action全部的相關配置信息和request等內置對象。  
	 public void before(JoinPoint joinpoint){  
	 }  
	 public void after(JoinPoint joinpoint){  
	 } 
	  
//有參並有返回值的方法
	 public void logArgAndReturn(JoinPoint point, Object returnObj) {
		 //此方法返回的是一個數組。數組中包含request以及ActionCofig等類對象
		 logger.debug("運行的方法名為:"+point.getSignature());
		 Object[] args = point.getArgs();
		 String arg="";
	  if (args != null) {
	      for (Object obj : args) {
	    	  if(obj != null){
	    		  arg+=obj.toString()+",";
	    	  }
	    	 
	  }
	  logger.debug("運行的方法參數為:"+arg);
	  logger.debug("運行的方法返回值為:"+returnObj);  
     }
  }
}

配置切面,切入點,和通知

 <!--針對於service中方法的監控--> 
	<bean id="logProcess" class="com.xsc.biz.common.LogAspect"></bean> <!--將日誌類註入到bean中。-->
	<aop:config>  
               <aop:aspect id="b" ref="logProcess"><!--調用日誌類-->  
               <aop:pointcut id="log" expression="execution(* com.xsc.biz.service.*.*(..))"/><!--配置在log包下全部的類在調用之前都會被攔截-->  
               <!--在log包以下全部的類的全部方法被調用之前都調用MyLog中的before方法-->
               <aop:before pointcut-ref="log" method="before"/> 
               <!--在log包以下全部的類的全部方法被調用之後都調用MyLog中的after方法--> 
               <aop:after pointcut-ref="log" method="after"/>  
  		<aop:after-returning method="logArgAndReturn" returning="returnObj" pointcut-ref="log"/>
               </aop:aspect>   
    </aop:config>


這裏配置<aop:aspect>是針對什麽問題,調用哪個類。

<aop:pointcut>是日誌類方法的切入點,是在業務層。全部方法運行完成切入。<aop:before><aop:after>是通知什麽時候運行什麽方法<aop:after-returning>是處理結果返回時的操作。運行方法logArgAndReturn。



有些倉促。有時間一定會清晰的再整理一遍。





spring工作原理