proxy-target-class屬性: proxy-target-class屬性值決定是基於接口的仍是基於類的代理被建立。若是proxy-target-class 屬性值被設置爲true,那麼基於類的代理將起做用(這時須要cglib庫)。若是proxy-target-class屬值被設置爲false或者這個屬性被省略,那麼標準的JDK 基於接口的代理 Spring事務傳播機制(面試題) 概述 當咱們調用一個基於Spring的Service接口方法(如UserService#addUser())時,它將運行於Spring管理的事務環境中,Service接口方法可能會在內部調用其它的Service接口方法以共同完成一個完整的業務操做,所以就會產生服務接口方法嵌套調用的狀況,Spring經過事務傳播行爲控制當前的事務如何傳播到被嵌套調用的目標服務接口方法中。 事務傳播是Spring進行事務管理的重要概念,其重要性怎麼強調都不爲過。可是事務傳播行爲也是被誤解最多的地方,在本文裏,咱們將詳細分析不一樣事務傳播行爲的表現形式,掌握它們之間的區別。 事務傳播行爲種類 Spring在TransactionDefinition接口中規定了7種類型的事務傳播行爲,它們規定了事務方法和事務方法發生嵌套調用時事務如何進行傳播: 事務傳播行爲類型 說明 PROPAGATION_REQUIRED(默認) 若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是最多見的選擇。 PROPAGATION_SUPPORTS 支持當前事務,若是當前沒有事務,就以非事務方式執行。 PROPAGATION_MANDATORY 使用當前的事務,若是當前沒有事務,就拋出異常。 PROPAGATION_REQUIRES_NEW 新建事務,若是當前存在事務,把當前事務掛起。 PROPAGATION_NOT_SUPPORTED 以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。 PROPAGATION_NEVER 以非事務方式執行,若是當前存在事務,則拋出異常。 PROPAGATION_NESTED 若是當前存在事務,則在嵌套事務內執行(REQUIRES_NEW)。若是當前沒有事務,則執行中PROPAGATION_REQUIRED相似的操做。 PROPAGATION_NOT_SUPPORTED @Override public boolean existsName(String name) { boolean result= this.flinkTypeDao.existsName(name)>0; //模擬作插入操做 FlinkType ft=new FlinkType(); ft.setTypeName("掛起事務"); this.flinkTypeDao.insert(ft); return result; } <tx:method name="insert*" propagation=" PROPAGATION_NOT_SUPPORTED " /> 以非事務的方式提交,若是存在事務,就將當前事務掛起,纔會執行insert() Spring事務何時才能回滾? 發生 RuntimeException (子類)這種時機,纔會發生回滾,不然不會回滾 小結 在Spring聲明式事務管理的配置中,事務傳播行爲是最容易被誤解的配置項,緣由在於事務傳播行爲名稱(如PROPAGATION_NESTED:嵌套式事務)和代碼結構的相似性上(業務類方法嵌套調用另外一個業務類方法)。這種誤解在不少Spring開發者中普遍存在,本文深刻講解了Spring事務傳播行爲對業務方法嵌套調用的真實影響,但願能幫助讀者化解對事務傳播行爲的困惑。 請寫你常見的異常? IOException, SqlException, FileNotFoundException, ClassNotFoundException NullPointerException,NumberFormatException ,IndexOutOfBoundsException,ClassCastException, StackOverException,StackOverflowError(遞歸致使的死循環) MappingNotFoundException,DateTimeException , struts的通用配置: <!-- 約定大於配置/admin/Flinktype_list.action --> <package name="freemarkerPackage" namespace="/admin" extends="commonPackage" > <!-- /admin/Flinktype_list.action --> <action name="*_*" class="{1}Action" method="{2}"> <result name="{2}" type="freemarker">/admin/template/{1}/{2}.ftl</result> </action> </package> FlinktypeAction.java有個String list()-->return list() 交給freemarker編譯-->模板文件/admin/Flinktype/list.action 默認狀況事務傳播: @Override public boolean existsName(String name) { boolean result= this.flinkTypeDao.existsName(name)>0; //模擬作插入操做 FlinkType ft=new FlinkType(); ft.setTypeName("掛起事務"); this.flinkTypeDao.insert(ft); return result; } <tx:advice id="myAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 對你的哪些方法作哪些事務 --> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="execute*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <!-- 以find,get,其它除上面的外方法,都是隻讀事務 --> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" propagation="REQUIRED" read-only="true" /> </tx:attributes>此事務是一個只讀事務,insert新增不能成功 要解決這個問題,有兩種解決方案 1)、直接更改方法名, exsitsName-executeExistsName/insertExistsName/updateExistsName等 2)、更改事務傳播行爲existsName <tx:method name="existsName" propagation="PROPAGATION_REQUIRES_NEW" read-only="true" /> 1、Spring有2個最核心概念 Spring IoC(控制反轉) 和 Spring AOP(面向切面) 2、spring由哪幾個部分組成,每一個部份的使用 由7個部分組成 1)、Spring AOP 面向切面編程 (在程序運行的過程當中,動態地爲程序添加額外的功能) 2)、Spring Core 核心 (管理全部的bean) 3)、Spring ORM 對第三方的ORM框的支持 4)、Spring DAO 對數據庫和事務的支持和管理 5)、Spring Context 應用程序上下文 6)、Spring Web 支持web操做 7)、Spring Web MVC 本身開的MVC框架 核心容器: 核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉 (IOC) 模式將應用程序的配置和依賴性規範與實際的應用程序代碼分開。 Spring 上下文: Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。 Spring AOP: 經過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。因此,能夠很容易地使 Spring 框架管理的任何對象支持 AOP。Spring AOP 模塊爲基於 Spring 的應用程序中的對象提供了事務管理服務。經過使用 Spring AOP,不用依賴 EJB 組件,就能夠將聲明性事務管理集成到應用程序中。 Spring DAO: JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不一樣數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,而且極大地下降了須要編寫的異常代碼數量(例如打開和關閉鏈接)。Spring DAO 的面向 JDBC 的異常聽從通用的 DAO 異常層次結構。 Spring ORM: Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。全部這些都聽從 Spring 的通用事務和 DAO 異常層次結構。 Spring Web 模塊: Web 上下文模塊創建在應用程序上下文模塊之上,爲基於 Web 的應用程序提供了上下文。因此,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工做。 Spring MVC 框架: MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。經過策略接口,MVC 框架變成爲高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。 3、Spring IoC 管理全部的Bean,經過BeanFactory來管理的,它提供了建立類的2種方式: 3.1)、 單態Singleton 是默認的也是最經常使用的對象模型。 3.2)、原型 模型確保每次檢索都會建立單獨的對象。 4、Spring IoC 和 AOP的做用? IoC 你再也不手動的去new 對象,而是讓Spring依賴注入對象(@Autowired ,@Resource) AOP 動態爲程序添加額外的功能 (事務) 5、Spring優勢 (瞭解) 低侵入式設計 獨立於各類應用服務器 依賴注入特性將組件關係透明化,下降了耦合度 面向切面編程特性容許將通用任務進行集中式處理 與第三方框架的良好整合 6、Spring IoC 解耦 將組件對象的控制權從代碼自己轉移到外部容器 組件化的思想:分離關注點,接口和實現分離 依賴的注入:將組件的構建和使用分開 7、在web運行過程當中,除了掃包的方式 和@Resource @Autowired注入還有沒有其它方式? WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext()); Object obj=webApplicationContext .getBean("messagePojo"); 控制檯中使用 ClassPathXmlApplicationContext cpa=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //獲得spring管理的全部的對象 Object obj=cpa.getBean("messagePojo"); 8、Spring管理bean能夠有3種形式來注入對象 1)、set方法 注入的不是以變量爲準,而是以setXXX()方法爲準 2)、構造函數 2.1)、按構造函數中的參數類型依次注入 2.2)、按構造函數中的參數名稱注入 2.3)、按構造函數中的參數的下標註入 3)、以接口方式進行注入 9、其它類型注入 <!-- 給數組注入值 --> <property name="empName"> <list> <value>小明</value> <value>小明小明</value> <value>小明小明小明小明</value> </list> </property> <!-- 給list注入值 list 中能夠有至關的對象 --> <property name="empList"> <list> <ref bean="emp2" /> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> <ref bean="emp1"/> </list> </property> <!-- 給set注入值 set不能有相同的對象 --> <property name="empsets"> <set> <ref bean="emp1" /> <ref bean="emp2"/> <ref bean="emp2"/> <ref bean="emp2"/> <ref bean="emp2"/> </set> </property> <!-- 給map注入值 map只有key不同,就能夠裝配value --> <property name="empMaps"> <map> <entry key="11" value-ref="emp1" /> <entry key="22" value-ref="emp2"/> <entry key="22" value-ref="emp1"/> </map> </property> <!-- 給屬性集合配置 --> <property name="pp"> <props> <prop key="pp1">abcd</prop> <prop key="pp2">hello</prop> </props> </property> </bean> <bean id="emp1" class="com.hsp.collection.Employee"> <property name="name" value="北京"/> <property name="id" value="1"/> </bean> <bean id="emp2" class="com.hsp.collection.Employee"> <property name="name" value="天津"/> <property name="id" value="2"/> </bean> 10、Spring自動注入方式 @AutoWired set注入和構造注入有時在作配置時比較麻煩。因此框架爲了提升開發效率,提供自動裝配功能,簡化配置。spring框架式默認不支持自動裝配的,要想使用自動裝配須要修改spring配置文件中<bean>標籤的autowire屬性。自動裝配屬性有5個值可選,分別表明不一樣的含義。 1、byName 從Spring環境中獲取目標對象時,目標對象中的屬性會根據名稱在整個Spring環境中查找<bean>標籤的id屬性值。若是有相同的,那麼獲取這個對象,實現關聯。 整個Spring環境:表示全部的spring配置文件中查找,那麼id不能有重複的。 2、byType 從Spring環境中獲取目標對象時,目標對象中的屬性會根據類型在整個spring環境中查找<bean>標籤的class屬性值。若是有相同的,那麼獲取這個對象,實現關聯。 缺點:若是存在多個相同類型的bean對象,會出錯。 若是屬性爲單一類型的數據,那麼查找到多個關聯對象會發生錯誤。 若是屬性爲數組或集合(泛型)類型,那麼查找到多個關聯對象不會發生異常。 三、constructor(3.x以上已不能用) 使用構造方法完成對象注入,其實也是根據構造方法的參數類型進行對象查找,至關於採用byType的方式。若是沒找到則拋出異常 4、autodetect 自動選擇:若是對象沒有無參數的構造方法,那麼自動選擇constructor的自動裝配方式進行構造注入。若是對象含有無參數的構造方法,那麼自動選擇byType的自動裝配方式進行setter注入。 5、no 默認狀況下,不自動裝配,經過「ref」attribute手動設定。 <bean>標籤的 autowire 屬性,它負責自動裝配<bean>標籤訂義 JavaBean 的屬性。這樣作能夠省去不少配置 JavaBean 屬性的標籤代碼,使代碼整潔、美觀。可是它也有負面影響,即便用自動裝配以後,沒法從配置文件中讀懂 JavaBean 須要什麼屬性。自動裝配存在不少不正確的裝配問題,例如錯誤裝載屬性、「byType」屬性和「constructor」屬性對相同類型參數沒法判斷等。固然,將自動裝配和手動裝配混合使用也能解決此問題 Spring引用關聯 <bean id=」名稱」 class=」完整類」 scope=」singleton/prototype」> <property name=」完整類中的set方法名變量名」 value=」值」 /> <property name=」完整類中的set方法名變量名」 ref=」引用SpringBean對象」 /> </bean> 10、Spring 註解配置 修飾類用的 @Component 能夠修飾全部類上面,如DaoImpl,ServiceImpl,Controller上面(通常用在Util,POJO) @Repository 修飾Dao @Service 修飾Service @Controller 修飾控制器 若是修用了註解,必須在applicationContext.xml中去配置掃包 <context:component-scan base-package="com.wisezone.dao,com.wisezone.service,com.wisezone.controller"> </context:component-scan> 11、Spring aop 專業名稱 1)、鏈接點(JoinPoint) 觸發點 (類初始化前,類初始化後, 方法調用前,方法調用後, 異常) 2)、切點 (pointCut) 哪些具體方法 3)、加強 (advice) 在方法 基礎上,去擴展額外的功能(不修改之前類) 加強Spring有幾個定位接口: BeforeAdvice(方法執行前)、 AfterReturningAdvice(方法返回以後)、 ThrowsAdvice(異常) 4)、目標對象 (Target) 實際業務邏輯類 5)、引介 (introduction) 引介是一種特殊的加強,它爲類添加一些屬性和方法,這樣,即便一個業務類本來沒有實現某個接口,經過AOP的引介功能,咱們能夠動態的爲該業務添加接口的實現邏輯,讓業務類成爲這個接口的實現類 6)、織入 (Waving) 織入是將加強添加對目標可具體鏈接點上的過程,AOP像一臺織布機,將目標類、加強或者引介經過AOP這臺織布機完美無缺的編織到一塊兒。根據不一樣的實現技術,AOP有三種織入的方式: (1)編譯時:當一個類文件被編譯時進行織入,這須要特殊的編譯器才能夠作的到,例如AspectJ的織入編譯器 (2)類加載時:使用特殊的ClassLoader在目標類被加載到程序以前加強類的字節代碼 (3)運行時:切面在運行的某個時刻被織入,SpringAOP就是以這種方式織入切面的,原理應該是使用了JDK的動態代理技術 Spring採用動態代理織入,而AspectJ採用編譯期織入和類裝載期織入 7)、代理(Proxy) 一個類被AOP織入加強後,就產生出一個結果類,它是融合了原類和加強邏輯的代理類。根據不一樣的代理方式,代理類即有可能時和原類具備相同接口的類,也可能就是原類的子類,因此咱們能夠採用調用原類相同的方式調用代理類 8)、切面(Aspect) 切面由切點和加強(引介)組成,它既包括了橫切邏輯的定義,也包括了鏈接點的定義,SpringAOP就是負責實施切面的框架,它將切面所定義的橫切邏輯織入到切面所指定的鏈接點中 9)、Spring支持5種類型的加強: 1.前置加強:org.springframework.aop.BeforeAdvice表明前置加強,由於Spring只支持 方法級的加強,因此MethodBeforeAdvice是目前可的的前置加強,表示在目標方法執行前 實施加強,而BeforeAdvice是爲了未來版本擴展須要而定義的; 2.後置加強:org.springframework.aop.AfterReturningAdvice表明後加強,表示在目標 方法執行後實施加強; 3.環繞加強:org.aopalliance.intercept.MethodInterceptor表明環繞加強,表示在目標 方法執行先後實施加強; 4:異常拋出加強:org.springframework.aop.ThrowsAdvice表明拋出異常加強,表示在目 標方法拋出異常後實施加強; 5.引介加強:org.springframework.aop.InteoductionInterceptor表明引介加強,表示在 目標類中添加一些新的方法和屬性; 這些加強接口都有一些方法,經過實現這些接口方法,在接口方法中這義橫切邏輯,就能夠將它們織入到目標類的方法的相應鏈接點的位置。 12、使用配置進行AOP代理設定 <bean id="people" class="exp1.ChinesePeople"></bean> <!-- 再配一個加強 --> <bean id="myAdvice" class="exp1.BeforeAdviceDemo"></bean> <!-- 使用Spring代理工廠產生一個代理對象 --> <bean id="sayHello" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 生成代理接口 --> <property name="proxyInterfaces" value="exp1.SayHello"></property> <property name="interceptorNames" value="myAdvice"></property> <property name="target" ref="people"></property> <!-- 變爲子類 --> <property name="proxyTargetClass" value="false"></property> </bean> <property name="proxyTargetClass" value="true"></property> 生成ChinesePeolple子類 <property name="proxyTargetClass" value="false"></property> JDK動態代理,徹底不是Sayhello這個類相關的東西 13、Spring AOP execution()是最經常使用的切點函數,其語法以下圖所示: execution(<修飾符模式>?<返回類型模式><方法名模式>(<參數模式>)<異常模式>?) execution(* com.xxxx.service..(..) ) 經過方法簽名定義切點 execution(public * *(..)) 匹配全部目標類的public方法,可是不匹配Samartseller和protected void showGoods()方法。第一個*表明返回值;第二個*表明方法名;而..表明任意入參的方法 execution(* *To(..)) 匹配目標類全部以To爲後綴的方法。他匹配Naïve Waiter和NaughtyWaiter的greetTo()和serveTo()方法。第一個*表明返回類型,而*To表明任意以To爲後綴的方法 經過類定義切點 execution(*com.xxxx.Waiter.*(..)) 匹配Waiter接口的全部方法,它匹配NaiveWaiter和NaughtyWaiter類的greetTo()和serveTo方法。第一個*表明返回任意類型,com.xxxx.Waiter.*表明Waiter接口中的全部方法 經過類包定義切點 在類名模式串中,以「.*」表示包下的全部類,而「..*」表示包,子孫包下的全部類 execution(* com.xxxx.*(..)) 匹配com.xxxxx包下的全部類的全部方法 execution(* com.xxxx..*(..)) 匹配com.xxxx包、子孫包下全部類的全部方法,如com.xxxxx.dao、com.xxxxx.service以及com.xxxxx.user包下的全部類的全部方法都匹配,「..」出如今類名中時,後面必須跟「*」表示包、子孫包下的全部類 14、類加載器classLoader工做機制 類加載器就是尋找類或接口字節碼文件進行解析並構造JVM內部對象表示的組件。在Java中,類轉載器把一個類裝入JVM中,須要通過如下步驟: 1.裝載:查找和導入Class文件; 2.連接: 執行校驗、準備和解析步驟,其中解析步驟是能夠選擇的: a)校驗: 檢查載入Class文件數據的正確性; b)準備:給類的靜態變量分配存儲空間; c)解析:將符號引用變成直接引用; 3.初始化:對類的靜態變量、靜態代碼塊進行初始化工做。 類裝載工做是由ClassLoader及其之類負責的,ClassLoader是一個重要的Java運行時系統組件,它負責在運行時查找和裝入Class字節文件。JVM在運行時會產生三個ClassLoader:跟裝載器、ExtClassLoader(擴展類裝載器)和AppClassLoader(系統類裝載器)。其中,跟裝載器不是ClassLoader的子類,它使用C++編寫,所以咱們在Java中看不到它,跟裝載器負責裝載JRE的核心類庫,如rt.jar,charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子類。其中ExtClassLoader負責裝載JRE擴展目錄ext中的JAR類包;AppClassLoader負責裝載ClassPath路徑下的類包。 這三個類裝載器之間存在父子層級關係,跟裝載器是ExtClassLoader的父裝載器,ExtClassLoader是AppClassLoader的父裝載器。 15、經過AspectJ動態配置AOP import org.aspectj.lang.JoinPoint; //花費時間AOP public class SpeendAspectj { private long startTime; private long endTime; // 開始時候 public void begin(JoinPoint jp) { System.out.println("--Spring AOP監聽時間開始了-----"); this.startTime=System.currentTimeMillis(); } // 方法返回之後 public void end(JoinPoint jp, Object returnValue) { this.endTime=System.currentTimeMillis(); System.out.println(jp.getTarget() + "中的" + jp.getSignature().getName() + "的方法總共花費 了:"+(endTime-startTime)+"毫秒"); } } import org.aspectj.lang.JoinPoint; public class LogAspectj { //開始時候 public void begin(JoinPoint jp){ System.out.println("--Spring AOP切面開始了-----"); System.out.println(jp.getTarget()+"中的"+jp.getSignature().getName()+"的方法"); } //方法返回之後 public void end(JoinPoint jp, Object returnValue){ System.out.println("方法執完了返回的結果是:"+returnValue); System.out.println("-----------------------------------------"); } } <!-- aop切面配置 --> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.wisezone.service..*(..))" id="myPointCut" /> <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" /> <!-- 監聽日誌 --> <aop:aspect ref="log"> <aop:before method="begin" pointcut-ref="myPointCut"/> <aop:after-returning method="end" returning="returnValue" pointcut-ref="myPointCut"/> </aop:aspect> <!-- 花費時間 --> <aop:aspect ref="speedTime"> <aop:before method="begin" pointcut="execution(* com.wisezone.controller.admin..*(..))"/> <aop:after-returning method="end" returning="returnValue" pointcut="execution(* com.wisezone.controller.admin..*(..))" /> </aop:aspect> </aop:config>