Java面试——Spring系列总结
文章目錄:
1.什么是Spring?
2.Spring由哪些模塊組成?
3.Spring中都用到了哪些設(shè)計(jì)模式?
4.什么是Spring IOC容器?有什么作用?
5.Spring IoC的實(shí)現(xiàn)機(jī)制
6.BeanFactory 和 ApplicationContext有什么區(qū)別?
7.什么是Spring的依賴注入(Dependency Injection)?
8.什么是Spring AOP?
9.Spring AOP 與 AspectJ AOP 有什么區(qū)別?AOP 有哪些實(shí)現(xiàn)方式?
10.解釋一下Spring AOP里面的幾個(gè)名詞
11.Spring AOP中的通知有哪些類型?
12.Spring支持的幾種bean的作用域
13.解釋一下Spring中bean的生命周期
14.Spring支持的事務(wù)管理類型, Spring事務(wù)實(shí)現(xiàn)方式有哪些?你更傾向用哪種事務(wù)管理類型?
15.什么是Spring事務(wù)的傳播行為?
16.什么是Spring事務(wù)的隔離級別?
1.什么是Spring?
Spring是一個(gè)輕量級Java開源框架,最早由Rod Johnson創(chuàng)建,目的是解決企業(yè)級應(yīng)用開發(fā)的復(fù)雜性,簡化Java開發(fā)。Spring為開發(fā)Java應(yīng)用程序提供全面的基礎(chǔ)架構(gòu)支持,因此Java開發(fā)者可以專注于應(yīng)用程序的開發(fā)。
Spring可以做很多事情,它為企業(yè)級開發(fā)提供給了豐富的功能,但是這些功能的底層都依賴于它的兩個(gè)核心特性,也就是控制反轉(zhuǎn)(IoC)也可以說依賴注入(DI)和面向切面編程(AOP)。
為了降低Java開發(fā)的復(fù)雜性,Spring采取了以下4種關(guān)鍵策略
- 基于POJO的輕量級和最小侵入性編程;
- 通過依賴注入和面向接口實(shí)現(xiàn)松耦合;
- 基于切面和慣例進(jìn)行聲明式編程;
- 通過切面和模板減少樣板式代碼。
Spring設(shè)計(jì)目標(biāo):Spring為開發(fā)者提供一個(gè)一站式輕量級應(yīng)用開發(fā)平臺(tái);
Spring設(shè)計(jì)理念:在JavaEE開發(fā)中,支持POJO和JavaBean開發(fā)方式,使應(yīng)用面向接口開發(fā),充分支持OO(面向?qū)ο?#xff09;設(shè)計(jì)方法;Spring通過IoC容器實(shí)現(xiàn)對象耦合關(guān)系的管理,并實(shí)現(xiàn)依賴反轉(zhuǎn),將對象之間的依賴關(guān)系交給IoC容器,實(shí)現(xiàn)解耦;
Spring框架的核心:IoC容器和AOP模塊。通過IoC容器管理POJO對象以及他們之間的耦合關(guān)系;通過AOP以動(dòng)態(tài)非侵入的方式增強(qiáng)服務(wù),把遍布于應(yīng)用各層的功能分離出來形成可重用的功能組件。
2.Spring由哪些模塊組成?
- spring core:提供了框架的基本組成部分,包括控制反轉(zhuǎn)(Inversion of Control,IOC)和依賴注入(Dependency Injection,DI)功能。
- spring beans:提供了BeanFactory,是工廠模式的一個(gè)經(jīng)典實(shí)現(xiàn),Spring將管理對象稱為Bean。
- spring context:構(gòu)建于 core 封裝包基礎(chǔ)上的 context 封裝包,提供了一種框架式的對象訪問方法。
- spring jdbc:提供了一個(gè)JDBC的抽象層,消除了煩瑣的JDBC編碼和數(shù)據(jù)庫廠商特有的錯(cuò)誤代碼解析, 用于簡化JDBC。
- spring aop:提供了面向切面的編程實(shí)現(xiàn),讓你可以自定義攔截器、切點(diǎn)等。
- spring Web:提供了針對 Web 開發(fā)的集成特性,例如文件上傳,利用 servlet listeners 進(jìn)行 ioc 容器初始化和針對 Web 的 ApplicationContext。
- spring test:主要為測試提供支持的,支持使用JUnit或TestNG對Spring組件進(jìn)行單元測試和集成測試。
3.Spring中都用到了哪些設(shè)計(jì)模式?
4.什么是Spring IOC容器?有什么作用?
控制反轉(zhuǎn)即IoC (Inversion of Control),它把傳統(tǒng)上由程序代碼直接操控的對象的調(diào)用權(quán)交給容器,通過容器來實(shí)現(xiàn)對象組件的裝配和管理。所謂的“控制反轉(zhuǎn)”概念就是對對象組件控制權(quán)的轉(zhuǎn)移,從程序代碼本身轉(zhuǎn)移到了外部容器。
Spring IOC 負(fù)責(zé)創(chuàng)建對象,管理對象(通過依賴注入(DI),裝配對象,配置對象,并且管理這些對象的整個(gè)生命周期。)
IoC容器的作用:
- 管理對象的創(chuàng)建和依賴關(guān)系的維護(hù)。對象的創(chuàng)建并不是一件簡單的事,在對象關(guān)系比較復(fù)雜時(shí),如果依賴關(guān)系需要程序猿來維護(hù)的話,那是相當(dāng)頭疼的
- 解耦,由容器去維護(hù)具體的對象
- 托管了類的整個(gè)生命周期,比如我們需要在類的產(chǎn)生過程中做一些處理,最直接的例子就是代理,如果有容器程序可以把這部分處理交給容器,應(yīng)用程序則無需去關(guān)心類是如何完成代理的
5.Spring IoC的實(shí)現(xiàn)機(jī)制
Spring 中的 IoC 的實(shí)現(xiàn)原理就是工廠模式加反射機(jī)制。
package com.szh.spring;/****/ interface Fruit {void eat(); }class Apple implements Fruit {public Apple() {System.out.println("Apple類的無參構(gòu)造執(zhí)行了....");}@Overridepublic void eat() {System.out.println("蘋果");} }class Banana implements Fruit {public Banana() {System.out.println("Banana類的無參構(gòu)造執(zhí)行了....");}@Overridepublic void eat() {System.out.println("香蕉");} }class Factory {public static Fruit getInstance(String className) {Fruit fruit = null;try {fruit = (Fruit) Class.forName(className).newInstance();} catch (Exception e) {e.printStackTrace();}return fruit;} }public class Client {public static void main(String[] args) {Fruit fruit = Factory.getInstance("com.szh.spring.Apple");if (fruit != null) {fruit.eat();}} }6.BeanFactory 和 ApplicationContext有什么區(qū)別?
BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當(dāng)做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
依賴關(guān)系
BeanFactory:是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實(shí)例化,控制bean的生命周期,維護(hù)bean之間的依賴關(guān)系。我們可以稱之為 “低級容器”。
ApplicationContext接口作為BeanFactory的派生,可以稱之為 “高級容器”。除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:
- 繼承MessageSource,因此支持國際化。
- 統(tǒng)一的資源文件訪問方式。
- 提供在監(jiān)聽器中注冊bean的事件。
- 同時(shí)加載多個(gè)配置文件。
- 載入多個(gè)(有繼承關(guān)系)上下文 ,使得每一個(gè)上下文都專注于一個(gè)特定的層次,比如應(yīng)用的web層。
加載方式
BeanFactroy采用的是延遲加載形式來注入Bean的,即只有在使用到某個(gè)Bean時(shí)(調(diào)用getBean()),才對該Bean進(jìn)行加載實(shí)例化。這樣,我們就不能發(fā)現(xiàn)一些存在的Spring的配置問題。如果Bean的某一個(gè)屬性沒有注入,BeanFacotry加載后,直至第一次使用調(diào)用getBean方法才會(huì)拋出異常。
ApplicationContext,它是在容器啟動(dòng)時(shí),一次性創(chuàng)建了所有的Bean。這樣,在容器啟動(dòng)時(shí),我們就可以發(fā)現(xiàn)Spring中存在的配置錯(cuò)誤,這樣有利于檢查所依賴屬性是否注入。ApplicationContext啟動(dòng)后預(yù)載入所有的單實(shí)例Bean,通過預(yù)載入單實(shí)例bean,確保當(dāng)你需要的時(shí)候,你就不用等待,因?yàn)樗鼈円呀?jīng)創(chuàng)建好了。
相對于基本的BeanFactory,ApplicationContext 唯一的不足是占用內(nèi)存空間。當(dāng)應(yīng)用程序配置Bean較多時(shí),程序啟動(dòng)較慢。
創(chuàng)建方式
BeanFactory通常以編程的方式被創(chuàng)建,ApplicationContext還能以聲明的方式創(chuàng)建,如使用ContextLoader。
注冊方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區(qū)別是:BeanFactory需要手動(dòng)注冊,而ApplicationContext則是自動(dòng)注冊。
7.什么是Spring的依賴注入(Dependency Injection)?
依賴注入:相對于IoC而言,依賴注入(DI)更加準(zhǔn)確地描述了IoC的設(shè)計(jì)理念。所謂依賴注入(Dependency Injection),即組件之間的依賴關(guān)系由容器在應(yīng)用系統(tǒng)運(yùn)行期來決定,也就是由容器動(dòng)態(tài)地將某種依賴關(guān)系的目標(biāo)對象實(shí)例注入到應(yīng)用系統(tǒng)中的各個(gè)關(guān)聯(lián)的組件之中。組件不做定位查詢,只提供普通的Java方法,讓容器去決定依賴關(guān)系。
依賴注入是時(shí)下最流行的IoC實(shí)現(xiàn)方式,依賴注入分為接口注入(Interface Injection),Setter方法注入(Setter Injection)和構(gòu)造器注入(Constructor Injection)三種方式。其中接口注入由于在靈活性和易用性比較差,現(xiàn)在從Spring4開始已被廢棄。
構(gòu)造器注入:構(gòu)造器注入是容器通過調(diào)用一個(gè)類的構(gòu)造器來實(shí)現(xiàn)的,該構(gòu)造器有一系列參數(shù),每個(gè)參數(shù)都必須注入。
Setter方法注入:Setter方法注入是容器通過調(diào)用無參構(gòu)造器或無參static工廠方法實(shí)例化bean之后,調(diào)用該bean的setter方法來實(shí)現(xiàn)的依賴注入。
8.什么是Spring AOP?
AOP(Aspect-Oriented Programming),一般稱為面向切面編程,作為面向?qū)ο蟮囊环N補(bǔ)充,用于將那些與業(yè)務(wù)無關(guān),但卻對多個(gè)對象產(chǎn)生影響的公共行為和邏輯,抽取并封裝為一個(gè)可重用的模塊,這個(gè)模塊被命名為“切面”(Aspect),通過面向切面編程減少了系統(tǒng)中的重復(fù)代碼,降低了模塊間的耦合度,同時(shí)提高了系統(tǒng)的可維護(hù)性。常用于權(quán)限認(rèn)證、日志、事務(wù)處理等。
9.Spring AOP 與 AspectJ AOP 有什么區(qū)別?AOP 有哪些實(shí)現(xiàn)方式?
AOP實(shí)現(xiàn)的關(guān)鍵在于代理模式,AOP代理主要分為靜態(tài)代理和動(dòng)態(tài)代理。靜態(tài)代理的代表為AspectJ;動(dòng)態(tài)代理則以Spring AOP為代表。
(1)AspectJ是靜態(tài)代理的增強(qiáng),所謂靜態(tài)代理,就是AOP框架會(huì)在編譯階段生成AOP代理類,因此也稱為編譯時(shí)增強(qiáng),他會(huì)在編譯階段將AspectJ(切面)織入到Java字節(jié)碼中,運(yùn)行的時(shí)候就是增強(qiáng)之后的AOP對象。
(2)Spring AOP使用的動(dòng)態(tài)代理,所謂的動(dòng)態(tài)代理就是說AOP框架不會(huì)去修改字節(jié)碼,而是每次運(yùn)行時(shí)在內(nèi)存中臨時(shí)為方法生成一個(gè)AOP對象,這個(gè)AOP對象包含了目標(biāo)對象的全部方法,并且在特定的切點(diǎn)做了增強(qiáng)處理,并回調(diào)原對象的方法。
10.解釋一下Spring AOP里面的幾個(gè)名詞
切入點(diǎn)定義切入的位置,通知定義切入的時(shí)間。
11.Spring AOP中的通知有哪些類型?
| 前置通知(Before) | 在目標(biāo)方法被執(zhí)行之前調(diào)用通知 | |
| 后置通知(After) | 無論如何都會(huì)在目標(biāo)方法執(zhí)行之后調(diào)用通知 | 記錄日志(方法已經(jīng)調(diào)用,但不一定成功) |
| 最終通知(After-returning ) | 無論目標(biāo)方法是否拋出異常,該增強(qiáng)均會(huì)被執(zhí)行。 | 記錄日志(方法已經(jīng)成功調(diào)用) |
| 異常通知(After-throwing) | 在目標(biāo)方法拋出異常后調(diào)用通知 | 異常處理 |
| 環(huán)繞通知(Around) | 通知包裹了目標(biāo)方法,在目標(biāo)方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為 | 事務(wù)權(quán)限控制 |
12.Spring支持的幾種bean的作用域
當(dāng)定義一個(gè)bean在Spring里,我們還能給這個(gè)bean聲明一個(gè)作用域。它可以通過bean的scope屬性來定義。
Spring框架支持以下五種bean的作用域:
| singleton | 單例模式,在spring IoC容器僅存在一個(gè)Bean實(shí)例,默認(rèn)值 |
| prototype | 原型模式,每次從容器中獲取Bean時(shí),都返回一個(gè)新的實(shí)例,即每次調(diào)用getBean()時(shí),相當(dāng)于執(zhí)行newXxxBean() |
| request | 每次HTTP請求都會(huì)創(chuàng)建一個(gè)新的Bean,該作用域僅在基于web的Spring ApplicationContext環(huán)境下有效 |
| session | 同一個(gè)HTTP Session共享一個(gè)Bean,不同Session使用不同的Bean,該作用域僅在基于web的Spring ApplicationContext環(huán)境下有效 |
| global-session | 同一個(gè)全局的HTTP Session中共享一個(gè)Bean,一般用于Portlet應(yīng)用環(huán)境,該作用域僅在基于web的Spring ApplicationContext環(huán)境下有效 |
因?yàn)榻?jīng)常用到的就是前兩種 singleton、prototype,所以下面通過簡單的代碼案例演示一下。
首先演示當(dāng)Spring Bean的作用域設(shè)置為 默認(rèn)singleton 的情況。依次是實(shí)體類、Spring配置文件、測試方法。
package com.szh.spring;/*** */ public class Book {private String bookName;private String bookAuthor;public void setBookName(String bookName) {this.bookName = bookName;}public void setBookAuthor(String bookAuthor) {this.bookAuthor = bookAuthor;}@Overridepublic String toString() {return "Book{" +"bookName='" + bookName + '\'' +", bookAuthor='" + bookAuthor + '\'' +'}';} } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="book" class="com.szh.spring.Book" scope="singleton"><property name="bookName" value="盜墓筆記"/><property name="bookAuthor" value="南派三叔"/></bean></beans> @Testpublic void testBook() {ApplicationContext context =new ClassPathXmlApplicationContext("bean1.xml");Book book1 = context.getBean("book",Book.class);Book book2 = context.getBean("book",Book.class);System.out.println(book1);System.out.println(book2);System.out.println(book1 == book2);}從上面的輸出結(jié)果中可以看到,在bean的作用域?yàn)?singleton 單例的情況下,通過Spring IoC容器依次拿到的這兩個(gè)對象是一樣的,也就是說此時(shí)容器中僅存在這一個(gè)bean(Book)。
下面再來演示 bean 作用域?yàn)閜rototype的情況。所有測試代碼和上面的一樣,只是將配置文件中 標(biāo)簽中的 scope 屬性修改為 prototype。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="book" class="com.szh.spring.Book" scope="prototype"><property name="bookName" value="盜墓筆記"/><property name="bookAuthor" value="南派三叔"/></bean></beans>這個(gè)時(shí)候,我們可以看到從容器中拿到的這兩個(gè)對象就不一樣了,因?yàn)榇藭r(shí)bean的作用域變成了 prototype 多實(shí)例情況,也就是說容器中可以有多個(gè)Book實(shí)例。
關(guān)于 singleton 和 prototype 的區(qū)別:
設(shè)置 scope 值是 prototype 的時(shí)候,不是在加載 spring 配置文件的時(shí)候創(chuàng)建 對象,而是在調(diào)用getBean 方法時(shí)候創(chuàng)建多實(shí)例對象。
13.解釋一下Spring中bean的生命周期
在傳統(tǒng)的Java應(yīng)用中,bean的生命周期很簡單。使用Java關(guān)鍵字new進(jìn)行bean實(shí)例化,然后該bean就可以使用了。一旦該bean不再被使用,則由Java自動(dòng)進(jìn)行垃圾回收。相比之下,Spring容器中的bean的生命周期就顯得相對復(fù)雜多了。正確理解Spring bean的生命周期非常重要,因?yàn)槟慊蛟S要利用Spring提供的擴(kuò)展點(diǎn)來自定義bean的創(chuàng)建過程。
下圖展示了bean裝載到Spring應(yīng)用上下文中的一個(gè)典型的生命周期過程。
Spring對bean進(jìn)行實(shí)例化;
Spring將值和bean的引用注入到bean對應(yīng)的屬性中;(set方法賦值、引用類型、構(gòu)造器等等)
如果bean實(shí)現(xiàn)了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;
如果bean實(shí)現(xiàn)了BeanFactoryAware接口,Spring將調(diào)用setBeanFactory()方法,將BeanFactory容器實(shí)例傳入;
如果bean實(shí)現(xiàn)了ApplicationContextAware接口,Spring將調(diào)用setApplicationContext()方法,將bean所在的應(yīng)用上下文的引用傳入進(jìn)來;
如果bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們的post-ProcessBeforeInitialization()方法;
如果bean實(shí)現(xiàn)了InitializingBean接口,Spring將調(diào)用它們的after-PropertiesSet()方法。類似地如果bean使用initmethod聲明了初始化方法,該方法也會(huì)被調(diào)用;
此時(shí),bean已經(jīng)準(zhǔn)備就緒,可以被應(yīng)用程序使用了,它們將一直駐留在應(yīng)用上下文中,直到該應(yīng)用上下文被銷毀;
如果bean實(shí)現(xiàn)了DisposableBean接口,Spring將調(diào)用它的destroy()接口方法。同樣,如果bean使用destroy-method聲明了銷毀方法,該方法也會(huì)被調(diào)用。
下面簡單演示一下Spring Bean的生命周期:👇👇👇
package com.szh.spring.bean;/****/ public class Orders {private String name;public Orders() {System.out.println("第一步: 執(zhí)行無參構(gòu)造創(chuàng)建bean實(shí)例");}public void setName(String name) {this.name = name;System.out.println("第二步: 調(diào)用set方法設(shè)置屬性值");}//創(chuàng)建執(zhí)行的初始化的方法public void initMethod() {System.out.println("第三步: 執(zhí)行bean初始化的方法");}//創(chuàng)建執(zhí)行的銷毀的方法public void destroyMethod() {System.out.println("第五步: 執(zhí)行bean銷毀的方法");}} package com.szh.spring.bean;import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;/****/ public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之前執(zhí)行的方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之后執(zhí)行的方法");return bean;} } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="orders" class="com.szh.spring.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"><property name="name" value="手機(jī)"/></bean><!-- 配置后置處理器 --><bean id="myBeanPost" class="com.szh.spring.bean.MyBeanPost"/></beans> @Testpublic void testBean() { // ApplicationContext context = // new ClassPathXmlApplicationContext("bean2.xml");ClassPathXmlApplicationContext context =new ClassPathXmlApplicationContext("bean2.xml");Orders orders = context.getBean("orders",Orders.class);System.out.println("第四步: 獲取創(chuàng)建好的bean實(shí)例對象 ---> " + orders);//手動(dòng)讓bean實(shí)例銷毀context.close();}bean 生命周期有七步
14.Spring支持的事務(wù)管理類型, Spring事務(wù)實(shí)現(xiàn)方式有哪些?你更傾向用哪種事務(wù)管理類型?
Spring事務(wù)的本質(zhì)其實(shí)就是數(shù)據(jù)庫對事務(wù)的支持,沒有數(shù)據(jù)庫的事務(wù)支持,spring是無法提供事務(wù)功能的。真正的數(shù)據(jù)庫層的事務(wù)提交和回滾是通過bin log或者redo log實(shí)現(xiàn)的。
Spring支持兩種類型的事務(wù)管理:
編程式事務(wù)管理:通過編程的方式管理事務(wù),靈活性好,但是難維護(hù)。
聲明式事務(wù)管理:將業(yè)務(wù)代碼和事務(wù)管理分離,只需用注解和XML配置來管理事務(wù)。
大多數(shù)情況下選擇聲明式事務(wù)管理,雖然比編程式事務(wù)管理少了一點(diǎn)靈活性,最細(xì)粒度只能作用到方法級別,無法做到像編程式事務(wù)那樣可以作用到代碼塊級別,但是聲明式事務(wù)管理對應(yīng)用代碼的影響最小,更符合一個(gè)無侵入的輕量級容器的思想,具有更好的可維護(hù)性。
15.什么是Spring事務(wù)的傳播行為?
spring事務(wù)的傳播行為說的是,當(dāng)多個(gè)事務(wù)同時(shí)存在的時(shí)候,spring如何處理這些事務(wù)的行為。
16.什么是Spring事務(wù)的隔離級別?
spring 有五大隔離級別,默認(rèn)值為 ISOLATION_DEFAULT(使用數(shù)據(jù)庫的設(shè)置),其他四個(gè)隔離級別和數(shù)據(jù)庫的隔離級別一致:
總結(jié)
以上是生活随笔為你收集整理的Java面试——Spring系列总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java计算一个多边形的重心_2D凸多边
- 下一篇: C/C++关键字 static 和 co