Spring hello world
什麼是Spring
Spring是一個開源的,輕量級Java開發框架; 其核心特性是可以用於開發任何 Java 應用程式,Spring 框架的目標是使 JavaEE應用程式的開發變得更加容易,核心概念是IOC和AOP;這也是學習Spring的重點所在;
Spring不是針對某個具體功能,具體層級的框架; 也就是說以前該有的系統分層,結構,設計模式都不需要改變,而是讓Spring加入進來,讓開發變得更簡單; 記住Spring並不想取代某個已存在的框架,反而可以讓各個框架的配合使用難度降低,它就像502膠水,可快速的在系統中整合其他優秀的框架
Spring也因其特性而得名,寓意為JavaEE開發的春天來了
為什麼需要Spring
我們經常會看到Spring替代EJB,或Spring與EJB對比等等相關文章,那麼兩者之間到底有什麼關係呢?
之前的課程中我們知道,EJB是JavaEE規範中的一個,主要用於開發分散式應用程式
從概念上來看:
- Spring是一個框了架,框架是幫你實現了一部分功能的半成品
- 而EJB是一個規範,用來規範(指導)開發者,如何去實現JavaEE程式
所以這個問題其實是在問Spring(框架)和JavaEE(規範)的對比,而因為兩者不是同一種概念,所以無法直接對比,那到底在對比啥? 不能在賣關子了;
問題應該是:使用Spring開發和完全按照JavaEE規範開發應用程式的區別
這個問題應該由Spring的作者Rod Johnson來回答:
#Rod Johnson在2002年編寫的《Expert One-to-One J2EE Design and Development》一書,Rod 在本書中對J2EE正統框架臃腫、低效、脫離現實的種種學院派做法提出了質疑,並以此書為指導思想,編寫了interface21框架,也就是後來的Spring。
的確推出Spring推出就是民間開發者對官方規範的中不足的地方提出的質疑以及做出的強力迴應,在早期階段,開發者們經歷了擁抱到拋棄,從最早的JavaEE這一官方協議推出後,開發者們非常擁戴,畢竟是官方嘛,後來慢慢發現這堆複雜,晦澀,學習成本極高的規範是多麼的臃腫不堪,就像你為了打一隻小鳥而搬出了戰鬥機;就在這時候Spring框架應運而生,因其輕量級,使用簡單很快受到了大家的喜愛;
好在官方也意識到了問題,於是在EJB3.0做出了大量的改進,並借鑑了Spring中一些非常優秀的特性,但如日中天的Spring好像並沒有受到太大的影響,大家一如既往的喜愛Spring;
EJB容器IOC容器
另一方面因為Spring具備ICO容器,可以幫助我們管理Bean,而EJB的需要放在EJB容器中才能使用其提供的功能; EJB主要用於提供分散式能力,而IOC容器是幫助我們更好的解耦
Spring的優點
- Spring 對JavaEE中的一些API(JDBC、JavaMail、遠端呼叫等),提供了封裝,使這些API使用難度降低;
- 一站式框架,可簡單快速的整合其他框架;
- IOC,利用依賴注入,極大的降低各元件間的耦合,提高整體擴充套件性;
- AOP(面向切面)程式設計的支援,可以方便的對程式進行許可權攔截,執行監控等;
- 宣告式事務支援,通過配置就可以完成對事務的管理,無序進行手動程式設計;
- 容器化,Spring包含並管理應用物件的配置和生命週期,你可以配置每個bean如何被建立以及bean是一個單獨的例項或者每次需要時都生成一個新的例項,以及它們是如何相互關聯的。
IOC,DI
概念
控制反轉(Inversion of Control,縮寫為IoC),是面向物件程式設計中的一種設計原則,可以用來減低計算機程式碼之間的耦合度。
將原本由程式實現的一部分邏輯反過來交給系統來完成就稱之為控制反轉
其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI)通過控制反轉,可以說,依賴被注入到物件中。
依賴注入是實現控制反轉的一種手段;
為何需要IOC
舉個例子:自己搭配組裝機,需要考慮各種部件的相容性,和自己的效能的要求,如CPU,記憶體,顯示卡等等;但有了專門的組裝機伺服器商(IOC容器),你只要告訴他你的基本需求,比如,要一臺吃雞電腦,剩下的就交給服務商去做了;
大多數應用程式,都是有很多不同物件彼此合作來完成業務邏輯,這導致在獲取一個合作物件時,必須顯示的去new一個物件,這將就導致程式碼高度耦合並且難以維護和除錯。像下面這樣
public class Controller {
@Test
public void doGet() throws Exception {
//這裡需要依賴Service層
UserService service = new UserService("引數1","引數2");
}
當需要更換其他業務邏輯實現類時就不得不修改原始碼,並且若Service的例項化需要引數時,Controller層就不得不為其提供必要的引數,這反映了Controller與Service的耦合度是較高的
Spring體系結構
core,提供了框架基礎組成部分,包括IoC和DI;
beans,提供了BeanFactory,是工廠模式的實現,提供普通物件和單例物件的獲取
context,建立在core和bean的基礎上,可將其他庫整合到Spring中
SpEL(spring-expression Language)提供了表示式語言支援,其對JSP中的EL進行了擴充套件
AOP,提供了面向切面程式設計實現
Aspects 模組提供了與 AspectJ 的整合,是一個功能強大且成熟的AOP框架
Instrumentation 用於代理監控JVM執行的JAVA程式,對位元組碼修改以實現AOP
Messaging 模組為 STOMP 提供了支援,主要處理來自 WebSocket 客戶端的 STOMP 資訊
強調:
Spring是模組化的,完全可以根據需要來匯入所需模組
使用入門
傳統寫法
先來看一個不使用Spring時,控制和業務邏輯層互動的案例,控制器:
public class Controller {
@Test
public void doGet() throws Exception {
//這裡需要依賴Service層
//v1 直接寫
//UserService service = new UserService();
//v2 面向介面 某個實現類
//UserService service = new UserServiceImpl();
//要跟換其他實現類時 違反了OCP(開放封閉)原則
//UserService service = new UserServiceImpl2();
//v3 為避免修改原始碼擴充套件 加入工廠
ServiceFactory factory = new ServiceFactory();
UserService service = factory.getService();
//呼叫業務方法
service.userLogin("jerry","admin");
}
}
工廠:
public class ServiceFactory {
public UserService getService() throws Exception {
//此處id應配置在xml中
String id = "UserServiceImpl";
if (id.equals("UserServiceImpl")){
return new UserServiceImpl();
}else if(id.equals("UserServiceImpl2")){
return new UserServiceImpl2();
}
throw new Exception("id:"+id + "not register");
}
}
使用工廠模式可以進一步降低元件間的耦合度,但在完整的系統中有很多元件,需要很多個工廠,使程式變得複雜,臃腫;
Spring將自身設計為一個大型物件工廠,負責管理系統中設計到的所有物件,並利用DI處理物件的依賴關係,當物件A需要物件B時不再自己建立而是從Spring中獲取
補充說明:OCP
叫做開放封閉原則,是應用程式開發中應該遵循的一個原則
open:對擴充套件開放
close:對修改原始碼封閉
其目的是要在不修改原始碼的情況下對已有功能進行擴充套件
使用Spring
1.建立Maven專案
2.新增依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- Maven會自動下載所有Spring核心容器和aop的依賴-->
3.建立配置檔案
通常名為:applicationContext.xml
當然你也可以修改放在resources
下
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用bean標籤,建立Service物件,並交給容器來管理-->
<bean id="UserService1" class="com.yyh.serviceimpl.UserServiceImpl"/>
<bean id="UserService2" class="com.yyh.serviceimpl.UserServiceImpl2"/>
</beans>
名稱空間宣告可到官網查詢,或是直接在jar中查詢,如:
4.從Spring中獲取需要的物件
@Test
public void doGetUseSpring() throws Exception {
//建立應用上下文 指定配置檔案
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//從Spring中獲取所需物件
UserService userService = (UserService)context.getBean("UserService2");
//呼叫業務邏輯方法
userService.userLogin("jerry","admin");
}
不難看出此時的Spring就是一個物件工廠,但這僅僅Spring的基礎功能
IOC容器
容器可以理解為存放物件的地方,當然不僅僅是儲存,還有物件的管理,包括-建立-銷燬-裝配; 這樣原本程式要做的事情交給了Spring,所以這屬於IOC,稱之為IOC容器;
Spring有兩個介面ApplicationContext是BeanFactory的子介面。它們都可以作為Spring的容器;
兩種容器的區別:
BeanFactory作為頂級介面主要面向於Spring框架本身,僅提供了基礎基本的容器功能如DI
ApplicationContext,是BeanFactory的子介面,意味著功能比BeanFactory更多,諸如國際化,註解配置,XML配置等等
BeanFactory採取的懶載入的方式,在獲取物件時才會例項化
ApplicationContext會在工廠初始化時立即例項化物件
ApplicationContext的兩個實現類區別:
ClassPath表示從類路徑中獲取配置檔案
FileSystem表示從檔案系統獲取配置檔案