參考:
SpringMVC
1、什么是Spring MVC ?簡單介紹下你對springMVC的理解?
2、MVC 和 服務端的三層架構
三層架構 與MVC的區別
3、SpringMVC的流程?
4、Spring MVC的主要組件?
5、SpringMvc的控制器是不是單例模式,如果是,有什么問題,怎么解決?
答:是單例模式,全局只有一份,所以可能會存在線程爭用的問題,如果有成員變量就會有線程安全的問題。
第一個解決辦法
不在控制器中寫成員變量。如果用加鎖來解決則會影響性能
解釋:為什么任何一個類只要沒有成員變量,就是線程安全的,其實是因為成員變量逃逸到了其他線程。
因為成員方法是每個線程私有的,而我們常說的線程安全問題就是我們通過成員方法訪問了成員變量,從而造成了線程之間成員變量狀態不一致的問題,所以只要沒有成員變量,就不會有不一致問題,從而也就不會有線程安全問題。
至於為什么訪問了成員變量就會有線程安全問題: 是因為成員變量的對象分配是在堆內存中的,所以是為所有線程所共享的,所以可能會被多個線程同時訪問,從而造成線程不安全。也可以說是成員變量逃逸到了其他線程,導致線程不安全。
第二個解決辦法
如果這個成員變量只是線程私有的,可以把它放到ThreadLocal中,這樣可以使得每個線程訪問自己的成員變量,沒有公共變量就沒有線程安全的問題。關於ThreadLocal的知識可以閱讀《ThreadLocal原理,內存泄漏問題,怎么解決》
6、怎樣在方法里面得到Request,或者Session?
答:直接在方法的形參中聲明request,SpringMvc就自動把request對象傳入。
7、如果想在攔截的方法里面得到從前台傳入的參數,怎么得到?
答:直接在形參里面聲明這個參數就可以,但必須名字和傳過來的參數一樣。
8、如果前台有很多個參數傳入,並且這些參數都是一個對象的,那么怎么樣快速得到這個對象?
答:直接在方法中聲明這個對象,SpringMvc就自動會把屬性封裝賦值到這個對象里面。
9、轉發和重定向
Spring
1、Spring是什么?
Spring是一個為Java應用程序提供基礎性服務的輕量級IoC和AOP容器框架,目的是用於簡化企業應用程序的開發,它使得開發者只需要關心業務需求。常見的配置方式有兩種:基於XML的配置、基於注解的配置。現在非常熱門的SpringBoot就是在Spring框架的基礎上做了再封裝,簡化了很多配置文件,更加方便了用戶的使用。
2、Spring的主要模塊組成
Spring Core:核心類庫,提供IOC服務;
Spring Context:提供框架式的Bean訪問方式,以及企業級功能(JNDI、定時任務等);
Spring AOP:AOP服務;
Spring DAO:對JDBC的抽象,簡化了數據訪問異常的處理;
Spring ORM:對現有的ORM框架的支持;
Spring Web:提供了基本的面向Web的綜合特性,例如多方文件上傳;
Spring MVC:提供面向Web應用的Model-View-Controller實現。
Spring Test : 提供了對 JUnit 和 TestNG 測試的支持。
Spring JMS :Java消息服務。
3、Spring 的優點?
(1)spring屬於低侵入式設計,代碼的污染極低;
(2)spring的 DI 機制將對象之間的依賴關系交由框架處理,減低組件的耦合性;
(3)Spring提供了AOP技術,支持將一些通用任務,如安全、事務、日志、權限等進行集中式管理,從而提供更好的復用。
(4)spring對於主流的應用框架提供了集成支持。
擴展:侵入式和非侵入式設計
侵入式的做法就是要求用戶代察覺到框架的代碼,表現為用戶代碼需要繼承框架提供的類。非侵入式則不需要用戶代碼引入框架代碼的信息,從類的編寫者角度來看,察覺不到框架的存在。
例如:
使用struts的時候,需要繼承一些struts的類,這時struts侵入到了我們的代碼里。
使用spring,編寫一些業務類的時候不需要繼承spring特定的類,通過配置完成依賴注入后就可以使用,此時,spring就沒有侵入到我業務類的代碼里。
侵入式讓用戶代碼產生對框架的依賴,這些代碼不能在框架外使用,不利於代碼的復用。但侵入式可以使用戶跟框架更好的結合,更容易更充分的利用框架提供的功能。
非侵入式的代碼則沒有過多的依賴,可以很方便的遷移到其他地方。但是與用戶代碼互動的方式可能就比較復雜。
4、Spring的AOP理解:
OOP面向對象,允許開發者定義縱向的關系,但並不適用於定義橫向的關系,導致了大量代碼的重復,而不利於各個模塊的重用。
AOP,一般稱為面向切面,作為面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行為和邏輯,抽取並封裝為一個可重用的模塊,這個模塊被命名為“切面”(Aspect),減少系統中的重復代碼,降低了模塊間的耦合度,同時提高了系統的可維護性。可用於權限認證、日志、事務處理。
(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是每次運行時在內存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法。
擴展:動態代理
①JDK動態代理只提供接口的代理,不支持類的代理。核心InvocationHandler接口和Proxy類,InvocationHandler 通過invoke()方法反射來調用目標類中的代碼,動態地將橫切邏輯和業務編織在一起;接着,Proxy利用 InvocationHandler動態創建一個符合某一接口的的實例, 生成目標類的代理對象。(是spring AOP的默認實現方式)
②如果代理類沒有實現 InvocationHandler 接口,那么Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成指定類的一個子類對象,並覆蓋其中特定方法並添加增強代碼,從而實現AOP。CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態代理的。
5、Spring的IOC和 DI 理解:
(1)IOC就是控制反轉,是指創建對象的控制權的轉移,以前創建對象的主動權和時機是由程序自己控制的,而現在這種權力轉移到Spring容器中,由容器根據配置文件去創建實例和管理各個實例之間的依賴關系,而且程序只能從容器中獲取對象。這樣可以降低對象與對象之間耦合度,也利於功能的復用。DI依賴注入,和控制反轉是同一個概念的不同角度的描述,即 應用程序在運行時依賴IoC容器來動態注入對象需要的外部資源。Spring 采用依賴注入的方式實現了IOC思想。反過來,IOC其實是依賴 DI 來實現的,所以IOC和DI的關系非常緊密。
(2)最直觀的表達就是,IOC讓對象的創建不用程序去new了,可以由spring自動生產,使用java的反射機制,根據配置文件在運行時動態的去創建對象以及管理對象,並調用對象的方法的。
(3)Spring的IOC有三種注入方式 :構造器注入、setter方法注入、根據注解注入。
IOC讓相互協作的組件保持松散的耦合,而AOP編程允許你把遍布於應用各層的功能分離出來形成可重用的功能組件。
6、解釋Spring支持的幾種bean的作用域
Spring容器中的bean可以分為5個范圍:
(1)singleton:默認,容器中只有一個bean的實例,單例的模式由BeanFactory自身來維護。使用了單例設計模式。
(2)prototype:容器中存在多個實例,每次獲取該 bean 時,都會獲取一個新實例。使用了原型設計模式。
(3)request:為每一個網絡請求創建一個實例,在請求完成以后,bean會失效並被垃圾回收器回收。
(4)session:與request范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效。
(5)global-session:為全局的session創建一個實例,僅在基於portlet的web應用中才有意義,Spring5 已經沒有了。Portlet是能夠生成語義代碼(例如:HTML)片段的小型Java Web插件。它們基於portlet容器,可以像servlet一樣處理HTTP請求。但是,與 servlet 不同,每個 portlet 都有不同的會話。
(6)application: 為整個web應用創建一個實例。
7、Spring框架中的單例Bean是線程安全的么?
Spring框架並沒有對單例bean進行任何多線程的封裝處理。關於單例bean的線程安全和並發問題需要開發者自行去搞定。但實際上,大部分的Spring bean並沒有可變的狀態,因為我們方法中並不會對這個單例對象賦值或者修改這個對象的屬性值。所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀態的話(比如 View Model 對象),就需要自行保證線程安全。最淺顯的解決辦法就是將多態bean的作用域由“singleton”變更為“prototype”。
8、@Component 和 @Bean 的區別是什么?
- 作用對象不同: @Component 注解作用於類,而@Bean注解作用於方法。
- @Component通常是通過類路徑掃描來自動偵測以及自動裝配到Spring容器中(我們可以使用 @ComponentScan 注解定義要掃描的路徑從中找出標識了需要裝配的類自動裝配到 Spring 的 bean 容器中)。@Bean 注解通常是我們在標有該注解的方法中定義產生這個 bean,@Bean把方法的返回值類放入spring 容器。
- @Bean 注解比 Component 注解的自定義性更強,而且很多地方我們只能通過 @Bean 注解來注冊bean。比如當我們引用第三方庫中的類需要裝配到 Spring容器時,則只能通過 @Bean來實現。
9、將一個類聲明為Spring的 bean 的注解有哪些?
我們一般使用 @Autowired 注解自動裝配 bean,要想把類標識成可用於 @Autowired 注解自動裝配的 bean 的類,采用以下注解可實現:
- @Component :通用的注解,可標注任意類為 Spring 組件。如果一個Bean不知道屬於哪個層,可以使用@Component 注解標注。
- @Repository : 對應持久層即 Dao 層,主要用於數據庫相關操作。
- @Service : 對應服務層,主要涉及一些復雜的邏輯,需要用到 Dao層。
- @Controller : 對應 Spring MVC 控制層,主要用於接受用戶請求並調用 Service 層返回數據給前端頁面。
10、請解釋Spring Bean的生命周期?
首先說一下Servlet的生命周期:實例化,初始init,接收請求service,銷毀destroy;
Spring上下文中的Bean生命周期也類似,如下:
(1)實例化Bean:
對於BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調用createBean進行實例化。對於ApplicationContext容器,當容器啟動結束后,通過獲取BeanDefinition對象中的信息,實例化所有的bean。
(2)設置對象屬性(依賴注入):
實例化后的對象被封裝在BeanWrapper對象中,緊接着,Spring根據BeanDefinition中的信息 以及 通過BeanWrapper提供的設置屬性的接口完成依賴注入。
(3)處理Aware接口:
接着,Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例注入給Bean:
①如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的就是Spring配置文件中Bean的id值;
②如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。
③如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;
(4)BeanPostProcessor:
如果想對Bean進行一些自定義的處理,那么可以讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。比如實現一些AOP邏輯。
(5)InitializingBean 與 init-method:
如果Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法。
(6)如果這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;由於這個方法是在Bean初始化結束時調用的,所以可以被應用於內存或緩存技術;
以上幾個步驟完成后,Bean就已經被正確創建了,之后就可以使用這個Bean了。
(7)DisposableBean:
當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用其實現的destroy()方法;
(8)destroy-method:
最后,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷毀方法。
11、Spring如何處理線程並發問題?
在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因為Spring對一些Bean中非線程安全狀態采用ThreadLocal進行處理,解決線程安全問題。
ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。同步機制采用了“時間換空間”的方式,僅提供一份變量,不同的線程在訪問前需要獲取鎖,沒獲得鎖的線程則需要排隊。而ThreadLocal采用了“空間換時間”的方式。
ThreadLocal會為每一個線程保存各自需要的變量,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。
比如spring就把connection放入了threadlocal, 避免的threadlocal的並發爭用問題。
ThreadLocal的知識可以閱讀《ThreadLocal原理,內存泄漏問題,怎么解決》
12、Spring基於xml注入bean的幾種方式:
(1)Set方法注入;
(2)構造器注入:①通過index設置參數的位置;②通過type設置參數類型;
(3)靜態工廠注入;
(4)實例工廠;
詳細內容可以閱讀:https://blog.csdn.net/a745233700/article/details/89307518
13、Spring的自動裝配:
在spring中,對象無需自己查找或創建與其關聯的其他對象,由容器負責把需要相互協作的對象引用賦予各個對象,使用autowire來配置自動裝載模式。
在Spring框架xml配置中共有5種自動裝配:
(1)no:默認的方式是不進行自動裝配的,通過手工設置ref屬性來進行裝配bean。
(2)byName:通過bean的名稱進行自動裝配,如果一個bean的 property 與另一bean 的name 相同,就進行自動裝配。
(3)byType:通過參數的數據類型進行自動裝配。
(4)constructor:利用構造函數進行裝配,並且構造函數的參數通過byType進行裝配。
(5)autodetect:自動探測,如果有構造方法,通過 construct的方式自動裝配,否則使用 byType的方式自動裝配。
基於注解的方式:
使用@Autowired注解來自動裝配指定的bean。在使用@Autowired注解之前需要在Spring配置文件進行配置,<context:annotation-config />。在啟動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找需要的bean,並裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:
如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的數據;
如果查詢的結果不止一個,那么@Autowired會根據名稱來查找;
如果上述查找的結果為空,那么會拋出異常。解決方法時,使用required=false。
@Autowired可用於:構造函數、成員變量、Setter方法
注:@Autowired和@Resource之間的區別
(1) @Autowired默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在(可以設置它required屬性為false)。
(2) @Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean才會按照類型來裝配注入。
14、Spring 框架中都用到了哪些設計模式?
(1)工廠模式:BeanFactory就是簡單工廠模式的體現,用來創建對象的實例;
(2)單例模式:Bean默認為單例模式。
(3)原型模式:如果選擇了bean實例為protype則在需要使用bean實例時會使用原型模式快速創建bean實例。
(4)代理模式:Spring的AOP功能用到了JDK的動態代理和CGLIB字節碼生成技術;
(5)模板模式:用來解決代碼重復的問題。比如. TymeleafTemplate, RedisTemplate, ElasticTemplat,RestTemplate, JmsTemplate, JpaTemplate,等等。
(6)觀察者模式:定義對象間一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都會得到通知被制動更新,如Spring中listener的實現--ApplicationListener。
(7)委派模式:Spring 提供了 DispatcherServlet 來對請求進行分發。
(8)適配器模式 :Spring AOP 的增強或通知(Advice)使用到了適配器模式、spring MVC 中也是用到了適配器模式適配Controller。
Spring 事務
1、Spring 管理事務的方式有幾種?
- 編程式事務,在代碼中硬編碼。(不推薦使用)
- 聲明式事務,在配置文件中配置(推薦使用)
聲明式事務又分為兩種:
- 基於XML的聲明式事務
- 基於注解的聲明式事務
2、Spring 事務中的隔離級別有哪幾種?
- TransactionDefinition.ISOLATION_DEFAULT: 使用后端數據庫默認的隔離級別,Mysql 默認采用的 REPEATABLE_READ隔離級別 Oracle 默認采用的 READ_COMMITTED隔離級別.
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:未提交讀
- TransactionDefinition.ISOLATION_READ_COMMITTED:提交讀
- TransactionDefinition.ISOLATION_REPEATABLE_READ: 可重復讀
- TransactionDefinition.ISOLATION_SERIALIZABLE: 可序列化
3、Spring 事務的傳播行為
事務傳播行為(propagation behavior)指的就是當一個事務方法被另一個事務方法調用時,這個事務方法應該如何進行。
例如:methodA事務方法調用methodB事務方法時,methodB是繼續在調用者methodA的事務中運行呢,還是為自己開啟一個新事務運行,這就是由methodB的事務傳播行為決定的。
Spring定義了七種傳播行為:
- PROPAGATION_ _REQUIRED: 表示當前methodB方法必須運行在事務中。如果調用方methodA存在事務,mothodB方法將會在methodA事務中運行。否則,會啟動一個新的事務
- PROPAGATION_ SUPPORTS:表示當前方法不需要事務上下文, 但是如果調用方methodA存在事務的話,那么該方法會在這個事務中運行
- PROPAGATION_ MANDATORY: 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常。
- PROPAGATION_ REQUIRED_ NEW:表示當前方法必須運行在它自己的事務中。一個新的事務將被啟動。如果存在當前事務,在該方法執行期間.當前事務會被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager
- PROPAGATION_ NOT_ SUPPORTED:表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。如果使用JTATransactionManager的話 ,則需要訪問TransactionManager。
- PROPAGATION_ NEVER:表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常
- PROPAGATION_ NESTED:表示如果當前已經存在一 個事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立於當前事務進行單獨地提交或回滾。如果當前事務不存在,那么其行為與PROPAGATION_ REQUIRED- 樣。注意各廠商對這種傳播行為的支持是有所差異的。可以參考資源管理器的文檔來確認它們是否支持嵌套事務
4、@Transactional(rollbackFor = Exception.class)注解了解嗎?
我們知道:Exception分為運行時異常RuntimeException和非運行時異常。事務管理對於企業應用來說是至關重要的,即使出現異常情況,它也可以保證數據的一致性。
當@Transactional注解作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標注來覆蓋類級別的定義。如果類或者方法加了這個注解,那么這個類里面的方法拋出異常,就會回滾,數據庫里面的數據也會回滾。
在@Transactional注解中如果不配置rollbackFor屬性,那么事務只會在遇到RuntimeException的時候才會回滾,加上rollbackFor=Exception.class,可以讓事務在遇到非運行時異常時也回滾。
關於 @Transactional 注解推薦閱讀的文章:
MyBatis
1、什么是Mybatis?
ORM是什么
即 Object-Relationl Mapping 它的作用是在關系型數據庫和對象之間作一個映射,這樣,我們在具體的操作數據庫的時候,就不需要再去和復雜的SQL語句打交道。只要提供了持久化類與表的映射關系,ORM框架在運行時就能參照映射文件的信息,把對象持久化到數據庫中
2、Mybaits的優點:
3、MyBatis框架的缺點:
4、MyBatis框架適用場合:
5、MyBatis與Hibernate有哪些不同?
6、#{}和${}的區別是什么?
7、為什么說Mybatis是半自動ORM映射工具?它與全自動的區別在哪里?
Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,可以根據對象關系模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,需要手動編寫sql來完成,所以,稱之為半自動ORM映射工具。
8、當實體類中的屬性名和表中的字段名不一樣 ,怎么辦 ?
第1種: 通過在查詢的sql語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致。
第2種: 通過<resultMap>來映射字段名和實體類屬性名的一一對應的關系。
9、Mybatis是如何進行分頁的?分頁插件的原理是什么?
Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁。可以在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可以使用分頁插件來完成物理分頁。
分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,然后重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數