-
若是一個接口有2個不一樣的實現, 如何Autowire某一個指定的實現?
一、經過增長@Qualifier(實現類的名字):前端
@Autowired @Qualifier("GirlStudentImpl") private Student student;
二、也能夠經過@Resource(name=」*「)裝配,則編程更加簡潔:java
@Resource(name="GirlStudentImpl") private Student student;
-
Spring註解(annotation-driven和annotation-config)的區別
若是你想使用@Autowired註解,那麼就必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。傳統聲明方式以下
<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
若是想使用@ Resource 、@ PostConstruct、@ PreDestroy等註解就必須聲明CommonAnnotationBeanPostProcessor
若是想使用@PersistenceContext註解,就必須聲明PersistenceAnnotationBeanPostProcessor的Bean。
若是想使用 @Required的註解,就必須聲明RequiredAnnotationBeanPostProcessor的Bean。一樣,傳統的聲明方式以下:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
通常來講,這些註解咱們仍是比較經常使用,尤爲是Antowired的註解,在自動注入的時候更是常用,因此若是老是須要按照傳統的方式一條一條配置顯得有些繁瑣和沒有必要,因而spring給咱們提供<context:annotation-config/>的簡化配置方式,自動幫你完成聲明。啓動註解裝配算法
不過,咱們使用註解通常都會配置掃描包路徑選項spring
<context:component-scan base-package=」XX.XX」/>
該配置項其實也包含了自動注入上述processor的功能,所以當使用 <context:component-scan/> 後,就能夠將 <context:annotation-config/> 移除了sql
<mvc:annotation-driven/>
至關於註冊了DefaultAnnotationHandlerMapping①和AnnotationMethodHandlerAdapter兩個bean,配置一些messageconverter。即解決了@Controller註解的使用前提配置。並提供了:數據綁定支持,@NumberFormatannotation支持,@DateTimeFormat支持, @Valid支持,讀寫XML的支持(JAXB),讀寫JSON的支持(Jackson)。數據庫
-
@Component, @Controller, @Repository, @Service 有何區別?
-
@Component:這將 java 類標記爲 bean。它是任何 Spring 管理組件的通用構造型。spring 的組件掃描機制如今能夠將其拾取並將其拉入應用程序環境中。express
-
@Controller:這將一個類標記爲 Spring Web MVC 控制器。標有它的 Bean 會自動導入到 IoC 容器中。編程
-
@Service:此註解是組件註解的特化。它不會對 @Component 註解提供任何其餘行爲。您能夠在服務層類中使用 @Service 而不是 @Component,由於它以更好的方式指定了意圖。json
-
@Repository:這個註解是具備相似用途和功能的 @Component 註解的特化。它爲 DAO 提供了額外的好處。它將 DAO 導入 IoC 容器,並使未經檢查的異常有資格轉換爲 Spring DataAccessException,在註解了
@Repository
的類上若是數據庫操做中拋出了異常,就能對其進行處理,轉而拋出的是翻譯後的spring專屬數據庫異常,方便咱們對異常進行排查處理。設計模式
-
-
@RequestParam 和 @PathVariable @RequestBody 以及不加的區別?
@RequestParam
@RequestParam
是 獲取請求參數的值,也就是 ?
後面的那些值 ,也能夠是post請求中參數的值
請求路徑:http://www.test.com/user/query?username=zhangsan&age=20
請求參數:username=zhangsan&age=20
@RequestMapping(value = "/user/query")
public String query(@RequestParam(value="username") String username) {
System.out.println("username = " + username); //此處打印:username = zhangsan
return SUCCESS;
}
經過@RequestParam 獲取 不一樣請求對應的值:
.../query?username=zhangsan 獲取 username 等於 zhangsan
.../query?username= 獲取 username==""
.../query 獲取 username==null
@RequestParam 默認必傳的,不能爲null
如上面例子,請求路徑是 http://www.test.com/user/query?age=20 ,程序必定會報錯的,
若是username不傳時, 就是null ,而 @RequestParam 默認是必傳的。
解決方法是
第1種: 請求路徑改成 http://www.test.com/user/query?username=&age=20 表示 username=="",不爲null;
第2種: required=false,具體以下:
@RequestParam(value="username",required=false) String username
@PathVariable
@PathVariable
是 處理 URL 中的參數值
URL 中的 { xxx } 佔位符能夠經過 @PathVariable("xxx") 綁定到操做方法的入參中。
請求路徑 : http://www.test.com/user/031267/view?username=zhangsan&age=20
請求URL : http://www.test.com/user/031267/view
@RequestMapping(value = "/user/{userid}/view") //佔位符 userid
public String view ( @PathVariable("userid") String userid){ //@PathVariable 中指定 userid
System.out.println("userid= "+userid); //此處能夠獲取:userid= 031267
return SUCCESS;
}
帶佔位符的URL 是Spring3.0 新增的功能,該功能在SpringMVC 向REST目標挺進發展過程當中具備里程碑的意義。
@RequestBody
@RequestBody的做用實際上是將json格式的數據轉爲java對象,能夠省去咱們在後臺將json轉成java對象
-
BeanFactory和ApplicationContext以及FactoryBean的區別?
BeanFacotry是spring中比較原始的Factory。如XMLBeanFactory就是一種典型的BeanFactory。原始的BeanFactory沒法支持spring的許多插件,如AOP功能、Web應用等。
ApplicationContext接口,它由BeanFactory接口派生而來,ApplicationContext包含BeanFactory的全部功能,一般建議比BeanFactory優先
BeanFactory是個Factory,也就是IOC容器或對象工廠,FactoryBean是個Bean,二者都是接口。在Spring中,全部的Bean都是由BeanFactory(也就是IOC容器)來進行管理的。但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式相似。不一樣於普通Bean的是:若是一個Bean實現了FactoryBean<T>接口,根據該Bean的ID從BeanFactory中獲取的其實是FactoryBean的getObject()返回的對象,而不是FactoryBean自己,若是要獲取FactoryBean對象,請在id前面加一個&符號來獲取②。
-
Spring Bean 的做用域?
當scope=」prototype」時,容器會延遲初始化bean(若是一個bean的scope屬性爲scope="pototype"時,即便設置了lazy-init="false"也會延遲),Spring讀取xml文件的時候,並不會馬上建立對象,而是在第一次請求該bean時才初始化(如調用getBean方法時),所以談及prototype做用域的bean時,在某些方面能夠將Spring容器的角色看做是Java new操做的替代者,任何遲於該時間點的生命週期事宜都得交由客戶端來處理。
Spring容器能夠管理singleton做用域下bean的生命週期,在此做用域下,Spring可以精確地知道bean什麼時候被建立,什麼時候初始化完成,以及什麼時候被銷燬。而對於prototype做用域的bean,Spring只負責建立,當容器建立了bean的實例後,bean的實例就交給了客戶端的代碼管理,Spring容器將再也不跟蹤其生命週期,而且不會管理那些被配置成prototype做用域的bean的生命週期。
-
SpringMVC的控制器是否是單例模式,若是是,有什麼問題,怎麼解決?
Spring MVC默認是Singleton的,因此會產生一個潛在的安全隱患。根本核心是instance變量保持狀態的問題。這意味着每一個request過來,系統都會用原有的instance去處理,這樣致使了兩個結果:
一是咱們不用每次建立Controller,
二是減小了對象建立和垃圾收集的時間;
因爲只有一個Controller的instance,當多個線程同時調用它的時候,它裏面的instance變量就不是線程安全的了,會發生竄數據的問題。
固然大多數狀況下,咱們根本不須要考慮線程安全的問題,好比dao,service等,除非在bean中聲明瞭實例變量。所以,咱們在使用spring mvc 的contrller時:
- 應避免在controller中定義實例變量。
- 或者將控制器的做用域從單例改成原型,即在spring配置文件Controller中聲明 scope="prototype",每次都建立新的controller
- 在Controller中使用ThreadLocal變量
-
Spring MVC的五大組鍵 ?
-
前端控制器 (DispatcherServlet)
-
映射處理器(HandlerMapping)
-
處理器(Controller)
-
模型和視圖(ModelAndView)
-
視圖解析器(ViewResolver)
文字解析: 客戶端請求提交到DispatcherServlet 由DispatcherServlet控制器查詢一個或多個HandlerMapping,找處處理請求的Controller DispatcherServlet將請求提交到Controller Controller調用業務邏輯處理後,返回ModelAndView DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖 視圖負責將結果顯示到客戶
-
spring中的設計模式?
spring中經常使用的設計模式爲:
單例模式(Singleton):保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
spring中的單例模式完成了後半句話,即提供了全局的訪問點BeanFactory。但沒有從構造器級別去控制單例,這是由於spring管理的是是任意的java對象。
核心提示點:Spring下默認的bean均爲singleton,能夠經過singleton=「true|false」 或者 scope=「?」來指定
代理(Proxy):在Spring的Aop中,使用的Advice(通知)來加強被代理類的功能。Spring實現這一AOP功能的原理就使用代理模式(一、JDK動態代理。二、CGLib字節碼生成技術代理。)對類進行方法級別的切面加強,即,生成被代理類的代理類, 並在代理類的方法前,設置攔截器,經過執行攔截器重的內容加強了代理方法的功能,實現的面向切面編程。
模板方法(Template Method):定義一個操做中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。
Template Method模式通常是須要繼承的。這裏想要探討另外一種對Template Method的理解。spring中的JdbcTemplate,在用這個類時並不想去繼承這個類,由於這個類的方法太多,可是咱們仍是想用到JdbcTemplate已有的穩定的、公用的數據庫鏈接,那麼咱們怎麼辦呢?咱們能夠把變化的東西抽出來做爲一個參數傳入JdbcTemplate的方法中。可是變化的東西是一段代碼,並且這段代碼會用到JdbcTemplate中的變量。怎麼辦?那咱們就用回調對象吧。在這個回調對象中定義一個操縱JdbcTemplate中變量的方法,咱們去實現這個方法,就把變化的東西集中到這裏了。而後咱們再傳入這個回調對象到JdbcTemplate,從而完成了調用。這多是Template Method不須要繼承的另外一種實現方式吧。
工廠方法(Factory Method):一般由應用程序直接使用new建立新的對象,爲了將對象的建立和使用相分離,採用工廠模式,即應用程序將對象的建立及初始化職責交給工廠對象。
-
常見的三種注入方式?
1:field注入 @Controller public class FooController { @Autowired //@Inject private FooService fooService; //簡單的使用例子,下同 public List<Foo> listFoo() { return fooService.list(); } //承接上面field注入的代碼,假如客戶端代碼使用下面的調用(或者再Junit測試中使用) //這裏只是模擬一下,正常來講咱們只會暴露接口給客戶端,不會暴露實現。 FooController fooController = new FooController(); fooController.listFoo(); // -> NullPointerException } 缺點顯而易見,對於IOC容器之外的環境,除了使用反射來提供它須要的依賴以外,沒法複用該實現類。並且將一直是個潛在的隱患,由於你不調用將一直沒法發現NPE的存在。 2: 構造器注入 推薦 @Controller public class FooController { private final FooService fooService; @Autowired public FooController(FooService fooService) { this.fooService = fooService; } //使用方式上同,略 } 3:setter注入 @Controller public class FooController { private FooService fooService; //使用方式上同,略 @Autowired public void setFooService(FooService fooService) { this.fooService = fooService; } }
-
spring的4種事務特性,5種隔離級別,7種傳播行爲?
4種特性:
(1)原子性
事務必須是原子工做單元;對於其數據修改,要麼全都執行,要麼全都不執行。
(2)一致性
事務的一致性指的是在一個事務執行以前和執行以後數據庫都必須處於一致性狀態。事務執行的結果必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。
(3) 隔離性(關於事務的隔離性數據庫提供了多種隔離級別)
一個事務的執行不能干擾其它事務。即一個事務內部的操做及使用的數據對其它併發事務是隔離的,併發執行的各個事務之間不能互相干擾。
(4)持久性
事務完成以後,它對於數據庫中的數據改變是永久性的。該修改即便出現系統故障也將一直保持。
併發下事務會產生的問題
舉個例子,事務A和事務B操縱的是同一個資源,事務A有若干個子事務,事務B也有若干個子事務,事務A和事務B在高併發的狀況下,會出現各類各樣的問題。"各類各樣的問題",總結一下主要就是五種:第一類丟失更新、第二類丟失更新、髒讀、不可重複讀、幻讀。五種之中,第一類丟失更新、第二類丟失更新不重要,不講了,講一下髒讀、不可重複讀和幻讀。
一、髒讀
所謂髒讀,就是指事務A讀到了事務B尚未提交的數據,好比銀行取錢,事務A開啓事務,此時切換到事務B,事務B開啓事務-->取走100元,此時切換回事務A,事務A讀取的確定是數據庫裏面的原始數據,由於事務B取走了100塊錢,並無提交,數據庫裏面的帳務餘額確定仍是原始餘額,這就是髒讀。
二、不可重複讀
所謂不可重複讀,就是指在一個事務裏面讀取了兩次某個數據,讀出來的數據不一致。仍是以銀行取錢爲例,事務A開啓事務-->查出銀行卡餘額爲1000元,此時切換到事務B事務B開啓事務-->事務B取走100元-->提交,數據庫裏面餘額變爲900元,此時切換回事務A,事務A再查一次查出帳戶餘額爲900元,這樣對事務A而言,在同一個事務內兩次讀取帳戶餘額數據不一致,這就是不可重複讀。
三、幻讀
所謂幻讀,就是指在一個事務裏面的操做中發現了未被操做的數據。好比學生信息,事務A開啓事務-->修改全部學生當天簽到情況爲false,此時切換到事務B,事務B開啓事務-->事務B插入了一條學生數據,此時切換回事務A,事務A提交的時候發現了一條本身沒有修改過的數據,這就是幻讀,就好像發生了幻覺同樣。幻讀出現的前提是併發的事務中有事務發生了插入、刪除操做。
5種隔離級別:
- DEFAULT 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別. (Mysql 默認:可重複讀 Oracle 默認:讀已提交)
- read uncommited:是最低的事務隔離級別,它容許另一個事務能夠看到這個事務未提交的數據。
- read commited:保證一個事物提交後才能被另一個事務讀取。另一個事務不能讀取該事物未提交的數據。
- repeatable read:這種事務隔離級別能夠防止髒讀,不可重複讀。可是可能會出現幻象讀。它除了保證一個事務不能被另一個事務讀取未提交的數據以外還避免瞭如下狀況產生(不可重複讀)。
- serializable:這是花費最高代價但最可靠的事務隔離級別。事務被處理爲順序執行。除了防止髒讀,不可重複讀以外,還避免了幻象讀(避免三種)。
@Transactional(isolation=Isolation.DEFAULT) public void method(){}
7種傳播行爲:
支持當前事務的狀況:
-
TransactionDefinition.PROPAGATION_REQUIRED: 若是當前存在事務,則加入該事務;若是當前沒有事務,則建立一個新的事務。
-
TransactionDefinition.PROPAGATION_SUPPORTS: 若是當前存在事務,則加入該事務;若是當前沒有事務,則以非事務的方式繼續運行。
-
TransactionDefinition.PROPAGATION_MANDATORY: 若是當前存在事務,則加入該事務;若是當前沒有事務,則拋出異常。(mandatory:強制性)
不支持當前事務的狀況:
-
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 建立一個新的事務,若是當前存在事務,則把當前事務掛起。
-
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式運行,若是當前存在事務,則把當前事務掛起。
-
TransactionDefinition.PROPAGATION_NEVER: 以非事務方式運行,若是當前存在事務,則拋出異常。
其餘狀況:
- TransactionDefinition.PROPAGATION_NESTED: 若是當前存在事務,則建立一個事務做爲當前事務的嵌套事務來運行;若是當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
掛起的解讀:
例如 方法A支持事務
方法B不支持事務。
方法A調用方法B。
在方法A開始運行時,系統爲它創建Transaction,方法A中對於數據庫的處理操做,會在該Transaction的控制之下。
這時,方法A調用方法B,方法A打開的 Transaction將掛起,方法B中任何數據庫操做,都不在該Transaction的管理之下。
當方法B返回,方法A繼續運行,以前的Transaction恢復,後面的數據庫操做繼續在該Transaction的控制之下 提交或回滾。
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於:
PROPAGATION_REQUIRES_NEW 徹底是一個新的事務, 而 PROPAGATION_NESTED
則是外部事務的子事務, 若是外部事務 commit, 潛套事務也會被 commit,
這個規則一樣適用於 roll back. 並且嵌套事務最有價值的點在於
ServiceA { /** * 事務屬性配置爲 PROPAGATION_REQUIRED */ void methodA() { try { ServiceB.methodB(); } catch (SomeException) { // 執行其餘業務, 如 ServiceC.methodC(); } } }
嵌套事務最有價值的地方, 它起到了分支執行的效果, 若是 ServiceB.methodB 失敗, 那麼執行 ServiceC.methodC(), 而 ServiceB.methodB 已經回滾到它執行以前的 SavePoint, 因此不會產生髒數據(至關於此方法從未執行過), 這種特性能夠用在某些特殊的業務中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都沒有辦法作到這一點. (題外話 : 看到這種代碼, 彷佛似曾相識, 想起了 prototype.js 中的 Try 函數 )
-
Spring事務和hibernate事務的區別?
對於傳統的基於特定事務資源的事務處理而言(如基於JDBC的數據庫訪問),Spring並不會對其產生什麼影響,咱們照樣能夠成功編寫並運行這樣的代碼。同時,Spring還提供了一些輔助類可供咱們選擇使用,這些輔助類簡化了傳統的數據庫操做流程,在必定程度上節省了工做量,提升了編碼效率。
對於依賴容器的參數化事務管理而言,Spring則表現出了極大的價值。Spring自己也是一個容器,只是相對EJB容器而言,Spring顯得更爲輕便小巧。咱們無需付出其餘方面的代價,便可經過Spring實現基於容器的事務管理(本質上來說,Spring的事務管理是基於動態AOP)。
hibernate事務:
hibernate是JDBC的輕量級對象封裝,hibernate自己不具有Transaction處理功能,Hibernate的Transaction其實是JDBC的Transaction封裝或者JTATransaction的封裝.具體分析以下:
Hibernate Transaction能夠配置JDBCTransaction或者JTATransaction這取決與你在Hibernate.properties中的配置
Hibernate的事務是對底層數據庫的JDBC/JTA等的封裝 Spring則是對Hibernate等事務的封裝
-
Spring IOC的初始化過程?
-
Spring MVC配置中的總結?
在不少配置中通常都會吧Spring-common.xml和Spring-MVC.xml進行分開配置,這種配置就行各施其職同樣,顯得特別清晰。
在Spring-MVC.xml中只對@Controller進行掃描就可,做爲一個控制器,其餘的事情不作。
在Spring-common.xml中只對一些事務邏輯的註解掃描。
(1)在Spring-MVC.xml中有如下配置:
<!-- 掃描@Controller註解 --> <context:component-scan base-package="com.xx.controller"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
能夠看出要把最終的包寫上,而不能這樣寫base-package=」com.xx」。這種寫法對於include-filter來說它都會掃描,而不是僅僅掃描@Controller。
(2)在Spring-common.xml中有以下配置:
<!-- 配置掃描註解,不掃描@Controller註解 --> <context:component-scan base-package="com.xx"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
能夠看到,這是要掃描com.xx包下的全部子類,不包含@Controller。
註釋一:Spring2.5引入註解式處理器支持,經過@Controller 和 @RequestMapping註解定義咱們的處理器類。而且提供了一組強大的註解:
須要經過處理器映射DefaultAnnotationHandlerMapping和處理器適配器AnnotationMethodHandlerAdapter來開啓支持@Controller 和 @RequestMapping註解的處理器。
Spring 3.0.x中使用了mvc:annotation-driven後,默認會幫咱們註冊默認處理請求,參數和返回值的類,其中最主要的兩個類:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分別爲HandlerMapping的實現類和HandlerAdapter的實現類,從3.1.x版本開始對應實現類改成了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
註解二:舉例,FactoryBean接口以下:
public interface FactoryBean<T> { T getObject() throws Exception; Class<?> getObjectType(); boolean isSingleton(); }
咱們有個Person對象,裏面包含 name,address,age。set、get方法不寫了
public class Person {
private String name;
private String address;
private int age;
}
那麼若是咱們要在Spring中配置該對象的話,須要這麼配置:
<bean id="personBean" class="com.xx.Person">
<property name="name" value="lulu" />
<property name="address" value="address1" />
<property name="age" value="24" />
</bean>
那麼如今咱們能夠經過getBean("personBean")來獲取該對象。那麼咱們來看下若是經過實現FactoryBean之後該怎麼寫呢?來看下咱們的PersonFactoryBean的代碼:
public class PersonFactoryBean implements FactoryBean<Person>{
private String personInfo;
public Person getObject() throws Exception {
Person person = new Person () ;
String [] infos = personInfo.split ( "," ) ;
person.setName(infos[0]);
person.setAddress(infos[1]);
person.setAge(Integer.parseInt(infos[2]));
return person;
}
public Class<Person> getObjectType() {
return Person.class;
}
public boolean isSingleton() {
return true;
}
}
咱們看到,這裏PersonFactoryBean實現了FactoryBean接口,那麼天然也要實現它定義的方法。這裏咱們是經過一個personInfo字符串解析獲得Person對象,那麼咱們在配置Spring的時候就能夠這麼配置:
<bean id="personFactory" class="com.xx.PersonFactory">
<property name="personInfo" value="king,address2,24"></property>
</bean>
OK,那麼這個時候咱們getBean("personFactory")獲得的就是Person對象而不是PersonFactoryBean對象。具體調用到了getObject方法,因此結果很明顯。context.getBean("&personFactory")則爲PersonFactoryBean對象