JavaGuide知識點整理——Spring常見面試題總結

Spring基礎

什麼是Spring框架?

Spring是一款開源的輕量級java開發框架。旨在提高開發人員的開發效率以及系統的可維護性。
我們一般說的Spring框架指的是Spring Framework。它是很多模塊的集合。使用這些可以方便協助我們進行開發,比如Spring支持IOC(控制反轉)和AOP(切面編程),可以很方便的對數據庫進行訪問,可以很方便的集成三方組件,對單元測試友好,支持Restful接口等。
Spring最核心的思想是不重新造輪子,開箱即用,提高開發效率。

Spring包含哪些模塊?

Core Container(核心組件)
Spring框架的核心模塊就是core。也可以說是基礎模塊,主要提供IOC依賴注入功能的支持。Spring的其他所有功能都依賴於該模塊。我們從上面的依賴圖就可以看出。

  • spring-core:Spring框架基本的核心工具類
  • spring-beans:提供對bean創建,配置,管理等功能
  • spring-context:提供對國際化,事件傳播,資源加載等功能
  • spring-expression:提供對錶達式語言SpELD的支持,只依賴core模塊,可以單獨使用。

AOP

  • spring-aspects:該模塊爲與AspectJ的集成提供支持
  • spring-aop:提供了面向切面編程的實現
  • spring-instrument:提供了爲JVM添加代理的功能。具體來講,它爲tomcat提供了一個植入代理。能夠爲tomcat傳遞類文件。就像這些文件是被類加載器加載的一樣。

Data Access

  • spring-jdbc:提供了對數據庫訪問的抽象JDBC,不同的數據庫都有自己獨立的api用於操作數據庫。而java程序只要和JDBC API交互,這樣就屏蔽了數據庫的影響。
  • spring-tx:提供對事務的支持
  • spring-orm:提供對hibernate,jpa,mybatis等ORM框架的支持
  • spring-oxm:提供一個抽象層支持OXM,例如JAXB,Castor,XMLBeans等
  • spring-jms:消息服務,spring4.1之後,還提供了對spring-messaging模塊的繼承。

Spring Web

  • spring-web:對web功能的實現提供一些最基礎的支持
  • spring-webmvc:提供對spring mvc的實現
  • spring-websocket:提供對webSocket的支持。讓客戶端和服務端進行雙向通信。
  • spring-webflux:提供對webflux的支持。是spring5.0中引入的響應式框架。它不需要servlet api,是完全異步。

Spring Test
spring團隊提倡測試驅動開發(TDD)。有了控制反轉的幫助,單元測試和集成測試變得更簡單。spring的測試模塊對junit,testNG,Mockito等等常用的測試框架支持的都比較好。

Spring,Spring MVC,Spring Boot之間的關係

Spring包含了多個功能模塊,其中最重要的是spring-core(提供ioc依賴注入功能的支持),而Spring MVC功能的實現需要依賴該模塊。
spring-mvc也是Spring中一個很重要的模塊,主要賦予spring快速構建MVC架構的web程序的能力。M是模型,V是試圖,C是控制器。其核心思想是通過將業務邏輯,數據,顯示分離來組織代碼。

而使用Spring進行開發的時候各種配置很麻煩,需要用到XML或者java顯示配置,於是Spring Boot誕生了。
Spring旨在簡化開發,Spring Boot旨在簡化Spring的開發。Spring Boot只是簡化了配置,其實本質上還是Spring MVC框架,只是做到了開箱即用而已。

Spring IoC

Spring IoC是什麼

IoC(Inverse of Control:控制反轉)是一種設計思想,而不是一個具體的技術實現。IoC的思想就是將原本在程序中手動創建對象的控制權限交由Spring框架管理。不過IoC並非spring特有,其它語言中也有應用。
爲什麼叫控制反轉?

  • 控制:指的是對象創建的權力
  • 反轉:控制權交給外部環境


將對象之間的相互依賴關係交給IoC容器來管理,並由IoC容器完成對象的注入。這樣可以很大程度簡化應用開發。把應用從複雜的依賴關係中解放出來。IoC容器就像是一個工廠一樣,當我們需要創建一個對象的時候,只需要配置好配置文件/註解即可,完全不用考慮對象是如何被創建出來的。
在實際項目中一個Service類可能依賴很多其它的類,加入我們需要實例化這個Service,可能每次都要搞清楚Service所有底層類的構造函數。如果利用IoC的話,只需要配置好,然後在需要的地方引用就行了。降低了項目的開發難度,提高了可維護性。
在Spring中,IoC容器是Spring用來實現IoC的載體,實際上IoC容器就是個Map,Map中key是對象名,value是各種對象。
Spring時代我們一般用xml配置bean,後來覺得xml很麻煩,spring boot註解配置就流行起來了。

什麼是Spring Bean?

簡單來說Bean代指那些被IoC容器所管理的對象。
我們需要告訴IoC容器幫我們管理哪些對象。這個是通過配置來定義的。之前的xml文件,和現在常用的註解配置,也可以通過java配置類配置。

將一個類聲明爲Bean有哪些註解?

  • @Component:可標註任意類爲Spring組件。如果不知道處於哪層,可以用此註解標註。
  • @Repository:對應持久層即Dao層。主要用於數據庫相關操作
  • @Service:對應服務層。涉及到業務邏輯
  • @Controller:對應spring mvc的控制層,用於接收用戶請求並調用service層返回數據給前端

@Component與@Bean的區別是什麼?

  • @Component註解用於類,@Bean用於方法
  • @Component通常是通過類路徑掃描自動裝配到spring容器中。@Bean註解通常我們在標有該註解的方法中定義產生這個bean。
  • @Bean註解比@Component註解的自定義性強,很多地方我們只能通過@Bean註解來註冊bean。比如我們引用三方庫中的類需要裝配到Spring容器時,只能通過@Bean來實現。

注入Bean的註解有哪些?

  • @Autowired: spring提供的註解
  • @Resource:jdk提供的註解
  • @Inject:jdk提供的,但是我沒用過

@Autowired和@Resource的區別是什麼?

  • Autowired屬於spring內置的註解,默認的注入方式是byType根據類型匹配。也就是說會優先根據接口類型區匹配並注入bean(接口的實現類)。
    比如A接口,有A1,A2,A3三個實現類,如果用@Autowired注入A。那麼就無法正確的注入對象了。這種情況下注入方式會變成byName,如果說注入的bean名稱是a2,那麼會匹配到A2這個類。所以建議在使用@Autowired的時候用@Qualifier指定名稱

  • Resource是JDK提供的註解,優先根據byName注入,如果無法通過名稱匹配會根據byType注入。

也就是說當一個接口存在多個實現類的時候,兩者都需要指定名稱。Autowired是通過@Qualifier註解來顯示指定名稱。@Resource可以通過name屬性來指定名稱。

Bean的作用域有哪些?

  • singleton:單例bean,容器中只有唯一的bean實例。spring中bean默認都是單例。
  • prototype:非單例bean,每次獲取都創建一個新的bean實例。
  • request(僅web應用可用):每次http請求都會產生一個新的bean。該bean僅在當前http request中有效
  • session(僅web應用可用):每一次來自新session的http請求都會生成一個新的會話bean。該bean僅在當前http request中有效
  • application/global-session(僅web應用可用):每個web應用在啓動時創建一個bean,該bean僅在當前應用啓動時間內有效。
  • websocket(僅web應用可用):每一個websocket會話產生一個新的bean。

我們可以在配置bean的時候通過@Score註解配置作用域

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
    return new Person();
}

單例Bean的線程安全問題

單例Bean存在線程安全問題,主要是因爲當多個線程操作同一個對象的時候是存在資源競爭的。常見的兩種解決辦法如下:

  1. 在Bean中儘量避免定義可變的成員變量。
  2. 在類中定義一個ThreadLocal的成員變量,將需要的可變成員標量保存在ThreadLocal中。

不過大部分情況Bean都是武裝的,這種情況下Bean是線程安全的。

Bean的生命週期

  • Bean容器找到配置文件中的Spring Bean的定義
  • Bean容器利用java Reflection API創建一個Bean實例
  • 如果涉及到一些屬性值利用set()方法設置一些屬性
  • 如果Bean實現了BeanNameAware接口,調用serBeanName()方法傳入Bean的名字
  • 如果實現了BeanClassLoaderAware 接口,調用 setBeanClassLoader()方法,傳入 ClassLoader對象的實例。
  • 如果 Bean 實現了 BeanFactoryAware 接口,調用 setBeanFactory()方法,傳入 BeanFactory對象的實例。
  • 反正實現了什麼xxxAware接口,就調用相應接口的方法。
  • 如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象。執行postProcessBeforeInitialization() 方法。
  • 如果Bean實現了InitialzingBean接口,執行afterPropertiesSet()方法。
  • 如果有和加載這個 Bean 的 Spring 容器相關的 BeanPostProcessor 對象,執行postProcessAfterInitialization() 方法。
  • 當要銷燬 Bean 的時候,如果 Bean 實現了 DisposableBean 接口,執行 destroy() 方法。
  • 當要銷燬 Bean 的時候,如果 Bean 在配置文件中的定義包含 destroy-method 屬性,執行指定的方法。


Spring AoP

談談對AOP的瞭解

AOP面向切面編程,能將那些與業務無關,卻爲業務模塊共同調用的邏輯或者責任封裝起來,便於減少系統的重複代碼,降低模塊間的耦合度。並有利於維護和擴展。
Spring AOP就是基於動態代理的,如果要代理的對象實現了某個接口,那麼Spring AOP就會使用JDK代理去創建對象,而對於沒有實現接口的對象,就無法使用JDK代理,這時候Spring AOP會使用Cglib生成一個被代理對象的子類來作爲代理。


當然我們也可以使用AspectJ,AspectJ算是java生態系統中最完整的AOP框架了。
AOP切面編程涉及到的一些術語:

  • 目標(Target) 被通知的對象
  • 代理(Proxy) 向目標對象應用通知之後創建的代理對象
  • 連接點(JoinPoint) 目標對象的所屬類中,定義的所有方法均爲連接點
  • 切入點(Pointcut) 被切面攔截 / 增強的連接點(切入點一定是連接點,連接點不一定是切入點)
  • 通知(Advice) 增強的邏輯 / 代碼,也即攔截到目標對象的連接點之後要做的事情
  • 切面(Aspect) 切入點(Pointcut)+通知(Advice)
  • Weaving(織入) 將通知應用到目標對象,進而生成代理對象的過程動作

Spring AOP和AspectJ AOP有什麼區別?

Spring AOP屬於運行時增強,而AspectJ是編譯時增強。Spring AOP基於代理,而AspectJ基於字節碼操作。
AspectJ功能更強大,而Spring AOP更簡單。
如果我們切面比較少,兩者性能差別不大。如果切面太多,建議AspectJ。它比Spring AOP快很多。

AspectJ定義的通知類型有哪些?

  • Before(前置通知):目標對象的方法調用前觸發
  • After(後置通知):目標對象的方法調用後觸發
  • AfterReturning(返回通知):目標對象方法調用完成,在返回結果值之後觸發
  • AfterThrowing(異常通知):目標對象的方法運行中拋出/觸發異常觸發。這個和上面的AfterReturning是互斥的。
  • Around(環繞通知):可以任意在目標對象的方法調用前後搞事情,甚至不調用目標對象的方法。

多個切面的順序如何控制?

  1. 可以用@Order註解定義切面順序(值越小,優先級越高)
  2. 實現Ordered接口重寫getOrder方法(返回值越小,優先級越高)

Spring MVC

說說對Spring mvc的瞭解

mvc是模型Model,視圖View,控制器Controller的簡寫。其核心思想是將業務邏輯,數據,顯示分離來組織代碼。MVC是一種思想,也算是一種設計模式。

Model1時代
不得不說到一個很古老的技術JSP,JSP既是控制層,優勢表現層。這種模式的問題是代碼複用率低,而且前後端一起開發,很難維護和定位問題。我是17年入行的,當時學習有學到這個技術,但是我工作以後就已經變成了mvc前後端分離的模式,所以對於jsp屬於能看懂,但是不熟悉的程度。

Model2時代
據說是Java Bean(Model)+JSP(View)+Servlet(Controller)開發模式,這就是早期的JavaWeb MVC開發模式。

  • Model:系統涉及的數據,也就是dao和bean
  • View:展示模型中的數據,只是用來展示
  • Controller:處理用戶請求都發送給它,返回數據給JSP並展示給用戶。

Spring MVC時代
隨着spring輕量級框架的流行。spring生態圈出了Spring MVC框架。是當前最優秀的MVC框架。相比於Struts2.Spring MVC更加簡單和方便,開發效率更高。並且spring MVC運行速度很快。
MVC是一種設計模式,Spring MVC是一款優秀的MVC框架。可以幫我們進行更簡潔的web層的開發,並且它天生與spring框架集成。Spring MVC下我們一般把後端項目分爲Service層,Dao層,Entity層,Controller層。

Spring MVC的核心組件有哪些?

  • DispatcherServlet:核心的中央處理器。負責接收請求,分發,並給予客戶端響應。
  • HandlerMapping:處理器映射器。根據uri去匹配查找能處理的Handler,並會將請求涉及到的攔截器和Handler一起封裝。
  • HandlerAdapter:處理器適配器。根據HandlerMapping找到的handler適配執行對應的handler。
  • Handler:請求處理器。處理實際請求的處理器。
  • ViewResolver:視圖解析器。根據Handler返回的邏輯視圖/視圖,解析並渲染真正的視圖,並傳遞給DispatcherServlet響應客戶端。

SpringMVC工作原理


流程說明:

  1. 客戶端發送請求,DispatcherServlet攔截請求
  2. DispatcherServlet根據請求信息調用HandlerMapping,HandlerMapping根據uri去匹配查找能處理的Handler(就是我們說的Controller控制器)。並將請求涉及到的攔截器和Handler一起封裝。
  3. DispatcherServlet調用HandlerAdapter適配器執行Handler。
  4. Handler完成對用戶請求的處理後,返回一個ModelAndView對象給DispatcherServlet,這個對象裏包含了數據模型和相應的視圖信息。M哦的歷史返回的數據對象。View是邏輯上的視圖。
  5. ViewResolver會根據邏輯View查找實際的View。
  6. DispatcherServlet把返回的Model傳給View(視圖渲染)。
  7. 把View返回給請求者。

統一異常處理怎麼做?

可以使用註解的方式統一異常處理。@ControllerAdvice和@ExceptionHandler這兩個註解。

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(BaseException.class)
    public ResponseEntity<?> handleAppException(BaseException ex, HttpServletRequest request) {
      //......
    }

    @ExceptionHandler(value = ResourceNotFoundException.class)
    public ResponseEntity<ErrorReponse> handleResourceNotFoundException(ResourceNotFoundException ex, HttpServletRequest request) {
      //......
    }
}

這種異常處理方式下,會給所有或者指定的Controller植入異常處理的邏輯(AOP)。當Controller中的方法拋出異常的時候,由被@ExceptionHandler註解修飾的方法進行處理。
ExceptionHandlerMethodResolver 中 getMappedMethod 方法決定了異常具體被哪個被 @ExceptionHandler 註解修飾的方法處理異常。

@Nullable
    private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
        List<Class<? extends Throwable>> matches = new ArrayList<>();
    //找到可以處理的所有異常信息。mappedMethods 中存放了異常和處理異常的方法的對應關係
        for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
            if (mappedException.isAssignableFrom(exceptionType)) {
                matches.add(mappedException);
            }
        }
    // 不爲空說明有方法處理異常
        if (!matches.isEmpty()) {
      // 按照匹配程度從小到大排序
            matches.sort(new ExceptionDepthComparator(exceptionType));
      // 返回處理異常的方法
            return this.mappedMethods.get(matches.get(0));
        }
        else {
            return null;
        }
    }

從源碼看出:getMappedMethod()會首先找到可以匹配處理異常的所有方法信息,然後對其進行從小到大排序,最後取最小的那一個匹配的方法。

Spring框架中用到了哪些設計模式?

  • 依賴注入是實現控制反轉的一種設計模式。控制反轉是一個思想,a對象依賴b,如果是創建a的時候去創建b,這是一種直接模式。而IOC控制反轉的思想是讓a和b失去直接聯繫。當創建a的時候需要b,直接從容器中拿b給a用。而這個實現就是依賴注入。所以說依賴注入是實現控制反轉的一種設計模式。

  • 工廠設計模式。spring可以通過BeanFactory或者ApplicationContext創建bean對象。

    • 說一下BeanFactory和ApplicationContext的區別:
      BeanFactory是延遲注入,用到纔會注入。因此不太影響程序啓動
      ApplicationContext是容器啓動的時候不管用沒用到一次性創建。而且ApplicationContext擴展了BeanFactory。其有三個實現類,分別是;類文件掃描,xml文件掃描和yml/properties文件掃描。
  • 單例設計模式:spring中bean的默認作用域就是單例的。其實現的方式是通過註冊表。其實就是個key。id是bean名稱,值是單例對象本身。在獲取bean的時候如果註冊表存在則直接取。如果不存在創建(創建過程中用了雙重檢測鎖機制)後加入到註冊表中。並返回。

  • 代理設計模式:AOP就是通過動態代理實現的。如果代理的對象實現了某接口,就通過jdk去創建代理對象。如果沒有實現接口。就用cglib生成被代理對象的子類來代理(代理模式就是用a對象去代理b。我們可以理解中介代理了房東一樣)。

  • 模板方法模式:幾乎所有的Template都是用到了模板方法。大概意思就是先設置一個模板,然後讓子類去按照這個模板實現。其中包括有些事必須按照模板來實現,有些要自己去填充。就好像上班一樣,不管任何崗位,上班,下班是固定的,但是每個人的工作內容又不一樣的。但是 上班 + 工作 +下班,這三個算是一個模板。

  • 觀察者模式: spring中事件驅動模型(監聽機制)就屬於觀察者模式。繼承ApplicationEvent實現。這個模式比較簡單,理論上就是當a發生改變,b也要同步做點什麼。這樣可以說b在觀察a。

適配器模式:就是將一個接口轉換成客戶希望的另一個接口。mvc的實現中用到了適配器處理器,其實現的功能的就是適配。

本篇筆記就記到這裏,如果稍微幫到你了記得點個喜歡點個關注。也祝大家工作順順利利!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章