查看更多寶典,請點擊《金三銀四,你的專屬面試寶典》html
Spring容器是Spring的核心,一切Spring bean都存儲在Spring容器內,並由其經過IoC技術管理。Spring容器也就是一個bean工廠(BeanFactory)。應用中bean的實例化,獲取,銷燬等都是由這個bean工廠管理的。java
org.springframework.context.ApplicationContext接口用於完成容器的配置,初始化,管理bean。一個Spring容器就是某個實現了ApplicationContext接口的類的實例。也就是說,從代碼層面,Spring容器其實就是一個ApplicationContext。mysql
在普通的JAVA工程中,咱們能夠經過代碼顯式new一個ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext來初始化一個Spring容器。程序員
在Web工程中,咱們通常是經過配置web.xml的方式來初始化Spring容器。web
輕量--從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架能夠在一個大小隻有1MB多的JAR文件裏發佈。而且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的對象不依賴於Spring的特定類。面試
控制反轉-Spring經過一種稱做控制反轉(IoC)的技術促進了低耦合。當應用了IoC,一個對象依賴的其它對象會經過被動的方式傳遞進來,而不是這個對象本身建立或者查找依賴對象。你能夠認爲IoC與JNDI相反--不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它。spring
面向切面--Spring提供了面向切面編程的豐富支持,容許經過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發。應用對象只實現它們應該作的--完成業務邏輯--僅此而已。它們並不負責(甚至是意識)其它的系統級關注點,例如日誌或事務支持。sql
容器--Spring包含並管理應用對象的配置和生命週期,在這個意義上它是一種容器,你能夠配置你的每一個bean如何被建立--基於一個可配置原型(prototype),你的bean能夠建立一個單獨的實例或者每次須要時都生成一個新的實例--以及它們是如何相互關聯的。然而,Spring不該該被混同於傳統的重量級的EJB容器,它們常常是龐大與笨重的,難以使用。數據庫
框架--Spring能夠將簡單的組件配置、組合成爲複雜的應用。在Spring中,應用對象被聲明式地組合,典型地是在一個XML文件裏。Spring也提供了不少基礎功能(事務管理、持久化框架集成等等),將應用邏輯的開發留給了你。編程
MVC--Spring的做用是整合,但不只僅限於整合,Spring 框架能夠被看作是一個企業解決方案級別的框架。客戶端發送請求,服務器控制器(由DispatcherServlet實現的)完成請求的轉發,控制器調用一個用於映射的類HandlerMapping,該類用於將請求映射到對應的處理器來處理請求。HandlerMapping 將請求映射到對應的處理器Controller(至關於Action)在Spring 當中若是寫一些處理器組件,通常實現Controller 接口,在Controller 中就能夠調用一些Service 或DAO 來進行數據操做 ModelAndView 用於存放從DAO 中取出的數據,還能夠存放響應視圖的一些數據。 若是想將處理結果返回給用戶,那麼在Spring 框架中還提供一個視圖組件ViewResolver,該組件根據Controller 返回的標示,找到對應的視圖,將響應response 返回給用戶。
全部Spring的這些特徵使你可以編寫更乾淨、更可管理、而且更易於測試的代碼。它們也爲Spring中的各類模塊提供了基礎支持。
spring容器工廠:spring對全部對象均可以進行管理,而後經過單例模式建立一個全局惟一的一個實例對象,經過工廠模式在調用注入的接口時實例化對象。
Spring模式包含:單例模式和工廠模式
單例模式: a.單例模式限制了類實例的建立,但採用這種模式設計的類,能夠保證僅有一個實例,並可提供訪問該實例的全局訪問點。b.J2EE應用的大量組件,都須要保證一個類只有一個實例,好比數據庫引擎訪問只有一個。c.可是更多時候,爲了提升性能,程序應儘可能減小Java 對象的建立和銷燬時的開銷。使用單例模式可避免Java 類被屢次實例化。d. 爲了防止單態模式的類被屢次實例化,應將類的構造器設成私有,這樣就保證了只能經過靜態方法得到類實例。
工廠模式:a.工廠模式是根據調用數據返回某個類的一個實例,此類能夠是多個類的某一個類。b.一般,這些類知足共同的規則(接口)或父類。調用者只關心工廠生產的實例是否知足某種規範,即實現的某個接口是否可供本身正常調用(調用者僅僅使用)。c.該模式給對象之間做出了清晰的角色劃分,下降程序的耦合。d.接口產生的所有實例一般用於實現相同接口,接口裏定義了所有實例共同擁有的方法,這些方法在不一樣的實現類中實現的方式不一樣。f.從而使程序調用者無須關心方法的具體實現,下降了系統異構的代價。
IoC 不是一種技術,只是一種思想,一個重要的面向對象編程的法則,它能指導咱們如何設計出鬆耦合、更優良的程序。傳統應用程序都是由咱們在類內部主動建立依賴對象,從而致使類與類之間高耦合,難於測試;有了IoC容器後,把建立和查找依賴對象的控制權交給了容器,由容器進行注入組合對象,因此對象與對象之間是鬆散耦合,這樣也方便測試,利於功能複用,更重要的是使得程序的整個體系結構變得很是靈活。
其實IoC對編程帶來的最大改變不是從代碼上,而是從思想上,發生了「主從換位」的變化。應用程序本來是老大,要獲取什麼資源都是主動出擊,可是在IoC/DI思想中,應用程序就變成被動的了,被動的等待IoC容器來建立並注入它所須要的資源了。
IoC很好的體現了面向對象設計法則之一—— 好萊塢法則:「別找咱們,咱們找你」;即由IoC容器幫對象找相應的依賴對象並注入,而不是由對象主動去找。
DI—Dependency Injection,即「依賴注入」:組件之間依賴關係由容器在運行期決定,形象的說,即由容器動態的將某個依賴關係注入到組件之中。依賴注入的目的並不是爲軟件系統帶來更多功能,而是爲了提高組件重用的頻率,併爲系統搭建一個靈活、可擴展的平臺。經過依賴注入機制,咱們只須要經過簡單的配置,而無需任何代碼就可指定目標須要的資源,完成自身的業務邏輯,而不須要關心具體的資源來自何處,由誰實現。
IoC(Inversion of Control,控制反轉)。這是spring的核心,貫穿始終。所謂IoC,對於spring框架來講,就是由spring來負責控制對象的生命週期和對象間的關係。
Spring所倡導的開發方式就是如此,全部的類都會在spring容器中登記,告訴spring你是個什麼東西,你須要什麼東西,而後spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其餘須要你的東西。全部的類的建立、銷燬都由 spring來控制,也就是說控制對象生存週期的再也不是引用它的對象,而是spring。對於某個具體的對象而言,之前是它控制其餘對象,如今是全部對象都被spring控制,因此這叫控制反轉。
IoC的一個重點是在系統運行中,動態的向某個對象提供它所須要的其餘對象。這一點是經過DI(Dependency Injection,依賴注入)來實現的。
AOP編程思想:橫向重複代碼,縱向抽取;就是說多個地方重複的代碼能夠抽取出來公用(過濾器等能夠體現)
動態代理:動態代理能夠體現AOP思想;對目標方法進行加強
SpringAOP開發:封裝了動態代理代碼(包括cglib代理),能夠對任何類進行代理加強
AOP(Aspect Orient Programming),做爲面向對象編程的一種補充,普遍應用於處理一些具備橫切性質的系統級服務,如事務管理、安全檢查、緩存、對象池管理等。AOP 實現的關鍵就在於 AOP 框架自動建立的 AOP 代理,AOP 代理則可分爲靜態代理和動態代理兩大類,其中靜態代理是指使用 AOP 框架提供的命令進行編譯,從而在編譯階段就可生成 AOP 代理類,所以也稱爲編譯時加強;而動態代理則在運行時藉助於 JDK 動態代理、CGLIB 等在內存中「臨時」生成 AOP 動態代理類,所以也被稱爲運行時加強。
Spring 的 AOP 代理由 Spring 的 IoC 容器負責生成、管理,其依賴關係也由 IoC 容器負責管理。所以,AOP 代理能夠直接使用容器中的其餘 Bean 實例做爲目標,這種關係可由 IoC 容器的依賴注入提供。
縱觀 AOP 編程,其中須要程序員參與的只有 3 個部分:
定義普通業務組件。
定義切入點,一個切入點可能橫切多個業務組件。
定義加強處理,加強處理就是在 AOP 框架爲普通業務組件織入的處理動做。
上面 3 個部分的第一個部分是最日常不過的事情,無須額外說明。那麼進行 AOP 編程的關鍵就是定義切入點和定義加強處理。一旦定義了合適的切入點和加強處理,AOP 框架將會自動生成 AOP 代理
spring的一些基本概念:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
5
6 <!-- spring:管理對象的容器 -->
7 <!-- spring IOC:控制反轉,經過spring建立對象(無需手動建立) -->
8 <!-- DI:依賴注入;就是給對象的某些屬性賦值 -->
9
10 <!-- 將User對象交給spring管理 -->
11 <!-- bean元素:描述須要spring管理的對象;name屬性:給對象取個別名,獲取對象時須要;
12 class屬性:被管理對象的完整類名;id屬性:與name屬性如出一轍,不可重複,不能使用特殊字符(所以要name)-->
13 <!-- 建立方式一:spring調用無參構造建立對象 -->
14 <!-- scope:singleton:表示單例對象,在spring容器中只會存在一個實例 -->
15 <!-- scope:prototype:表示多例對象,每次獲取都會建立一個新的對象;整合struts2時必須爲多例 -->
16 <!-- 生命週期方法配置init,destroy -->
17 <bean name="user" class="com.bean.User" scope="singleton" init-method="init" destroy-method="destroy"></bean>
18
19 <!-- 建立方式二:經過靜態工廠的某個方法建立一個user對象 -->
20 <bean name="user1" class="com.bean.UserFactory" factory-method="createUser"></bean>
21
22 <!-- 建立方式三:實例工廠建立對象 -->
23 <bean name="user2" factory-bean="userFactory" factory-method="createUser2"></bean>
24 <bean name="userFactory" class="com.bean.UserFactory"></bean>
25
26 <!-- 模塊化配置,能夠導入其餘spring配置文件 -->
27 <!--<import resource="applicationContext.xml"/>-->
28 </beans>
spring依賴注入方式:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:p="http://www.springframework.org/schema/p"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
6
7 <!-- set方式注入 -->
8 <bean name="user" class="com.bean.User">
9 <!-- 值類型注入 -->
10 <property name="name" value="xdzy"/>
11 <property name="age" value="18"/>
12 <!-- 引用類型注入 -->
13 <property name="car" ref="car"/>
14 </bean>
15
16 <!-- 將car對象配置到spring容器 -->
17 <bean name="car" class="com.bean.Car">
18 <property name="name" value="蘭博基尼"/>
19 <property name="color" value="紅色"/>
20 </bean>
21
22 <!-- 構造函數注入 -->
23 <bean name="user1" class="com.bean.User">
24 <!-- 當構造方法參數位置不一樣,能夠經過index肯定參數位置 -->
25 <!-- 當構造方法參數類型不一樣,能夠經過type肯定參數類型 -->
26 <constructor-arg name="name" value="xdzy" index="0" type="java.lang.String"/>
27 <constructor-arg name="car" ref="car"/>
28 </bean>
29
30 <!-- p屬性注入 -->
31 <!-- 需加入xmlns:p="http://www.springframework.org/schema/p" -->
32 <bean name="user2" class="com.bean.User" p:name="xdzy" p:age="18" p:car-ref="car"/>
33
34 <!-- spel表達式注入;能夠實現動態注入 -->
35 <bean name="user3" class="com.bean.User">
36 <property name="name" value="#{user.name}"/>
37 <property name="age" value="#{user2.age}"/>
38 <property name="car" ref="car"/>
39 </bean>
40
41 <!-- 數組注入 -->
42 <bean name="cb" class="com.bean.CollectionBean">
43 <!-- 只有一個值時 -->
44 <!--<property name="arr" value="tom"/>-->
45 <!-- 多值多元素注入 -->
46 <property name="arr">
47 <array>
48 <value>xdzy</value>
49 <value>jady</value>
50 <ref bean="user3"/>
51 </array>
52 </property>
53 </bean>
54
55 <!-- 集合注入 -->
56 <bean name="cb2" class="com.bean.CollectionBean">
57 <!-- 只有一個值時 -->
58 <!--<property name="list" value="tom"/>-->
59 <!-- 多值多元素注入 -->
60 <property name="list">
61 <list>
62 <value>xdzy</value>
63 <value>jady</value>
64 <ref bean="user3"/>
65 </list>
66 </property>
67 </bean>
68
69 <!-- map注入 -->
70 <bean name="cb3" class="com.bean.CollectionBean">
71 <property name="map">
72 <map>
73 <entry key="name" value="xdzy"/>
74 <entry key="user" value-ref="user3"/>
75 <entry key-ref="user1" value-ref="user2"/>
76 </map>
77 </property>
78 </bean>
79
80 <!-- 資源注入 -->
81 <bean name="cb4" class="com.bean.CollectionBean">
82 <property name="properties">
83 <props>
84 <prop key="driverClass">com.jdbc.mysql.Driver</prop>
85 <prop key="userName">admin</prop>
86 <prop key="password">123</prop>
87 </props>
88 </property>
89 </bean>
90 </beans>
spring的通知類型:
1 package com.aspect;
2
3 import org.aspectj.lang.ProceedingJoinPoint;
4 /**
5 * @author: 肖德子裕
6 * @date: 2018/9/7 08:23
7 * @description: 通知
8 * 前置通知:目標方法運行以前
9 * 後置通知(若是出現異常不會調用):以後
10 * 環繞通知:以前以後
11 * 異常攔截通知:出現異常調用
12 * 後置通知(不管是否出現異常都會調用):以後
13 */
14 public class MyAdvice {
15 //前置通知:目標方法運行以前
16 public void before(){
17 System.out.println("前置通知");
18 }
19 //後置通知(若是出現異常不會調用):以後
20 public void afterReturning(){
21 System.out.println("後置通知(若是出現異常不會調用)");
22 }
23 //環繞通知:以前以後
24 public Object around(ProceedingJoinPoint pjp) throws Throwable{
25 System.out.println("環繞通知以前部分");
26 //調用目標方法
27 Object proceed=pjp.proceed();
28 System.out.println("環繞通知以後部分");
29 return proceed;
30 }
31 //異常攔截通知:出現異常調用
32 public void afterException(){
33 System.out.println("出現異常調用");
34 }
35 //後置通知(不管是否出現異常都會調用):以後
36 public void after(){
37 System.out.println("後置通知(不管是否出現異常都會調用)");
38 }
39 }
JDK動態代理:
1 package com.service;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Proxy;
6
7 /**
8 * @author: 肖德子裕
9 * @date: 2018/9/6 20:25
10 * @description: 動態代理
11 * 被代理對象必需要實現接口,才能產生代理對象,若是沒有接口將不能使用動態代理技術
12 * 動態代理可對方法進行加強,如增長事務的打開與提交
13 * 我的理解:它是對service實現類裏全部的方法進行了加強;
14 * 在不破壞原有結構的狀況下,生成動態代理對象,對原有方法進行加強
15 */
16 public class UserServiceProxyFactory implements InvocationHandler {
17 private UserService us;
18
19 public UserServiceProxyFactory(UserService us) {
20 this.us = us;
21 }
22
23 public UserService getUserServiceProxy(){
24 //生成動態代理
25 UserService userProxy=(UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
26 UserServiceImpl.class.getInterfaces(),
27 this);
28 //返回一個動態代理對象
29 return userProxy;
30 }
31
32 @Override
33 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
34 System.out.println("打開事務");
35 Object invoke=method.invoke(us,args);
36 System.out.println("提交事務");
37 return invoke;
38 }
39 }
cglib動態代理:
1 package com.service;
2
3 import org.springframework.cglib.proxy.Enhancer;
4 import org.springframework.cglib.proxy.MethodInterceptor;
5 import org.springframework.cglib.proxy.MethodProxy;
6
7 import java.lang.reflect.Method;
8 /**
9 * @author: 肖德子裕
10 * @date: 2018/9/6 20:25
11 * @description: cglib代理
12 * 能夠對任何類生成代理,對目標對象進行繼承代理
13 */
14 public class UserServiceProxyFactory2 implements MethodInterceptor {
15 public UserService getUserServiceProxy(){
16 //生成代理對象
17 Enhancer en=new Enhancer();
18 //對誰進行代理
19 en.setSuperclass(UserServiceImpl.class);
20 //代理要作什麼
21 en.setCallback(this);
22 //建立代理對象
23 UserService us=(UserService) en.create();
24 return us;
25 }
26
27 @Override
28 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
29 //打開事務
30 System.out.println("打開事務");
31 //調用原有方法
32 Object returnValue=methodProxy.invokeSuper(o,objects);
33 //提交事務
34 System.out.println("提交事務");
35 return returnValue;
36 }
37 }