Spring
Spring 是一個輕量級的 IoC / DI 和 AOP 容器的開源框架,致力於構建輕量級的 JavaEE 應用,簡化應用開發。前端
IoC 和 DI 思想
IoCjava
將本來在程序中對象的建立權,交由 spring的IoC 容器來管理,強調建立對象。mysql
DIweb
指 Spring 建立對象的過程當中,將對象依賴屬性(常量,對象,集合)經過配置設值給該對象。強調設置對象的屬性值。面試
Spring項目的建立:
建立Maven項目,添加依賴和插件;
org.springframework
;spring須要經過配置文件
applicationContext.xml
告訴spring
來管理哪些對象;sqlBeanFactory
:表示 Spring IoC 容器 — 生產 bean 對象的工廠,負責配置,建立和管理 bean。數據庫文件是Spring Bean Configuration File,文件名通常爲:applicationContext.xml;express
在配置文件中完成<bean>標籤的配置:經過id和class屬性來告訴Spring容器來管理這個對象。apache
從容器中獲取這個對象:找到這個配置文件,底層經過反射建立對象,並保存在容器中進行管理;
注入屬性:<property>標籤來指定對象的屬性名的屬性值;
測試:經過
BeanFactory
來獲取被管理的bean對象;getBean的方法:
類型 變量名 = beanFactory.getBean("配置文件中的name",配置文件的類型.class);
Spring IoC 管理 bean 的原理
經過 Resource 對象加載配置文件;
解析配置文件,解析 bean 元素,id 做爲 bean 的名字,class 用於反射獲得 bean 的實例,注意:此時,bean 類必須存在一個無參數構造器(和訪問權限無關);
調用 getBean 方法的時候,從容器中返回對象實例。
<import resource="文件路徑"/>
applicationContext.xml文件中,項目規模變大時,<bean>元素太多,分類分解成多個xml文件,經過<import resource="文件路徑"/>
的方式將這些xml文件引入便可。
<import resource="classpath:cn/wolfcode/day1/_02_hello/hello.xml"/>
SpringText
Spring 容器在管理測試代碼,節省性能的開銷。添加spring-test
的依賴。
@Runwith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@Autowired
IoC 容器
Spring IoC 容器(Container)
Spring IoC 容器(Container)
應用中,通常不使用 BeanFactory,而推薦使用 ApplicationContext(應用上下文),它繼承自BeanFactory,在啓動Spring的時候就會把全部的bean都建立好了;
在字段上貼@Autowired註解,能夠直接獲取到容器中的bean。
bean的做用域:
singleton:單例 ,在 Spring IoC 容器中僅存在一個 bean 實例 (缺省默認的 scope);
prototype:多例 ,每次從容器中調用 Bean 時,都返回一個新的實例,即每次調用 getBean() 時 ,至關於執行 new Xxx():不會在容器啓動時建立對象。
注意:
只有正常關閉容器,纔會執行 bean 的配置的 destroy-method 方法。
bean 的 scope 爲 prototype 的,那麼容器只負責建立和初始化,它並不會被 Spring 容器管理(不須要存起來),交給用戶本身處理。即 bean 做用域爲 prototype 的即便配置了 destroy-method 也不會被調用。
DI
注入方式:
setter方法注入:
setter 方法注入又叫屬性注入,但其類必須提供對應 setter 方法。
<property name="對象屬性名稱" value="須要注入的值"/>
bean注入:
注入 bean,就是把一個 bean(非基本數據類型),經過 setter 方法設置給另外一個 bean;
<property name="對象屬性名稱" ref="被注入對象的bean的id" />
注入集合:
就是把一個集合類型的數據,經過 setter 方法設置給一個 bean;
配置Druid數據庫鏈接池
使用Spring以前,須要經過DruidDataSource對象來設置鏈接數據庫的四要素才能鏈接。太麻煩。添加依賴:druid、mysql-connector-java
如今只須要在applicationContext.xml 文件中配置便可:
配置以後:經過注入DruidDataSource對象 . getConnection()
便可得到鏈接對象。
property-placeholder
配置db.properties,在applicationContext.xml 文件中引入db跑配置文件。
location屬性爲配置文件的路徑;db中配置前綴jdbc.,防止從環境中去獲取屬性的值。
Autowired 和 Qualifier 註解
共同點:
可讓 Spring 自動的把屬性或字段須要的對象找出來,並注入到屬性上或字段上。
能夠貼在字段或者 setter 方法上面。
能夠同時注入多個對象。
不一樣點:
Autowired 註解尋找 bean 的方式:(先按類型在按名字)
Resource 註解尋找 bean 的方式:(先按名字再按類型)
IoC註解:
簡化不少的bean的配置:
@Repository
: 用於標註數據訪問組件,即 DAO 組件。@Service
: 用於標註業務層組件。@Controller
: 用於標註控制層組件(如 Struts2 中的 Action,SpringMVC 的 Controller)。@Component
: 泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。標註除上其餘組件。
須要配置IoC DI註解解析器:讓IoC註解或者DI註解起做用,發現某類貼有@Component註解,Spring就會建立這個類的對象存在Spring容器中
貼了註解以後,還須要配置IoC組件掃描器:
<!-- 配置 IoC DI 註解解析器 讓Spring幫咱們建立業務對象 -->
<context:component-scan base-package="cn.wolfcode.xxx"/>
靜態代理
代理對象徹底包含真實對象,客戶端使用的都是代理對象的方法,和真實對象沒有直接關係;
代理模式的職責:把不是真實對象該作的事情從真實對象上撇開——職責分離。
缺點:代理類本身實現,項目大,代理類多。
動態代理
動態代理類是在程序運行期間由 JVM 經過反射等機制動態的生成的,因此不存在代理類的字節碼文件,動態生成字節碼對象,代理對象和真實對象的關係是在程序運行時期才肯定的。
實現選擇:
針對有接口:使用 JDK 動態代理;
針對無接口:使用 CGLIB 或 Javassist 組件。
JDK 動態代理
前提
委託類(真實類),必須實現接口。
java.lang.reflect.Proxy 類
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler hanlder)
方法職責:爲指定類加載器、一組接口及調用處理器生成動態代理類實例
參數:
loader :類加載器,通常傳遞真實對象的類加載器
interfaces:代理類須要實現的接口
handler:代理執行處理器,說人話就是生成代理對象幫你要作什麼 返回:建立的代理對象
返回:建立的代理對象
java.lang.reflect.InvocationHandler 接口
public Object invoke(Object proxy, Method method, Object[] args)
方法職責:負責集中處理動態代理類上的全部方法調用,讓使用者自定義作什麼事情,對原來方法加強。
參數:
proxy :生成的代理對象
method:當前調用的真實方法對象
args :當前調用方法的實參
返回:真實方法的返回結果
操做步驟
定義封裝事務操做的一個模擬類。
實現
InvocationHandler
接口,實現invoke
方法,實現加強操做。在 Spring 配置文件中配置
InvocationHandler
實現類、事務操做模擬類、真實對象,讓其幫咱們建立對象組裝依賴。在單元測試類中注入
InvocationHandler
的bean
,在測試方法中手動使用Proxy
建立代理對象,調用代理對象的方法。
調用流程:
CGLIB 動態代理和原理
JDK 動態代理要求真實類必須實現接口。而 CGLIB 與 JDK 動態代理不一樣,真實類不用實現接口,代理類會繼承真實類。
org.springframework.cglib.proxy.Enhancer//相似 JDK 中 Proxy,用來生成代理類建立代理對象的。
org.springframework.cglib.proxy.InvocationHandler//相似 JDK 中InvocationHandler,讓使用者自定義作什麼事情,對原來方法加強。
操做步驟
修改
TransactionHandler
實現org.springframework.cglib.proxy.InvocationHandler
接口,其餘不變。修改單元測試類中的測試方法,改用
Enhancer
來生成代理類建立代理對象的。
調用流程:
動態代理的選用:
若真實類實現了接口,優先選用 JDK 動態代理。(真實類與代理類是共同實現一個接口)
若真實類沒有實現任何接口,使用 Javassit 和 CGLIB 動態代理。(代理類是繼承自真實類的)
動態代理問題:對多個 service 對象加強配置太多,還有要手動建立代理對象,在使用時不是面向接口,還要編寫 InvocationHandler 接口的實現類。
AOP 思想
AOP(Aspect Oriented Programming),是面向切面編程的技術。
Joinpoint:鏈接點,通常指須要被加強的方法。where:去哪裏作加強。
Pointcut:切入點,哪些包中的哪些類中的哪些方法,可認爲是鏈接點的集合。where:去哪些地方作加強。
Advice:加強,當攔截到 Joinpoint 以後,在方法執行的什麼時機(when)作什麼樣(what)的加強。
Aspect:切面,Pointcut + Advice,去哪些地方 + 在何時 + 作什麼加強。
Target:被代理的目標對象。
Weaving:織入,把 Advice 加到 Target 上以後,建立出 Proxy 對象的過程。
Proxy:一個類被 AOP 織入加強後,產生的代理類。
AOP 實現及 Pointcut 表達式
AspectJ 是一個面向切面的框架
AspectJ 切入點語法(表示在哪些包下的哪些類的哪些方法上作切入加強)
execution(* cn.wolfcode.wms.service.*.*(..))
execution(* cn.wolfcode.wms.service.*Service.*(..))
execution(* cn.wolfcode..service.*Service.*(..))
添加依賴:aspectjweaver
配置
<!-- 配置須要加的功能(加強)WHAT -->
<bean id="tx" class="cn.wolfcode.tx.MyTranansationManager"/>
<!-- 配置真實類型的對象 -->
<bean id="employeeService" class="cn.wolfcode.service.impl.EmployeeServiceImpl"/>
<!-- AOP的配置 -->
<aop:config proxy-target-class="true">
<!-- 切面 -->
<aop:aspect ref="tx">
<!-- 定義切入點:WHERE -->
<aop:pointcut expression="execution(* cn.wolfcode.service.impl.*ServiceImpl.*(..))" id="txPointcut"/>
<!-- 切入表達式中的方法,在方法執行以前調用tx.begin() -->
<aop:before method="begin" pointcut-ref="txPointcut"/>
<!-- 切入表達式中的方法,在方法正常執行完後調用tx.commit() -->
<aop:after-returning method="commit" pointcut-ref="txPointcut"/>
<!-- 切入表達式中的方法,在方法執行過程當中出現異常時調用tx.rollback() -->
<aop:after-throwing method="rollback" pointcut-ref="txPointcut"/>
</aop:aspect>
</aop:config>
使用 CGLIB
作以下配置便可:
轉帳功能集成:
使用框架,在別人的基礎上開發,提升效率;
集成 MyBatis 和業務層,即業務對象、 Mapper 對象等都交由 Spring 容器管理,使用 Spring IoC 和 DI 來完成對象建立及其屬性注入,後面再使用 AOP 來配置事務。
依賴及插件:
MyBatis框架所須要的依賴:
mybatis
mybatis-spring
數據庫驅動:
mysql-connector-java :SQL鏈接數據庫(做用域:runtime)
數據庫鏈接池:
Druid
druid
日誌打印:
slf4j-log4j12
Spring框架:
spring-test:測試(做用域:test)
Spring-jdbc:鏈接數據庫
aspectjweaver :AOP
spring-webmvc :MVC層
web項目共用的:
lombok (做用域:provided)
junit(做用域:test)
javax.servlet-api (做用域:provided)
頁面標籤:支持 JSTL
taglibs-standard-spec
taglibs-standard-impl
插件:
編譯插件:
maven-compiler-plugin
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source><!-- 更新項目(Maven | Update Project)以後,會修改項目的編譯版本 -->
<target>1.8</target><!-- 更新項目以後,會修改項目的運行版本 -->
<encoding>utf-8</encoding><!-- 更新項目以後,Java 編譯器讀取你的文件用的編碼 -->
</configuration>
/plugin>服務器maven項目插件:
org.apache.tomcat.maven
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port><!-- 端口 -->
<path>/</path> <!-- 上下路徑 -->
<uriEncoding>UTF-8</uriEncoding> <!-- 針對 GET 方式亂碼處理 -->
</configuration>
</plugin>
配置SqlSessionFactory
使用MyBatis須要建立SqlSessionFactory對象,交給Spring處理。
配置:
配置 Mapper 的代理對象
Mapper接口的實現類讓Spring來代理。管理需提供 Mapper 接口(接口中多參數使用@Param註解)和 Mapper XML 文件。
配置業務層對象
編寫業務接口和實現類:
配置業務對象:
測試:
註解方式整合 MyBatis
一、配置 Mapper 接口掃描器
以前配置多個Mapper 接口代理對象是比較麻煩的,使用 Mapper 接口掃描器能夠批量生成 Mapper 接口代理對象並註冊到 Spring 容器中。
二、使用註解方式配置業務對象
在業務類上貼 IoC 註解和 DI 註解:
在 applicationContext.xml 配置文件配置第三方解析程序:
配置總成:
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 配置數據源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置 IoC DI 註解解析器 讓Spring幫咱們建立業務對象 -->
<context:component-scan base-package="cn.wolfcode.ssm.service.impl"/>
<!--
配置時機(相似環繞加強:任什麼時候候都能起做用),並關聯上面上事務管理器
針對不一樣方法能夠區分配置
切入點表達式切到的方法,在方法執行以前調用 transactionManager.getTransaction()
切入點表達式切到的方法,在方法執行正常執行完調用 transactionManager.commit()
切入點表達式切到的方法,在方法執行拋出異常時調用 transactionManager.rollback()
-->
<!--CRUD通用事務配置 WHEN-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--Servlet中查詢的方法-->
<tx:method name="get*" read-only="true"/>
<tx:method name="list*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="count*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<!--Servlet中非查詢的方法-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP -->
<aop:config>
<!-- 定義 WHERE -->
<aop:pointcut expression="execution(* cn.wolfcode.ssm.service.impl.*ServiceImpl.*(..))"
id="txPointcut"/>
<!-- WHERE WHEN -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!-- 引入 db.properties:其中保存了鏈接數據庫的四要素 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置 DataSource 對象:數據源 鏈接數據庫的四要素 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置 SqlSessionFactory 對象 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--
關聯 MyBatis :主配置文件
主配置文件 配置能夠不配置什麼內容,可是約束和根元素必定要保留
若要配置:只須要配置延遲加載、二級緩存
-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 配置別名 -->
<property name="typeAliasesPackage" value="cn.wolfcode.ssm.domain"/>
<!-- 配置數據源:鏈接數據庫 -->
<property name="dataSource" ref="dataSource"/>
<!-- 關聯Mapper文件:和Mapper接口編譯後位置在一塊兒 ,因此能夠不配置 -->
<!-- <property name="mapperLocations" value="classpath:cn/wolfcode/ssm/mapper/*Mapper.xml"/> -->
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.wolfcode.ssm.mapper"/>
</bean>
</beans>
Spring MVC
MVC框架,它解決Web開發中常見的問題(參數接收、文件上傳、表單驗證、國際化等),與Spring無縫集成。
Servlet JavaBean JSP,減小耦合,提升可維護性。
前端控制器思想:
Front Controller模式要求在WEB應用系統的前端設置一個入口控制器,是用來提供一個集中的請求處理機制,全部的請求都被髮往控制器統一處理,而後把請求分發給各自相應的處理程序,通常用來作一個共同的處理。由於前端控制器集中處理請求的能力,提升了可重用性和可拓展性。
Spring將處理請求的對象稱之爲處理器/控制器( Controller)。使用MVC框架必須在web.xml中配置前端控制器,通常的,要麼是要 Filter,要麼是 Servlet。Spring MVC 是基於 Servlet實現的。
添加依賴和插件:
spring-webmvc
、javax.servlet-api
;服務器插件、編譯插件;
配置前端控制器:org.springframework.web.servlet.DispatcherServlet
編寫處理器類:貼註解@Controller
方法的註解@RequestMapping("/xxx")
編寫 Spring MVC 配置文件
處理器Controller
的響應處理
Controller 方法能夠有多個不一樣類型的參數,以及一個多種類型的返回結果。涉及到經過控制器的方法設計來完成處理請求處理和響應數處理。
響應處理關注的有兩方面:
Controller 方法的返回類型;
Controller 共享數據到視圖頁面。
處理方法返回 ModelAndView:Controller方法中定義 ModelAndView 對象並返回,對象中設置模型數據並指定視圖。
消除視圖前綴和後綴:配置這個,那麼方法最後要找的視圖就是:前綴+邏輯視圖名+後綴名。
處理方法返回 String
返回 String 類型和共享數據(使用普遍),此時和 Model 參數組合使用。
下面返回值爲 String,此時物理視圖路徑爲:前綴+邏輯視圖名+後綴。
請求轉發:加上forward: 前綴方式,表示請求轉發,至關於
request.getRequestDispatcher().forward(request,response)
,轉發後瀏覽器地址欄不變,共享以前請求中的數據。重定向:加上redirect: 前綴方式,表示重定向,至關於
response.sendRedirect()
,重定向後瀏覽器地址欄變爲重定向後的地址,不共享以前請求的數據。使用處理方法的形參來接收請求參數
請求參數名和 Controller方法的形參同名:能夠直接接收
請求參數名和 Controller方法的形參不一樣名:使用
@RequestParam
註解貼在形參上,設置對應的請求參數名稱。請求參數不是必須(用戶能夠不傳該參數):可使用
@RequestParam
的 required 爲 false。
亂碼處理
get 方式傳遞中文參數亂碼問題:在pom.xml文件的Tomcat插件中設置
post 方法傳遞中文亂問題:直接使用 Spring MVC 內置的編碼過濾器來處理。
處理複合類型請求參數
數組類型參數:多個同類型的請求參數,可直接用數組來接收;
JavaBean 自定義類型參數:注意:請求參數必須和對象的屬性同名
@ModelAttribute
註解:@ModelAttribute("xx")
:能夠貼在方法和形參上,形參前提是自定義類型,會存到模型裏,可在視圖中獲取到。
若沒貼這個註解,則經過類型首字母小寫做爲 key 獲取;
若貼了這個註解,能夠自定義 key,再經過這個 key 獲取。
日期類型處理
前臺日後臺傳參轉換爲 Date 類型:在對象字段或 Controller 形參貼上 @DateTimeFormat
在 JSP 中顯示 Date 類型的數據,此時須要使用 fmt 標籤。添加依賴才能支持 JSTL。
taglibs-standard-spec
、taglibs-standard-impl
Spring MVC 文件上傳
依賴:commons-fileupload
上傳表單:注意請求的類型必須是:multipart/form-data,且是 POST。
配置上傳解析器:注意上傳解析器這個 bean 名稱是固定的,必須爲 multipartResolver。
上傳控制器:接收上傳文件,並把上傳的文件拷貝項目的根路徑下指定目錄,文件名隨機(防止文件覆蓋)。
核心組件分析
一、核心組件
前端控制器 DispatcherServlet
不須要咱們開發,由框架提供,須要在 web.xml 中配置。做用:接受請求,處理響應結果,轉發器,中央處理器。
處理器映射器 HandlerMapping
不須要咱們開發,由框架提供。做用,更具請求的 URL 找到對應的 Handler。
處理器適配器 HandlerAdapter
不要咱們開發,由框架提供。做用:調用處理器(Handler / Controller)的方法。
處理器 Handler(又名 Controller),後端控制器
須要咱們開發,必須按照 HandlerAdapter 的規範去開發。做用:接收用戶請求數據,調用業務方法處理請求。
視圖解析器 ViewResolver
不須要咱們開發,有框架或者第三方提供。做用:視圖解析,把邏輯視圖名稱解析成真正的物理視圖。支持多種視圖技術 Velocity、FreeMarker、JSP 等。
視圖
須要咱們開發。做用:把數據展示給用戶。
開發步驟:
配置前端控制器
配置處理器映射器、處理適配器、視圖解析器(用默認的可不配置)。
須要開發(結合需求):
先開發 Contoller,再配置。
開發 JSP。
執行流程分析
一、圖示流程
二、文字描述
用戶發送出請求到前端控制器 DispatcherServlet。
DispatcherServlet 收到請求調用 HandlerMapping(處理器映射器)。
HandlerMapping 找到具體的處理器(經過 XML 或註解配置),生成處理器對象及處理器攔截器(如有),再一塊兒返回給 DispatcherServlet。
DispatcherServlet 調用 HandlerAdapter(處理器適配器)。
HandlerAdapter 通過適配調用具體的處理器的某個方法(Handler/Controller)。
Controller 執行完成返回 ModelAndView 對象。
HandlerAdapter 將 Controller 返回的 ModelAndView 再返回給 DispatcherServlet。
DispatcherServlet 將 ModelAndView 傳給 ViewReslover(視圖解析器)。
ViewReslover 解析後返回具體 View(視圖)。
DispatcherServlet 根據 View 進行渲染視圖(即將模型數據填充至視圖中)。
DispatcherServlet 響應用戶。
解耦,責任分離,可替換實現。看源碼分析執行流程。
小夥砸,歡迎再看分享給其餘小夥伴!共同進步!
本文分享自微信公衆號 - java學途(javaxty)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。