1. 程式人生 > >[Spring面試] 問題整理

[Spring面試] 問題整理

配置 異常 檢查 body 選擇 錯誤 npos p s ebean

1.談談你對spring IOC和DI的理解,它們有什麽區別?

IoC:Inverse of Control 反轉控制的概念,就是將原本在程序中手動創建UserService對象的控制權,交由Spring框架管理,

簡單說,就是創建UserService對象控制權被反轉到了Spring框架

DI:Dependency Injection 依賴註入,在Spring框架負責創建Bean對象時,動態的將依賴對象註入到Bean組件

IoC 和 DI的區別?

IoC 控制反轉,指將對象的創建權,反轉到Spring容器 , DI 依賴註入,指Spring創建對象的過程中,將對象依賴屬性通過配置進行註入

2.BeanFactory 接口和 ApplicationContext 接口有什麽區別 ?

①ApplicationContext 接口繼承BeanFactory接口,Spring核心工廠是BeanFactory ,BeanFactory采取延遲加載,第一次getBean時才會初始化Bean, ApplicationContext是會在加載配置文件時初始化Bean。 ②ApplicationContext是對BeanFactory擴展,詳細區別說明:
國際化處理 BeanFactory是不支持國際化功能的,因為BeanFactory沒有擴展Spring中MessageResource接口。相反,由於ApplicationContext擴展了MessageResource接口,因而具有消息處理的能力(i18N)
事件機制 ApplicationContext的事件機制主要通過ApplicationEvent和ApplicationListener這兩個接口來提供的,和java swing中的事件機制一樣。即當ApplicationContext中發布一個事件的時,所有擴展了ApplicationListener的Bean都將會接受到這個事件,並進行相應的處理。

Spring提供了部分內置事件,主要有以下幾種:
ContextRefreshedEvent :ApplicationContext發送該事件時,表示該容器中所有的Bean都已經被裝載完成,此ApplicationContext已就緒可用
ContextStartedEvent:生命周期 beans的啟動信號
ContextStoppedEvent: 生命周期 beans的停止信號
ContextClosedEvent:ApplicationContext關閉事件,則context不能刷新和重啟,從而所有的singleton bean全部銷毀(因為singleton bean是存在容器緩存中的)

雖然,spring提供了許多內置事件,但用戶也可根據自己需要來擴展spring中的事物。註意,要擴展的事件都要實現ApplicationEvent接口。
底層資源的訪問 ApplicationContext擴展了ResourceLoader(資源加載器)接口,從而可以用來加載多個Resource,而BeanFactory是沒有擴展ResourceLoader
對Web應用的支持 與BeanFactory通常以編程的方式被創建不同的是,ApplicationContext能以聲明的方式創建,如使用ContextLoader。當然你也可以使用ApplicationContext的實現之一來以編程的方式創建ApplicationContext實例 。

ContextLoader有兩個實現:ContextLoaderListenerContextLoaderServlet。它們兩個有著同樣的功能,除了listener不能在Servlet 2.2兼容的容器中使用。自從Servelt 2.4規範,listener被要求在web應用啟動後初始化。很多2.3兼容的容器已經實現了這個特性。使用哪一個取決於你自己,但是如果所有的條件都一樣,你大概會更喜歡ContextLoaderListener;關於兼容方面的更多信息可以參照ContextLoaderServlet的JavaDoc。

這個listener需要檢查contextConfigLocation參數。如果不存在的話,它將默認使用/WEB-INF/applicationContext.xml。如果它存在,它就會用預先定義的分隔符(逗號,分號和空格)分開分割字符串,並將這些值作為應用上下文將要搜索的位置。ContextLoaderServlet可以用來替換ContextLoaderListener。這個servlet像listener那樣使用contextConfigLocation參數。

其它 1).BeanFactroy采用的是延遲加載形式來註入Bean的,即只有在使用到某個Bean時(調用getBean()),才對該Bean進行加載實例化,這樣,我們就不能發現一些存在的Spring的配置問題。而ApplicationContext則相反,它是在容器啟動時,一次性創建了所有的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤。

2).BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區別是:BeanFactory需要手動註冊,而ApplicationContext則是自動註冊

開發中基本都在使用ApplicationContext, web項目使用WebApplicationContext ,很少用到BeanFactory。

3.spring配置bean實例化有哪些方式?

1)使用類構造器實例化

<bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean>

2)使用靜態工廠方法實例化(簡單工廠模式)

<bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2"></bean>

3)使用實例工廠方法實例化(工廠方法模式)

<bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory"></bean>

<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>

4.簡單的說一下spring的生命周期?

①instantiate bean對象實例化

②populate properties 封裝屬性

③如果Bean實現BeanNameAware 執行 setBeanName

④如果Bean實現BeanFactoryAware 或者 ApplicationContextAware 設置工廠 setBeanFactory 或者上下文對象 setApplicationContext

⑤如果存在類實現 BeanPostProcessor(後處理Bean) ,執行postProcessBeforeInitialization,BeanPostProcessor接口提供鉤子函數,用來動態擴展修改Bean。(程序自動調用後處理Bean)

⑥如果Bean實現InitializingBean 執行 afterPropertiesSet

⑦調用<bean init-method="init"> 指定初始化方法 init

⑧如果存在類實現 BeanPostProcessor(處理Bean) ,執行postProcessAfterInitialization

⑨執行業務處理

⑩如果Bean實現 DisposableBean 執行 destroy

?調用<bean destroy-method="customerDestroy"> 指定銷毀方法 customerDestroy

5.請介紹一下Spring框架中Bean的生命周期和作用域

Bean的生命周期:

(1)bean定義

在配置文件裏面用<bean></bean>來進行定義。

(2)bean初始化,有兩種方式初始化:

A.在配置文件中通過指定init-method屬性來完成

B.實現org.springframwork.beans.factory.InitializingBean接口

(3)bean調用

有三種方式可以得到bean實例,並進行調用

(4)bean銷毀

銷毀有兩種方式

A.使用配置文件指定的destroy-method屬性

B.實現org.springframwork.bean.factory.DisposeableBean接口

Bean的作用域:

singleton

當一個bean的作用域為singleton, 那麽Spring IoC容器中只會存在一個共享的bean實例,並且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實例。

prototype

Prototype作用域的bean會導致在每次對該bean請求(將其註入到另一個bean中,或者以程序的方式調用容器的getBean() 方法)時都會創建一個新的bean實例。根據經驗,對所有有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用 singleton作用域

request

在一次HTTP請求中,一個bean定義對應一個實例;即每次HTTP請求將會有各自的bean實例, 它們依據某個bean定義創建而成。該作用 域僅在基於web的Spring ApplicationContext情形下有效。

session

在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。

global session

在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基於 web的Spring ApplicationContext情形下有效。

6.Bean註入屬性有哪幾種方式?

構造器註入,通過 <constructor-arg> 元素完成註入

setter方法註入, 通過<property> 元素完成註入【開發中常用方式】

7.什麽是AOP,AOP的作用是什麽?

技術分享

8.Spring如何處理線程並發問題?

Spring使用ThreadLocal解決線程安全問題

我們知道在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。就是因為Spring對一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態采用ThreadLocal進行處理,讓它們也成為線程安全的狀態,因為有狀態的Bean就可以在多線程中共享了。

ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。

在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什麽時候對變量進行讀寫,什麽時候需要鎖定某個對象,什麽時候釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。

而ThreadLocal則從另一個角度來解決多線程的並發訪問。ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

由於ThreadLocal中可以持有任何類型的對象,低版本JDK所提供的get()返回的是Object對象,需要強制類型轉換。但JDK5.0通過泛型很好的解決了這個問題,在一定程度地簡化ThreadLocal的使用。

概括起來說,對於多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而後者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

9.介紹一下Spring的事物管理

事務就是對一系列的數據庫操作(比如插入多條數據)進行統一的提交或回滾操作,如果插入成功,那麽一起成功,如果中間有一條出現異常,那麽回滾之前的所有操作。這樣可以防止出現臟數據,防止數據庫數據出現問題。

開發中為了避免這種情況一般都會進行事務管理。Spring中也有自己的事務管理機制,一般是使用TransactionMananger進行管 理,可以通過Spring的註入來完成此功能。spring提供了幾個關於事務處理的類:

TransactionDefinition //事務屬性定義

TranscationStatus //代表了當前的事務,可以提交,回滾。

PlatformTransactionManager這個是spring提供的用於管理事務的基礎接口,其下有一個實現的抽象類 AbstractPlatformTransactionManager,我們使用的事務管理類例如 DataSourceTransactionManager等都是這個類的子類。

一般事務定義步驟:

  1. TransactionDefinition td =newTransactionDefinition();
  2. TransactionStatus ts = transactionManager.getTransaction(td);
  3. try{
  4. //do sth
  5. transactionManager.commit(ts);
  6. }catch(Exception e){
  7. transactionManager.rollback(ts);
  8. }
spring提供的事務管理可以分為兩類:編程式的和聲明式的。編程式的,比較靈活,但是代碼量大,存在重復的代碼比較多;聲明式的比編程式的更靈活。

編程式主要使用transactionTemplate。省略了部分的提交,回滾,一系列的事務對象定義,需註入事務管理對象.

  1. void add(){
  2. transactionTemplate.execute(newTransactionCallback(){
  3. pulic Object doInTransaction(TransactionStatus ts){
  4. //do sth
  5. }
  6. }
  7. }
聲明式:

使用TransactionProxyFactoryBean:PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED,readOnly

圍繞Poxy的動態代理 能夠自動的提交和回滾事務

org.springframework.transaction.interceptor.TransactionProxyFactoryBean

PROPAGATION_REQUIRED–支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。

PROPAGATION_SUPPORTS–支持當前事務,如果當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY–支持當前事務,如果當前沒有事務,就拋出異常。

PROPAGATION_REQUIRES_NEW–新建事務,如果當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED–以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER–以非事務方式執行,如果當前存在事務,則拋出異常。

PROPAGATION_NESTED–如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與 PROPAGATION_REQUIRED類似的操作。

10.解釋一下Spring AOP裏面的幾個名詞

例子:

技術分享
package core;

import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

//使用 @Aspect 註解將一個java類定義為切面類
@Aspect
@Component
public class WebLogAspect {

    private Logger logger = Logger.getLogger(getClass());

    //使用 @Pointcut 定義一個切入點,可以是一個規則表達式,比如下例中某個package下的所有函數,也可以是一個註解等。
    //TestController 任意方法的執行
    @Pointcut("execution(* core.TestController.*(..))")
    public void webLog(){}

    //使用 @Before 在切入點開始處切入內容
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到請求,記錄請求內容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 記錄下請求內容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));

    }
    //使用 @AfterReturning 在切入點return內容之後切入內容(可以用來對處理返回值做一些加工處理)
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請求,返回內容
        logger.info("RESPONSE : " + ret);
    }

}
WebLogAspect.java

輸出LOG:

技術分享

11.通知有哪些類型?

前置通知(Before advice):在某連接點(join point)之前執行的通知,但這個通知不能阻止連接點前的執行(除非它拋出一個異常)。 返回後通知(After returning advice):在某連接點(join point)正常完成後執行的通知:例如,一個方法沒有拋出任何異常,正常返回。
拋出異常後通知(After throwing advice):在方法拋出異常退出時執行的通知。
後通知(After (finally) advice):當某連接點退出的時候執行的通知(不論是正常返回還是異常退出)。
環繞通知(Around Advice):包圍一個連接點(join point)的通知,如方法調用。這是最強大的一種通知類型。 環繞通知可以在方法調用前後完成自定義的行為。它也會選擇是否繼續執行連接點或直接返回它們自己的返回值或拋出異常來結束執行。

環繞通知是最常用的一種通知類型。大部分基於攔截的AOP框架,例如Nanning和JBoss4,都只提供環繞通知。
切入點(pointcut)和連接點(join point)匹配的概念是AOP的關鍵,這使得AOP不同於其它僅僅提供攔截功能的舊技術。 切入點使得定位通知(advice)可獨立於OO層次。 例如,一個提供聲明式事務管理的around通知可以被應用到一組橫跨多個對象中的方法上(例如服務層的所有業務操作)。

[Spring面試] 問題整理