Spring是一個全面的全面的、企業應用開發一站式的解決方案,貫穿表現層、業務層、持久層。但是 Spring 仍然可以和其他的框架無縫整合。
1、Spring的核心組件
(1)數據層: JDBC、ORM、OXM、JMS、Transations
(2)Web層: Web、Servlet、Portlet、Struts
(3)中間層: AOP、Aspects、Instrumentation
(4)核心容器: Beans、Core、Context、Expression Language
(5)測試層: Test
2、Spring IOC 原理
(1)概念: Spring通過一個配置文件描述Bean及Bean之間的依賴關系,利用Java語言的反射功能實例化 Bean并建立Bean之間的依賴關系。Spring的IOC容器在完成這些底層工作的基礎上,還提供 了 Bean實例緩存、生命周期管理、Bean實例代理、事件發布、資源裝載等高級服務。
(2)Spring容器高層視圖
- Spring啟動時讀取應用程序提供的Bean配置信息,并在Spring容器中生成一份相應的Bean配置注冊表
- 根據這張注冊表實例化Bean,并將Bean實例存入Bean緩存池
- 應用程序讀取Bean緩存池中的Bean實例
(3)IOC容器實現
IOC容器依賴于BeanFactory,是Spring框架的基礎程序,所以開發者操作的是ApplicationContext而非底層的BeanFactory。
Bean注冊表
首先,Spring配置文件中的每一個節點元素在Spring容器中都通過一個 BeanDefinition 對象表示,它表述了 Bean 的配置信息,而BeanDefinitionRegistry 接口提供了向容器手動注冊 BeanDefinition 對象的方法。
獲取Bean實例對象
BeanFactory 提供的最主要方法就是getBean(String beanName)
方法,調用該方法能從容器中返回一個特定名稱的Bean。
訪問容器中關于Bean的基本信息——ListableBeanFactory
BeanFactory 的子類 ListableBeanFactory,提供了訪問容器內關于Bean 的基本信息,如Bean的個數,獲取某一類型Bean的配置名、查看容器中是否包含某一Bean等方法。
父子級容器——HierarchicalBeanFactory
父子級聯IOC容器實現的接口是HierarchicalBeanFactory
,子容器可以通過接口方法訪問父容器,由此建立的IOC級聯容器體系中,子容器可以訪問父容器,而父容器無法訪問子容器。
Spring利用父子級聯容器實現了很多功能,例如 SpringMVC中,View層的Bean位于一個子容器中,而Service層和Dao層的Bean位于父容器中,這樣View層的Bean就可以引用Service層和Dao層的Bean了
拓展接口 —— ConfigurableBeanFactory
這是一個BeanFactory子類系列十分重要的接口,它增強了IOC的可定制性,它定義了設置類加載器、屬性編輯器、容器初始化后置處理器等方法
自動裝配——AutowireCapableBeanFactory
這個接口定義了容器中的Bean按某種規則(如按名字匹配、按類型匹配等)進行自動裝配的方法。
注冊單例Bean——SingletonBeanRegistry
這個接口定義了允許在運行期間向容器注冊單例Bean的方法。
對于單例Bean對象來說,BeanFactory會緩存Bean實例,所以第二次調用getBean()獲取Bean對象時會直接從IOC容器的緩存中獲取Bean實例。
Spring 在 DefaultSingletenBeanFactory 類中提供了用于緩存單例Bean 緩存器,這個緩存器使用HashMap實現,單例Bena以beanName作為key進行存儲。
BeanFactory依賴日志框架
在初始化 BeanFactory 時,必須提供一種日志框架,例如使用Log4j,這樣啟動Spring容器時才不會報錯。
BeanFactory提供給開發者的操作類——ApplicationContext
ApplicationContext 繼承于 HierarchicalBeanFactory 和 ListableBeanFactory 接口,并由此拓展出其它功能接口:
- ClassPathXmlApplicationContext: 默認從類路徑加載配置文件
- FileSystemXmlApplicationContext: 默認從文件系統中裝載配置文件
- ApplicationEventPublisher: 讓容器擁有發布應用上下文事件的功能,包括啟動容器事件、關閉容器事件等
- MessageSource: 為應用提供 il8n 國際化消息訪問的功能
- ResourcePatternResolver: 通過帶前綴的Ant風格的資源文件路徑裝載Spring配置條件
- LifeCycle: 這個接口是Spring 2.0 時加入的,提供了start 和 stop 方法,主要用來控制異步處理過程,在具體使用中,該接口會被ApplicaitonContext和Bean實例同時實現,ApplicationContext 會將 start 和 stop 狀態發布給所有實現了接口的Bean,以達到管理和控制JMX、任務調度的目的
- ConfigurableApplicationContext: 擴展了ApplicationContext,主要是新增了兩個方法:refresh() 和 close(),讓ApplicationContext擁有了啟動、刷新、關閉應用上下文的功能。
WebApplicationContext
WebApplicationContext是專門為Web應用準備的,它允許從相對于Web根目錄的路徑中裝載配置文件完成初始化工作,從WebApplicationContext中可以獲得ServletContext的引用,整個Web應用上下文對象將作為屬性放置到ServletContext 中,以便Web應用環境可以訪問Spring應用上下文。
(4)Spring Bean的作用域
Spring 3.0 定義了五種Bean的作用域:單例、原型、請求、會話、全局會話
- singleton(單例模式,多線程不安全): Spring IOC容器只存在一個共享的 Bean 實例,無論有多少個 Bean 引用它,始終指向同一個對象,但這種模式在多線程環境下是不安全的。
- prototype(原型模式): Spring 每一次嘗試獲取原型模式的Bean對象時,容器都將創建一個新的Bean提供給Spring。
- request(請求模式): 一次HTTP請求,Spring創建一次新的Bean提供使用,其生命周期隨請求狀態的銷毀而銷毀。
- session(會話模式): 一次Http Session 中,容器返回的是同一個實例,當重新開啟一次Http Session,容器會重新創建一個Bean實例提供使用,請求結束,實例銷毀。
- global session(全局會話模式): 在一個全局Http Session中,容器返回同一個Bean實例,僅在protlet context時使用。
(5)Spring Bean的生命周期
SpringBean的生命周期:實例化 —— 屬性賦值 —— 初始化 —— 銷毀
實例化: 實例化一個Bean,也就是我們常說的new
屬性賦值
- IOC 依賴注入: 按照Spring Context對Bean實例進行配置
- setBeanName的實現: 若Bean實現了
BeanNameAware
接口,調用setBeanName(String beanId)
方法 - setBeanFactory的實現: 若Bean實現了
BeanFactoryAware
接口,調用setBeanFactory(BeanFacrtory beanFactory)
方法 - setApplicationContext的實現: 若Bean實現了
ApplicationContextAware
接口,調用setApplicationContext(ApplicationContext applicationContext)
方法,可以實現設置BeanFactory方法,并比BeanFactoryAware更加優秀 - postProcessBeforelnitialization的實現: 若Bean實現了
BeanPostProcessor
接口,將調用postProcessBeforelnitialization(Object obj, String s)
方法,BeanPostProcessor經常用于Bean內容的修改,并且Bean初始化結束后也會調用這個方法,也可以應用于內存或緩存技術。
初始化
- init-method: 若Bean在配置文件中定義了初始化方法,則在初始化階段會自動調用配置的初始化方法。
- postProcessAfterInitialization的實現: 若Bean實現了
BeanPostProcessor
接口,調用postProcessAfterInitialization(Object obj, String s)
方法。
銷毀
- destroy 過期自動清理階段: 當Bean不再需要時,會經歷清理階段,若 Bean 實現了 DisposableBean 接口,則調用
destroy()
方法進行銷毀。 - destroy-method 自配置清理: 若Bean的配置文件中設置了destroy方法時,則自動調用自定義的destroy方法
(6)Spring 依賴注入的方式
Spring 提供的依賴注入的方式:構造器注入、set方法注入、靜態工廠注入、實例工廠注入
構造器注入案例
public CatDaoImpl(String message){this.message = message;
}<bean id="CatDaoImpl" class="class.CatDaoImpl"><constructor-arg value="message"></constructor-arg>
</bean>
setter方法注入
public class Id{private int id;public int getId(){return id;}public void setId(int id){this.id = id;}
}<bean id="id" class="com.Id"><property name="id" value="123"></property>
</bean>
靜態工廠注入
// 對外提供的靜態工廠
public class DaoFactory{public static final FactoryDao getStaticFactoryDaoImpl(){return new StaticFactoryDaoImpl;}
}//使用靜態工廠的類
public class SpringAction{//注入對象private DaoFactory staticFactoryDao;//注入對象的set方法public void setStaticFactoryDao(FactoryDao staticFactoryDao){this.staticFactoryDao = staticFactoryDao;}
}//給調用類注入靜態工廠
<bean name="springAction" class="com.SpringAction"><property name="staticFactoryDao" ref="staticFatoryDao"></property>
</bean>//給靜態工廠中的成員注入
<bean name="staticFatoryDao" class="com.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
實例工廠注入
//創建一個實例工廠
public class DaoFactory{public DaoFactory getFactoryDaoImpl(){return new FactoryDaoImpl(); }
}//調用類使用實例工廠
public class SpringAction{private DaoFactory daoFactory;public void setDaoFactory(DaoFactory daoFactory){this.daoFactory = daoFactory;}
}//為調用類注入實例工廠Bean對象
<bean name="springAction" class="SpringAction"><property name="daoFactory" ref="daoFactory"></property>
</bean>//管理實例工廠,先聲明注入的類,再配置實例工廠的成員
<bean name="daoFactory" class="com.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
(7)自動裝配的實現方式
Spring裝配包括手動裝配和自動裝配,手動裝配是基于 xml 裝配、構造方法、setter方法等。
自動裝配一共有5種實現方式:
- no: 默認不自動裝配,通過顯式的 ref 屬性進行裝配
- byName: 通過參數名自動裝配,Spring在配置文件中檢測到Autowired屬性被設置為byName,容器自動按照beanName進行注入
- byType: 通過參數類型自動裝配,Spring在配置文件中檢測到Autowired屬性被設置為byType,容器自動按照type進行注入,若有多個匹配對象,則拋出錯誤
- constructor: 類似于byType,但必須提供構造器參數,若沒有確定參數的構造器參數類型,則拋出異常
- autodetect: 首先嘗試使用 構造器參數 裝配,若無法工作則使用byType方式
3、Spring AOP 的原理
(1)概念: AOP是一種“橫切”技術,將多個類的公共模塊抽取到一個模塊中,并將其命名為**“Aspect”**,即切面。
(2)AOP的兩個部分: 核心關注點、橫切關注點
- 核心關注點: 業務處理的主要流程
- 橫切關注點: 一切與業務代碼無相關的代碼
(3)AOP的應用場景:
- Authentication: 權限
- Caching: 緩存
- Context passing: 內容傳遞
- Error handling: 錯誤處理
- Lazy loading: 懶加載
- Debugging: 調試
- logging, tracing, profiling and monitoring: 記錄跟蹤 優化 校準
- Performance optimization: 性能優化
- Persistence: 持久化
- Resource pooling: 資源池
- Synchronization: 同步
- Transactions: 事務
(4)AOP的核心概念:
- 切面(Aspect): 類是對物體特征的抽象,切面是對橫切關注點的抽象
- 橫切關注點: 對哪些對象進行攔截、如何處理,這些關注點都是橫切關注點
- 連接點(JoinPoint): 被攔截到的點,因為Spirng只支持方法類型的連接點,所以Spirng中連接點就是被攔截方法,實際上連接點還可以是字段、構造方法
- 切入點(PointCut): 對連接點進行攔截的定義
- 通知(Advice): 所謂的通知就是攔截到連接點后要執行的代碼,分為前置、后置、異常、最終、環繞通知等類型
- 目標對象: 代理的目標對象
- 織入(weave): 將切面應用到目標對象并導致代理對象創建的過程
- 引入(introduction): 不修改代碼的前提下,引入可以在運行期為類動態地添加一些方法或字段
(5)AOP的代理方式
Spring 提供了兩種AOP的代理方式:JDK接口動態代理、CGLib動態代理
JDK接口動態代理:
- 被代理類實現
InvocationHandler
,通過實現該接口定義橫切邏輯,并通過反射機制調用目標類的代碼,動態地將橫切邏輯和業務邏輯編織在一起 - 代理類通過
InvocationHandler
接口動態創建一個實例,生成目標類的代理對象
GCLib動態代理:
GCLib的全稱是Code Generation Library,是一個高性能、高質量的代碼生成類庫,可以在運行期間動態擴展Java類和實現Java接口,CGLib封裝了ASM,可以在運行期間生成新的class,對比JDK動態代理,CGLib可以動態代理未實現接口的類。
(6)AOP的實現原理
@Aspect
public class TransactionDemo {@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))") public void point(){}@Before(value="point()")public void before(){System.out.println("transaction begin");}@AfterReturning(value = "point()")public void after(){System.out.println("transaction commit");}@Around("point()")public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("transaction begin");joinPoint.proceed();System.out.println("transaction commit");}
}
4、Spring MVC 的原理
MVC指的是Modal(模型),View(視圖),Controller(控制器),Spring MVC框架是圍繞 DispatcherServlet 而設計的,這個Servlet會將請求分發到各個控制器,并支持可配置的處理器映射、視圖渲染、本地化、時區與主題渲染等,甚至還能支持文件上傳。
(1)瀏覽器請求的全過程:
- 瀏覽器發送HTTP請求,DispatcherServlet接收
- DispatcherServlet輪詢處理器,通過HandlerMapping進行查找適用的Controller
- 當HandlerMapping查找到處理器后,DispatcherServlet調用處理器,將請求發送給Controller
- Controller調用Service層業務邏輯,獲取返回值后分發到ModalAndView對象
- DispatcherServlet監聽ModalAndView響應結果
- DispatcherServlet得到結果后分發給Model對象,并輪詢視圖映射ViewResolver,查找到指定的視圖
- Modal將結果反應到視圖,View向瀏覽器發送響應體
(2)MVC常用注解
組件注解: @Controller、@RestController、@Component、@Repository、@Service
請求注解: @RequestMapping、@Autowired、@PathVariable、@RequestParam、@RequestHeader
5、MyBatis緩存
MyBatis擁有兩級緩存,默認情況下開啟一級緩存,二級緩存由開發者手動開啟。
一級緩存是會話級別的緩存,當同一會話調用同一個SQL時,優先從緩存中讀取數據。
二級緩存是映射級別的緩存,不同的SQL會話可以共享該緩存
(1)一級緩存的原理
當用戶線程第一次發出查詢sql,sql的查詢結果會寫入到sqlSession的一級緩存中,緩存使用的是Map結構,其中key = mapperID + offset + limit + SQL + 所有入參,value = 用戶信息
,當同一個sqlSession再次發出同一個sql請求,就從緩存中取出數據,若兩次查詢中間發生更新操作,則本sqlSession中的一級緩存區域全部清空,所以第二次請求會從數據庫中查詢,并寫入到新的緩存中去。
(2)二級緩存的原理
二級緩存的范圍是mapper同命名空間的mapper,mapper以命名空間為單位創建緩存數據結構,結構是 map,通過 CacheExecutor 實現的。
CacheExecutor是Executor的代理對象,所有的查詢操作,在CacheExecutor都會先查詢緩存,再查詢數據庫。
(3)如何配置二級緩存
- MyBatis 全局配置中啟用二級緩存配置
- 對應的mapper配置cache節點
- 對應的select查詢節點添加useCache=true