Spring經典高頻面試題,原來是長這個樣子

Spring經典高頻面試題,原來是長這個樣子

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: http://www.javashuo.com/article/p-qhmifvnc-dx.html

本文選自《Spring 5核心原理與30個類手寫實戰》一書,文末參與互動有機會贏取本書。本文題目目錄:javascript

1  什麼是Spring框架,Spring框架有哪些主要模塊css

2  使用Spring框架能帶來哪些好處html

3  什麼是控制反轉(IoC),什麼是依賴注入前端

4  在Java中依賴注入有哪些方式java

5  BeanFactory和ApplicationContext有什麼區別python

6  Spring提供幾種配置方式來設置元數據web

7  如何使用XML配置方式配置Spring面試

8  Spring提供哪些配置形式算法

9  怎樣用註解的方式配置Springspring

10  請解釋Spring Bean的生命週期

11  更多經典高頻面試題

1  什麼是Spring框架,Spring框架有哪些主要模塊

Spring框架是一個爲Java應用程序開發提供綜合、普遍的基礎性支持的Java平臺。Spring幫助開發者解決了開發中基礎性的問題,使得開發人員能夠專一於應用程序的開發。Spring框架自己也是按照設計模式精心打造的,這使得咱們能夠在開發環境中安心地集成Spring框架,沒必要擔憂Spring是如何在後臺工做的。

 

2  使用Spring框架能帶來哪些好處

下面列舉了一些使用Spring框架帶來的主要好處。

(1)Dependency Injection(DI)使得構造器和JavaBean properties文件中的依賴關係一目瞭然。

(2)與EJB容器相比較,IoC容器更加趨向於輕量級。這樣一來使用IoC容器在有限的內存和CPU資源的狀況下進行應用程序的開發和發佈就變得十分有利。

(3)Spring並無閉門造車,Spring利用了已有的技術,好比ORM框架、logging框架、J2EE、Quartz和JDK Timer,以及其餘視圖技術。

(4)Spring框架是按照模塊的形式來組織的。由包和類的編號就能夠看出其所屬的模塊,開發者只需選用須要的模塊便可。

(5)要測試一個用Spring開發的應用程序十分簡單,由於測試相關的環境代碼都已經囊括在框架中了。更加簡單的是,利用JavaBean形式的POJO類,能夠很方便地利用依賴注入來寫入測試數據。

(6)Spring的Web框架也是一個精心設計的Web MVC框架,爲開發者在Web框架的選擇上提供了一個除主流框架(好比Struts)和過分設計的、不流行Web框架之外的選擇。

(7)Spring提供了一個便捷的事務管理接口,適用於小型的本地事務處理(好比在單DB的環境下)和複雜的共同事務處理(好比利用JTA的複雜DB環境)。

 

3  什麼是控制反轉(IoC),什麼是依賴注入

(1)控制反轉是應用於軟件工程領域的,在運行時被裝配器對象用來綁定耦合對象的一種編程技巧,對象之間的耦合關係在編譯時一般是未知的。在傳統的編程方式中,業務邏輯的流程是由應用程序中早已被設定好關聯關係的對象來決定的。在使用控制反轉的狀況下,業務邏輯的流程是由對象關係圖來決定的,該對象關係圖由裝配器負責實例化,這種實現方式還能夠將對象之間的關聯關係的定義抽象化。綁定的過程是經過「依賴注入」實現的。

(2)控制反轉是一種以給予應用程序中目標組件更多控制爲目的設計範式,並在實際工做中起到了有效的做用。

(3)依賴注入是在編譯階段還沒有知所需的功能是來自哪一個的類的狀況下,將其餘對象所依賴的功能對象實例化的模式。這就須要一種機制來激活相應的組件以提供特定的功能,因此依賴注入是控制反轉的基礎。不然若是在組件不受框架控制的狀況下,框架又怎麼知道要建立哪一個組件呢?

 

4  在Java中依賴注入有哪些方式

(1)構造器注入。

(2)Setter方法注入。

(3)接口注入。

 

5  BeanFactory和ApplicationContext有什麼區別

BeanFactory 能夠理解爲含有Bean集合的工廠類。BeanFactory 包含了Bean的定義,以便在接收到客戶端請求時將對應的Bean實例化。

BeanFactory還能在實例化對象時生成協做類之間的關係。此舉將Bean自身從Bean客戶端的配置中解放出來。BeanFactory還包含Bean生命週期的控制,調用客戶端的初始化方法(Initialization Method)和銷燬方法(Destruction Method)。

從表面上看,ApplicationContext如同BeanFactory同樣具備Bean定義、Bean關聯關係的設置及根據請求分發Bean的功能。但ApplicationContext在此基礎上還提供了其餘功能。

(1)提供了支持國際化的文本消息。

(2)統一的資源文件讀取方式。

(3)已在監聽器中註冊的Bean的事件。

如下是三種較常見的 ApplicationContext 實現方式。

(1) ClassPathXmlApplicationContext: 從ClassPath的XML配置文件中讀取上下文,並生成上下文定義。應用程序上下文從程序環境變量中取得。 

  •  
ApplicationContext context = new ClassPathXmlApplicationContext(「application.xml」);

(2)FileSystemXmlApplicationContext :由文件系統中的XML配置文件讀取上下文。 

  •  
ApplicationContext context = new FileSystemXmlApplicationContext(「application.xml」);

(3)XmlWebApplicationContext:由Web應用的XML文件讀取上下文。

 

6  Spring提供幾種配置方式來設置元數據

Spring提供如下三種配置方式來設置元數據:

(1)基於XML的配置。

(2)基於註解的配置。

(3)基於Java的配置。

 

7  如何使用XML配置方式配置Spring

在Spring框架中,依賴和服務須要專門的配置文件實現,通常用XML格式的配置文件。這些配置文件的格式採用公共的模板,由一系列的Bean定義和專門的應用配置選項組成。 

Spring XML配置的主要目的是使全部的Spring組件均可以用XML文件的形式來進行配置。這意味着不會出現其餘的Spring配置類型(好比聲明配置方式或基於Java Class的配置方式)。

Spring的XML配置方式是使用被Spring命名空間所支持的一系列的XML標籤來實現的。Spring主要的命名空間有context、beans、jdbc、tx、aop、mvc和aso。例如:

<beans><!-- JSON Support --><bean name="viewResolver"class="org.springframework.web.servlet.view.BeanNameViewResolver"/><bean name="jsonTemplate"class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/><bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/></beans>

下面這個web.xml僅配置了DispatcherServlet,最簡單的配置便能知足應用程序配置運行時組件的需求。​​​​​​​

<web-app><display-name>Archetype Created Web Application</display-name><servlet><servlet-name>spring</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>spring</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>

8  Spring提供哪些配置形式

Spring對Java配置的支持是由@Configuration註解和@Bean註解來實現的。由@Bean註解的方法將會實例化、配置和初始化一個新對象,這個對象將由Spring的IoC容器來管理。@Bean聲明所起到的做用與元素相似。被@Configuration所註解的類則表示這個類的主要目的是做爲Bean定義的資源。被@Configuration聲明的類能夠經過在同一個類內部調用@bean方法來設置嵌入Bean的依賴關係。

最簡單的@Configuration 聲明類請參考下面的代碼:​​​​​​​

@Configurationpublic class AppConfig{@Beanpublic MyService myService() {return new MyServiceImpl();}}

與上面的@Beans配置文件相同的XML配置文件以下:​​​​​​​

<beans><bean id="myService" class="com.gupaoedu.services.MyServiceImpl"/></beans>

上述配置方式的實例化方式以下:​​​​​​​

public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);MyService myService = ctx.getBean(MyService.class);myService.doStuff();}

要使用組件掃描,僅需用@Configuration進行註解便可:​​​​​​​

@Configuration@ComponentScan(basePackages = "com.gupaoedu")public class AppConfig {}

在上面的例子中,com.gupaoedu包首先會被掃描到,而後在容器內查找被@Component 聲明的類,找到後將這些類按照Spring Bean定義進行註冊。 

若是你要在Web應用開發中選用上述配置方式,須要用AnnotationConfigWebApplicationContext類來讀取配置文件,能夠用來配置Spring的Servlet監聽器ContrextLoaderListener或者Spring MVC的DispatcherServlet。

例如:​​​​​​​

<web-app><context-param><param-name>contextClass</param-name><param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value></context-param><context-param><param-name>contextConfigLocation</param-name><param-value>com.gupaoedu.AppConfig</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextClass</param-name><param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value></init-param><init-param><param-name>contextConfigLocation</param-name><param-value>com.gupaoedu.web.MVCConfig</param-value></init-param></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/web/*</url-pattern></servlet-mapping></web-app> 

9  怎樣用註解的方式配置Spring

Spring在2.5版本之後開始支持用註解的方式配置依賴注入。能夠用註解的方式來替代XML方式的Bean描述,能夠將Bean描述轉移到組件類的內部,只須要在相關類上、方法上或者字段聲明上使用註解便可。註解注入將會被容器在XML注入以前處理,因此後者會覆蓋前者對於同一個屬性的處理結果。

註解裝配在Spring中是默認關閉的,須要在Spring文件中進行配置才能使用基於註解的裝配模式。若是你想要在應用程序中使用註解的方式,請參考以下配置:​​​​​​​

<beans><context:annotation-config/></beans>

配置完成之後,就能夠用註解的方式在Spring中向屬性、方法和構造方法中自動裝配變量。

下面是幾種比較重要的註解類型。

(1)@Required:該註解應用於設值方法。 

(2)@Autowired:該註解應用於設值方法、非設值方法、構造方法和變量。 

(3)@Qualifier:該註解和@Autowired註解搭配使用,用於消除特定Bean自動裝配的歧義。 

(4)JSR-250 Annotations:Spring支持基於JSR-250 註解的註解,即@Resource、@PostConstruct和@PreDestroy。

10  請解釋Spring Bean的生命週期

Spring Bean的生命週期簡單易懂。在一個Bean實例被初始化時,須要執行一系列初始化操做以使其達到可用的狀態。一樣,當一個Bean再也不被調用時須要進行相關的析構操做,並從Bean容器中移除。

Spring Bean Factory 負責管理在Spring容器中被建立的Bean的生命週期。Bean的生命週期由兩組回調方法組成。 

(1)初始化以後調用的回調方法。 

(2)銷燬以前調用的回調方法。 

Spring提供瞭如下4種方式來管理Bean的生命週期事件:

(1)InitializingBean和DisposableBean回調接口。

(2)針對特殊行爲的其餘Aware接口。

(3)Bean配置文件中的 customInit() 方法和 customDestroy() 方法。

(4)@PostConstruct和@PreDestroy註解方式。

使用customInit()和 customDestroy()方法管理Bean生命週期的代碼樣例以下:​​​​​​​

<beans><bean id="demoBean" class="com.gupaoedu.task.DemoBean"init-Method="customInit" destroy-Method="customDestroy"></bean></beans>

更多經典高頻面試題

11  Spring Bean做用域的區別是什麼

12  什麼是Spring Inner Bean

13  Spring中的單例Bean是線程安全的嗎

14  請舉例說明如何在Spring中注入一個Java集合

15  如何向Spring Bean中注入java.util.Properties

16  請解釋Spring Bean的自動裝配

17  自動裝配有哪些侷限性

18  請解釋各類自動裝配模式的區別

19  請舉例解釋@Required註解

20  請舉例說明@Qualifier註解

21  構造方法注入和設值注入有什麼區別

22  Spring中有哪些不一樣類型的事件

23  FileSystemResource和ClassPathResource有什麼區別

24  Spring中用到了哪些設計模式

25  在Spring中如何更有效地使用JDBC

26  請解釋Spring中的IoC容器

27  在Spring中能夠注入null或空字符串嗎

 

 

Java框架經典面試題之Spring(內附答案) 

Spring 框架是一個開源的Java平臺,它爲容易而快速的開發出耐用的Java應用程序提供了全面的基礎設施。今天千鋒小編着重給你們總結了一些關於Spring框架的經典面試題,但願能助你們的面試一臂之力。

一、Spring框架中有哪些不一樣類型的事件?

Spring 提供瞭如下5中標準的事件:

  • 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時發佈。也能夠在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
  • 上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/從新開始容器時觸發該事件。
  • 上下文中止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法中止容器時觸發該事件。
  • 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的全部單例Bean都被銷燬。
  • 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

二、Spring 框架中都用到了哪些設計模型?

Spring框架中使用到了大量的設計模式,下面列舉了比較有表明性的:

  • 代理模式—在AOP和remoting中被用的比較多。
  • 單例模式—在spring配置文件中定義的bean默認爲單例模式。
  • 模板方法—用來解決代碼重複的問題。
  • 前端控制器—Srping提供了DispatcherServlet來對請求進行分發。
  • 視圖幫助(View Helper )—Spring提供了一系列的JSP標籤,高效宏來輔助將分散的代碼整合在視圖裏。
  • 依賴注入—貫穿於BeanFactory / ApplicationContext接口的核心理念。
  • 工廠模式—BeanFactory用來建立對象的實例。

三、使用Spring框架的好處是什麼?

  1. 輕量:Spring 是輕量的,基本的版本大約2MB。
  2. 控制反轉:Spring經過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是建立或查找依賴的對象們。
  3. 面向切面的編程(AOP):Spring支持面向切面的編程,而且把應用業務邏輯和系統服務分開。
  4. 容器:Spring 包含並管理應用中對象的生命週期和配置。
  5. MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
  6. 事務管理:Spring 提供一個持續的事務管理接口,能夠擴展到上至本地事務下至全局事務(JTA)。
  7. 異常處理:Spring 提供方便的API把具體技術相關的異常(好比由JDBC,Hibernate or JDO拋出的)轉化爲一致的unchecked 異常。

四、解釋Spring支持的幾種bean的做用域?

Spring框架支持如下五種bean的做用域:

  1. singleton : bean在每一個Spring ioc 容器中只有一個實例。
  2. prototype:一個bean的定義能夠有多個實例。
  3. request:每次http請求都會建立一個bean,該做用域僅在基於web的Spring ApplicationContext情形下有效。
  4. session:在一個HTTP Session中,一個bean定義對應一個實例。該做用域僅在基於web的Spring ApplicationContext情形下有效。
  5. global-session:在一個全局的HTTP Session中,一個bean定義對應一個實例。該做用域僅在基於web的Spring ApplicationContext情形下有效。

五、在 Spring中如何注入一個java集合?

Spring提供如下幾種集合的配置元素:

 

  • <list>類型用於注入一列值,容許有相同的值。
  • <set> 類型用於注入一組值,不容許有相同的值。
  • <map> 類型用於注入一組鍵值對,鍵和值均可覺得任意類型。
  • <props>類型用於注入一組鍵值對,鍵和值都只能爲String類型。

 

6.聊一聊 Spring 中的線程安全性

ImportNew. 2018-10-23 12:00
 
來源:SylvanasSun ,
juejin.im/post/5a0045ef5188254de169968e
Spring與線程安全
Spring做爲一個IOC/DI容器,幫助咱們管理了許許多多的「bean」。但其實,Spring並無保證這些對象的線程安全,須要由開發者本身編寫解決線程安全問題的代碼。
Spring對每一個bean提供了一個scope屬性來表示該bean的做用域。它是bean的生命週期。例如,一個scope爲singleton的bean,在第一次被注入時,會建立爲一個單例對象,該對象會一直被複用到應用結束。
咱們交由Spring管理的大多數對象其實都是一些無狀態的對象,這種不會由於多線程而致使狀態被破壞的對象很適合Spring的默認scope,每一個單例的無狀態對象都是線程安全的(也能夠說只要是無狀態的對象,無論單例多例都是線程安全的,不過單例畢竟節省了不斷建立對象與GC的開銷)。
無狀態的對象便是自身沒有狀態的對象,天然也就不會由於多個線程的交替調度而破壞自身狀態致使線程安全問題。無狀態對象包括咱們常用的DO、DTO、VO這些只做爲數據的實體模型的貧血對象,還有Service、DAO和Controller,這些對象並無本身的狀態,它們只是用來執行某些操做的。例如,每一個DAO提供的函數都只是對數據庫的CRUD,並且每一個數據庫Connection都做爲函數的局部變量(局部變量是在用戶棧中的,並且用戶棧自己就是線程私有的內存區域,因此不存在線程安全問題),用完即關(或交還給鏈接池)。
有人可能會認爲,我使用request做用域不就能夠避免每一個請求之間的安全問題了嗎?這是徹底錯誤的,由於Controller默認是單例的,一個controller對象是會被多個線程共享的,這就又回到了線程的安全問題。固然,你也能夠把Controller的scope改爲prototype,實際上Struts2就是這麼作的,但有一點要注意,Spring MVC對請求的攔截粒度是基於每一個方法的,而Struts2是基於每一個類的,因此把Controller設爲多例將會頻繁的建立與回收對象,嚴重影響到了性能。
經過閱讀上文其實已經說的很清楚了,Spring根本就沒有對bean的多線程安全問題作出任何保證與措施。對於每一個bean的線程安全問題,根本緣由是每一個bean自身的設計。不要在bean中聲明任何有狀態的實例變量或類變量,若是必須如此,那麼就使用ThreadLocal把變量變爲線程私有的,若是bean的實例變量或類變量須要在多個線程之間共享,那麼就只能使用synchronized、lock、CAS等這些實現線程同步的方法了。
下面將經過解析ThreadLocal的源碼來了解它的實現與做用,ThreadLocal是一個很好用的工具類,它在某些狀況下解決了線程安全問題(在變量不須要被多個線程共享時)。
ThreadLocal
ThreadLocal是一個爲線程提供線程局部變量的工具類。它的思想也十分簡單,就是爲線程提供一個線程私有的變量副本,這樣多個線程均可以隨意更改本身線程局部的變量,不會影響到其餘線程。不過須要注意的是,ThreadLocal提供的只是一個淺拷貝,若是變量是一個引用類型,那麼就要考慮它內部的狀態是否會被改變,想要解決這個問題能夠經過重寫ThreadLocal的initialValue()函數來本身實現深拷貝,建議在使用ThreadLocal時一開始就重寫該函數。
ThreadLocal與像synchronized這樣的鎖機制是不一樣的。首先,它們的應用場景與實現思路就不同,鎖更強調的是如何同步多個線程去正確地共享一個變量,ThreadLocal則是爲了解決同一個變量如何不被多個線程共享。從性能開銷的角度上來說,若是鎖機制是用時間換空間的話,那麼ThreadLocal就是用空間換時間。
ThreadLocal中含有一個叫作ThreadLocalMap的內部類,該類爲一個採用線性探測法實現的HashMap。它的key爲ThreadLocal對象並且還使用了WeakReference,ThreadLocalMap正是用來存儲變量副本的。
/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
....
ThreadLocal中只含有三個成員變量,這三個變量都是與ThreadLocalMap的hash策略相關的。
/**
* ThreadLocals rely on per-thread linear-probe hash maps attached
* to each thread (Thread.threadLocals and
* inheritableThreadLocals). The ThreadLocal objects act as keys,
* searched via threadLocalHashCode. This is a custom hash code
* (useful only within ThreadLocalMaps) that eliminates collisions
* in the common case where consecutively constructed ThreadLocals
* are used by the same threads, while remaining well-behaved in
* less common cases.
*/
private final int threadLocalHashCode = nextHashCode();
/**
* The next hash code to be given out. Updated atomically. Starts at
* zero.
*/
private static AtomicInteger nextHashCode =
new AtomicInteger();
/**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647;
/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
惟一的實例變量threadLocalHashCode是用來進行尋址的hashcode,它由函數nextHashCode()生成,該函數簡單地經過一個增量HASH_INCREMENT來生成hashcode。至於爲何這個增量爲0x61c88647,主要是由於ThreadLocalMap的初始大小爲16,每次擴容都會爲原來的2倍,這樣它的容量永遠爲2的n次方,該增量選爲0x61c88647也是爲了儘量均勻地分佈,減小碰撞衝突。
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
要得到當前線程私有的變量副本須要調用get()函數。首先,它會調用getMap()函數去得到當前線程的ThreadLocalMap,這個函數須要接收當前線程的實例做爲參數。若是獲得的ThreadLocalMap爲null,那麼就去調用setInitialValue()函數來進行初始化,若是不爲null,就經過map來得到變量副本並返回。
setInitialValue()函數會去先調用initialValue()函數來生成初始值,該函數默認返回null,咱們能夠經過重寫這個函數來返回咱們想要在ThreadLocal中維護的變量。以後,去調用getMap()函數得到ThreadLocalMap,若是該map已經存在,那麼就用新得到value去覆蓋舊值,不然就調用createMap()函數來建立新的map。
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
return setInitialValue();
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
protected T initialValue() {
return null;
ThreadLocal的set()與remove()函數要比get()的實現還要簡單,都只是經過getMap()來得到ThreadLocalMap而後對其進行操做。
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
/**
* Removes the current thread's value for this thread-local
* variable. If this thread-local variable is subsequently
* {@linkplain #get read} by the current thread, its value will be
* reinitialized by invoking its {@link #initialValue} method,
* unless its value is {@linkplain #set set} by the current thread
* in the interim. This may result in multiple invocations of the
* {@code initialValue} method in the current thread.
* @since 1.5
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
getMap()函數與createMap()函數的實現也十分簡單,可是經過觀察這兩個函數能夠發現一個祕密:ThreadLocalMap是存放在Thread中的。
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* @param t the current thread
* @param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
// Thread中的源碼
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
仔細想一想其實就可以理解這種設計的思想。有一種廣泛的方法是經過一個全局的線程安全的Map來存儲各個線程的變量副本,可是這種作法已經徹底違背了ThreadLocal的本意,設計ThreadLocal的初衷就是爲了不多個線程去併發訪問同一個對象,儘管它是線程安全的。而在每一個Thread中存放與它關聯的ThreadLocalMap是徹底符合ThreadLocal的思想的,當想要對線程局部變量進行操做時,只須要把Thread做爲key來得到Thread中的ThreadLocalMap便可。這種設計相比採用一個全局Map的方法會多佔用不少內存空間,但也所以不須要額外的採起鎖等線程同步方法而節省了時間上的消耗。
ThreadLocal中的內存泄漏
咱們要考慮一種會發生內存泄漏的狀況,若是ThreadLocal被設置爲null後,並且沒有任何強引用指向它,根據垃圾回收的可達性分析算法,ThreadLocal將會被回收。這樣一來,ThreadLocalMap中就會含有key爲null的Entry,並且ThreadLocalMap是在Thread中的,只要線程遲遲不結束,這些沒法訪問到的value會造成內存泄漏。爲了解決這個問題,ThreadLocalMap中的getEntry()、set()和remove()函數都會清理key爲null的Entry,如下面的getEntry()函數的源碼爲例。
/**
* Get the entry associated with key. This method
* itself handles only the fast path: a direct hit of existing
* key. It otherwise relays to getEntryAfterMiss. This is
* designed to maximize performance for direct hits, in part
* by making this method readily inlinable.
* @param key the thread local object
* @return the entry associated with key, or null if no such
*/
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
/**
* Version of getEntry method for use when key is not found in
* its direct hash slot.
* @param key the thread local object
* @param i the table index for key's hash code
* @param e the entry at table[i]
* @return the entry associated with key, or null if no such
*/
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
// 清理key爲null的Entry
while (e != null) {
ThreadLocal<?> k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
return null;
在上文中咱們發現了ThreadLocalMap的key是一個弱引用,那麼爲何使用弱引用呢?使用強引用key與弱引用key的差異以下:
但要注意的是,ThreadLocalMap僅僅含有這些被動措施來補救內存泄漏問題。若是你在以後沒有調用ThreadLocalMap的set()、getEntry()和remove()函數的話,那麼仍然會存在內存泄漏問題。
在使用線程池的狀況下,若是不及時進行清理,內存泄漏問題事小,甚至還會產生程序邏輯上的問題。因此,爲了安全地使用ThreadLocal,必需要像每次使用完鎖就解鎖同樣,在每次使用完ThreadLocal後都要調用remove()來清理無用的Entry
 

spring和springMVC的面試問題總結

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: http://www.javashuo.com/article/p-vizmbpfj-dy.html

1.Spring中AOP的應用場景、Aop原理、好處?

答:AOP--Aspect Oriented Programming面向切面編程;用來封裝橫切關注點,具體能夠在下面的場景中使用:

Authentication 權限、Caching 緩存、Context passing 內容傳遞、Error handling 錯誤處理Lazy loading懶加載、Debugging調試、logging, tracing, profiling and monitoring 記錄跟蹤優化 校準、Performance optimization 性能優化、Persistence 持久化、Resource pooling 資源池、Synchronization 同步、Transactions 事務

原理:AOP是面向切面編程,是經過動態代理的方式爲程序添加統一功能,集中解決一些公共問題。

優勢:1.各個步驟之間的良好隔離性耦合性大大下降 
           2.源代碼無關性,再擴展功能的同時不對源碼進行修改操做 

2.Spring中IOC的做用與原理?對象建立的過程。

答:IOC--Inversion of Control控制反轉。當某個角色須要另一個角色協助的時候,在傳統的程序設計過程當中,一般由調用者來建立被調用者的實例對象。但在spring中建立被調用者的工做再也不由調用者來完成,所以稱爲控制反轉。建立被調用者的工做由spring來完成,而後注入調用者 直接使用。

3.介紹spring框架

   它是一個一站式(full-stack全棧式)框架,提供了從表現層-springMVC到業務層-spring再到持久層-springdata的一套完整的解決方案。咱們在項目中能夠只使用spring一個框架,它就能夠提供表現層的mvc框架,持久層的Dao框架。它的兩大核心IoC和AOP更是爲咱們程序解耦和代碼簡潔易維護提供了支持。

4.Spring常見建立對象的註解?

答:@Component@Controller@ Service@ Repository

5.Spring中用到的設計模式

答:簡單工廠、工廠方法、單例模式、適配器、包裝器、代理、觀察者、策略、模板方法

詳細介紹:請參考本微博的:開發經常使用設計模式

6.Spring的優勢?

答:1.下降了組件之間的耦合性 ,實現了軟件各層之間的解耦 
2.可使用容易提供的衆多服務,如事務管理,消息服務等 
3.容器提供單例模式支持 
4.容器提供了AOP技術,利用它很容易實現如權限攔截,運行期監控等功能 
5.容器提供了衆多的輔助類,能加快應用的開發 
6.spring對於主流的應用框架提供了集成支持,如hibernate,JPA,Struts等 
7.spring屬於低侵入式設計,代碼的污染極低 
8.獨立於各類應用服務器 
9.spring的DI機制下降了業務對象替換的複雜性 
10.Spring的高度開放性,並不強制應用徹底依賴於Spring,開發者能夠自由選擇spring 的部分或所有 

7.Spring Bean的做用域之間有什麼區別?

Spring容器中的bean能夠分爲5個範圍。全部範圍的名稱都是自說明的,可是爲了不混淆,仍是讓咱們來解釋一下:

singleton:這種bean範圍是默認的,這種範圍確保無論接受到多少個請求,每一個容器中只有一個bean的實例,單例的模式由bean factory自身來維護。

prototype:原形範圍與單例範圍相反,爲每個bean請求提供一個實例。

request:在請求bean範圍內會每個來自客戶端的網絡請求建立一個實例,在請求完成之後,bean會失效並被垃圾回收器回收。

Session:與請求範圍相似,確保每一個session中有一個bean的實例,在session過時後,bean會隨之失效。

global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工做時,它包含不少portlet。若是你想要聲明讓全部的portlet共用全局的存儲變量的話,那麼這全局變量須要存儲在global-session中。

全局做用域與Servlet中的session做用域效果相同。

8.Spring管理事務有幾種方式?

答:有兩種方式:

一、編程式事務,在代碼中硬編碼。(不推薦使用)

二、聲明式事務,在配置文件中配置(推薦使用)

聲明式事務又分爲兩種:

a、基於XML的聲明式事務

b、基於註解的聲明式事務

9.spring中自動裝配的方式有哪些?

答:一、 No:即不啓用自動裝配。

二、 byName:經過屬性的名字的方式查找JavaBean依賴的對象併爲其注入。好比說類Computer有個屬性printer,指定其autowire屬性爲byName後,Spring IoC容器會在配置文件中查找id/name屬性爲printer的bean,而後使用Seter方法爲其注入。

三、 byType:經過屬性的類型查找JavaBean依賴的對象併爲其注入。好比類Computer有個屬性printer,類型爲Printer,那麼,指定其autowire屬性爲byType後,Spring IoC容器會查找Class屬性爲Printer的bean,使用Seter方法爲其注入。

四、 constructor:通byType同樣,也是經過類型查找依賴對象。與byType的區別在於它不是使用Seter方法注入,而是使用構造子注入。

五、 autodetect:在byType和constructor之間自動的選擇注入方式。

六、 default:由上級標籤<beans>的default-autowire屬性肯定。

10.spring中的核心類有那些,各有什麼做用?

答:BeanFactory:產生一個新的實例,能夠實現單例模式

BeanWrapper:提供統一的get及set方法

ApplicationContext:提供框架的實現,包括BeanFactory的全部功能

11.Bean的調用方式有哪些?

答:有三種方式能夠獲得Bean並進行調用:
一、使用BeanWrapper
HelloWorld hw=new HelloWorld();
BeanWrapper bw=new BeanWrapperImpl(hw);
bw.setPropertyvalue(」msg」,」HelloWorld」);
system.out.println(bw.getPropertyCalue(」msg」));
二、使用BeanFactory
InputStream is=new FileInputStream(」config.xml」);
XmlBeanFactory factory=new XmlBeanFactory(is);
HelloWorld hw=(HelloWorld) factory.getBean(」HelloWorld」);
system.out.println(hw.getMsg());
三、使用ApplicationConttext
ApplicationContext actx=new FleSystemXmlApplicationContext(」config.xml」);
HelloWorld hw=(HelloWorld) actx.getBean(」HelloWorld」);
System.out.println(hw.getMsg());

12.什麼是IOC,什麼又是DI,他們有什麼區別?

答:依賴注入DI是一個程序設計模式和架構模型, 一些時候也稱做控制反轉,儘管在技術上來說,依賴注入是一個IOC的特殊實現,依賴注入是指一個對象應用另一個對象來提供一個特殊的能力,例如:把一個 數據庫鏈接已參數的形式傳到一個對象的結構方法裏面而不是在那個對象內部自行建立一個鏈接。控制反轉和依賴注入的基本思想就是把類的依賴從類內部轉化到外 部以減小依賴

應用控制反轉,對象在被建立的時候,由一個調控系統內全部對象的外界實體,將其所依賴的對象的引用,傳遞給它。也能夠說,依賴被注入到對象中。所 以,控制反轉是,關於一個對象如何獲取他所依賴的對象的引用,這個責任的反轉。

13.spring有兩種代理方式:

答: 若目標對象實現了若干接口,spring使用JDK的java.lang.reflect.Proxy類代理。

      優勢:由於有接口,因此使系統更加鬆耦合

      缺點:爲每個目標類建立接口

若目標對象沒有實現任何接口,spring使用CGLIB庫生成目標對象的子類。

      優勢:由於代理類與目標類是繼承關係,因此不須要有接口的存在。

      缺點:由於沒有使用接口,因此係統的耦合性沒有使用JDK的動態代理好。

14.springMVC的流程?

答:1.用戶發送請求至前端控制器DispatcherServlet

2.DispatcherServlet收到請求調用HandlerMapping處理器映射器。

3.處理器映射器根據請求url找到具體的處理器,生成處理器對象及處理器攔截器(若是有則生成)一併返回給DispatcherServlet。

4.DispatcherServlet經過HandlerAdapter處理器適配器調用處理器

5.執行處理器(Controller,也叫後端控制器)。

6.Controller執行完成返回ModelAndView

7.HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet

8.DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器

9.ViewReslover解析後返回具體View

10.DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)。

11.DispatcherServlet響應用戶

15.Springmvc的優勢

答:1.它是基於組件技術的.所有的應用對象,不管控制器和視圖,仍是業務對象之類的都是 java組件.而且和Spring提供的其餘基礎結構緊密集成.

2.不依賴於Servlet API(目標雖是如此,可是在實現的時候確實是依賴於Servlet的)

3. 能夠任意使用各類視圖技術,而不只僅侷限於JSP

4 . 支持各類請求資源的映射策略

5 .它應是易於擴展的

相關文章
相關標籤/搜索