講Spring以前先寫段代碼,體會一下Java建立對象的方式,這塊你理解了對後面有好處!html
直接new建立對象,代碼以下:java
//User.java package com.ty.bean; public class User { private String username; private String password; /** * 省略有參無參構造,getter/setter方法 */ }
//UserDao.java public interface UserDao { void getUser(String username,String password); } //UserDao的實現類UserDaoImpl.java public class UserDaoImpl implements UserDao { @Override public void getUser(String username, String password) { System.out.println("用戶名:"+username+"\t密碼:"+password); } }
//UserService.java public interface UserService { void getUser(String username,String password); } //UserService的實現類UserServiceImpl.java public class UserServiceImpl implements UserService { private UserDao userDao= new UserDaoImpl(); @Override public void getUser(String username, String password) { userDao.getUser(username,password); } }
正常來說這裏還須要寫一個UserController,可是咱們只是測試,因此就寫一個TestUser類git
public class TestUser { @Test public void test(){ UserService userService=new UserServiceImpl(); userService.getUser("jack","root"); } }
這是以前學習常常寫的方式用來完成某種功能,service層調用dao層;UserService的實現類調用UserDao的實現類。想象一下:若是咱們業務更改了,增長了一個UserService的實現類BUserServiceImpl,使用的時候代碼就要變成這樣程序員
public class TestUser { @Test public void test(){ //UserService userService=new UserServiceImpl(); UserService userService=new BUserServiceImpl(); userService.getUser("jack","root"); } }
這就是所謂的耦合,調用的時候要修改代碼,即直接new , 顯然不符合面向對象的設計原則---------開閉原則github
工廠方式,再原來的代碼修改一下web
先建立一個BeanFactory.java文件spring
//建立工廠類,BeanFactory.java public class BeanFactory { public static UserService getUser(){ return new UserServiceImpl(); } }
這樣使用的時候就變成這樣數據庫
@Test public void test(){ UserService userService= BeanFactory.getUser(); userService.getUser("jack","root"); }
這樣雖然使用的時候沒有耦合了,可是BeanFactory裏面仍是有代碼耦合的即:return UserService,那怎麼辦呢?能夠利用反射建立對象編程
public class BeanFactory { public static UserService getUser(){ UserService userService=null; try { Class<?> clazz = Class.forName("com.ty.service.UserServiceImpl"); userService= (UserService) clazz.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return userService; }
這樣比直接new好多了,減小了耦合,可是還有些不妥,獲取類限定名的時候仍是須要改來改去。即:安全
Class<?> clazz = Class.forName("com.ty.service.UserServiceImpl");
下面咱們能夠用properties屬性配置文件存儲文件限定名,代碼以下:
userService=com.ty.service.UserServiceImpl #這就實現把具體的類限定名和代碼相分離,將來只須要修改此配置文件便可
public class BeanFactory { private static UserService userService; //建立Properties對象來加載properties屬性配置文件 private static Properties environment = new Properties(); private static InputStream resource; static { //加載applicationContext.properties配置文件 resource = BeanFactory.class.getResourceAsStream("/applicationContext.properties"); try { environment.load(resource); } catch (IOException e) { e.printStackTrace(); } finally { try { resource.close(); } catch (IOException e) { e.printStackTrace(); } } } public static UserService getUserService() throws Exception { Class<?> clazz = Class.forName(environment.getProperty("userService")); userService = (UserService) clazz.newInstance(); return userService; } }
這樣將來增長了service代碼,只須要修改properties配置文件便可,例如
public class BUserServiceImpl implements UserService { private UserDao userDao= new UserDaoImpl(); @Override public void getUser(String username, String password) { System.out.println("B"); userDao.getUser(username,password); } }
#配置文件就改爲這樣 userService=com.ty.service.BUserServiceImpl
//測試文件 @Test public void test2() throws Exception { UserService userService= BeanFactory.getUserService(); userService.getUser("jack","root"); }
咱們順便用這種方式把UserService調用UserDao進行改進
public static UserDao getUserDao() { UserDao userDao=null; Class<?> clazz = null; try { clazz = Class.forName(environment.getProperty("userDao")); userDao = (UserDao) clazz.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return userDao; } public class UserServiceImpl implements UserService { private UserDao userDao= BeanFactory.getUserDao(); @Override public void getUser(String username, String password) { userDao.getUser(username,password); } }
userDao=com.ty.dao.UserDaoImpl
@Test public void test2() throws Exception { UserService userService= BeanFactory.getUserService(); userService.getUser("jack","root"); }
工廠方法基本設計完成了,可是還有點小問題,那就是每次都須要在BeanFactory工廠類寫一個與其對應的對象建立工廠方法,好麻煩,並且這些方法長得基本差很少,能不能設計一個通用的工廠方法呢,那必須能啊,上代碼
public class BeanFactory { private static Properties environment = new Properties(); private static InputStream resource; static { //加載applicationContext.properties配置文件 resource = BeanFactory.class.getResourceAsStream("/applicationContext.properties"); try { environment.load(resource); } catch (IOException e) { e.printStackTrace(); } finally { try { resource.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * * @param key 配置文件對應的userService,userDao * @return */ public static Object getBean(String key){ Object returnedObject=null; try { Class<?> clazz = Class.forName(environment.getProperty(key)); returnedObject=clazz.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return returnedObject; } }
userService=com.ty.service.UserServiceImpl userDao=com.ty.dao.UserDaoImpl
public class UserServiceImpl implements UserService { private UserDao userDao= (UserDao) BeanFactory.getBean("userDao"); @Override public void getUser(String username, String password) { userDao.getUser(username,password); } } @Test public void test2() throws Exception { UserService userService= (UserService) BeanFactory.getBean("userService"); userService.getUser("jack","root"); } }
這樣一個通用工廠就完成了,這種方式你還須要先本身提供工廠類和方法,咱們若是用Spring的話,工廠類不用咱們手動實現,Spring提供了工廠
ioc容器建立對象,這種方式咱們後面會詳細講解
public class UserServiceImpl implements UserService { private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void getUser(String username, String password) { userDao.getUser(username,password); } }
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.ty.service.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.ty.dao.UserDaoImpl"></bean> </beans>
@Test public void test3(){ ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.getUser("jack","root"); }
這樣咱們就把建立對象的方式的一個小Demo寫完了,只就是Spring框架的核心之一:ioc,咱們先簡單介紹一下Spring
咱們常說的 Spring 其實是指 Spring Framework,而 Spring Framework 只是 Spring 家族中的一個分支而已。那麼 Spring 家族都有哪些東西呢? 具體能夠查看官網:https://spring.io/projects
官網地址:https://spring.io/projects/spring-framework
壓縮包下載地址:https://repo.spring.io/release/org/springframework/spring/
源碼地址:https://github.com/spring-projects/spring-framework
英文官網可能看不懂,github上還有一箇中文網址,只不過不是最新版本的,不過沒太大影響
https://gitee.com/fl_982659186/spring-docs
Spring 是爲了解決企業級應用開發的複雜性而建立的。在 Spring 以前,有一個重量級的工具叫作 EJB,使用 Spring 可讓 Java Bean 之間進行有效的解耦,而這個操做以前只有 EJB 才能完成,EJB 過於臃腫,使用不多。Spring 不只僅侷限於服務端的開發,在測試性和鬆耦合方面都有很好的表現。 官網有一個簡短的Spring介紹,說明Spring產生的緣由
Spring makes programming Java quicker, easier, and safer for everybody. Spring’s focus on speed, simplicity, and productivity has made it the world's most popular Java framework. 總結就是Spring能爲咱們快速、輕鬆和安全的進行Java編程 詳細:https://spring.io/why-spring
官網上還有一個Spring的概述
中文翻譯:https://gitee.com/fl_982659186/spring-docs/blob/master/pages/overview/overview.md
spring是一個一站式開源框架。
spring是爲了簡化企業開發而生的,使得開發變得更加優雅和簡潔。
spring是一個IOC和AOP的容器框架。
IOC:控制反轉
AOP:面向切面編程
容器:包含並管理應用對象的生命週期,就比如用桶裝水同樣,spring就是桶,而對象就是水
一、Spring經過DI、AOP和消除樣板式代碼來簡化企業級Java開發
二、Spring框架以外還存在一個構建在覈心框架之上的龐大生態圈,它將Spring擴展到不一樣的領域,如Web服 務、REST、移動開發以及NoSQL
三、低侵入式設計,代碼的污染極低
四、獨立於各類應用服務器,基於Spring框架的應用,能夠真正實現Write Once,Run Anywhere的承諾
五、Spring的IoC容器下降了業務對象替換的複雜性,提升了組件之間的解耦
六、Spring的AOP支持容許將一些通用任務如安全、事務、日誌等進行集中式處理,從而提供了更好的複用
七、Spring的ORM和DAO提供了與第三方持久層框架的的良好整合,並簡化了底層的數據庫訪問
八、Spring的高度開放性,並不強制應用徹底依賴於Spring,開發者可自由選用Spring框架的部分或所有
如何簡化開發
基於POJO的輕量級和最小侵入性編程
經過依賴注入和麪向接口實現鬆耦合
基於切面和慣例進行聲明式編程
經過切面和模板減小樣板式代碼
模塊解釋: Test:Spring的單元測試模塊 Core Container:核心容器模塊,主要組件是 BeanFactory是否是好熟悉,上面我們實現了一個簡易版的BeanFactory AOP+Aspects:面向切面編程模塊 Instrumentation:提供了class instrumentation支持和類加載器的實現來在特定的應用服務器上使用,幾乎不用 Messaging:包括一系列的用來映射消息到方法的註解,幾乎不用 Data Access/Integration:數據的獲取/整合模塊,包括了JDBC,ORM,OXM,JMS和事務模塊 Web:提供面向web整合特性
ioc(Inversion of Control ):控制反轉,這是一個思想,簡單一句話就是建立對象的控制權利交給Spring的容器 咱們稍微詳細展開一下
先看一下官網如何介紹的
IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern IOC與你們熟知的依賴注入同理,. 這是一個經過依賴注入對象的過程 也就是說,它們所使用的對象,是經過構造函數參數,工廠方法的參數或這是從工廠方法的構造函數或返回值的對象實例設置的屬性,而後容器在建立bean時注入這些須要的依賴。 這個過程相對普通建立對象的過程是反向的(所以稱之爲IoC),bean自己經過直接構造類來控制依賴關係的實例化或位置,或提供諸如服務定位器模式之類的機制。
可能稍微晦澀,用現實的事物舉個例子。咱們要找女盆友,傳統的方式是你本身按照標準親自一步步篩選,而後就須要打聽她們的興趣愛好、qq號、電話號、微信號等等,想辦法認識她們再繼續下一步事情。控制反轉的方式的話就是有一個婚介所,這個媒介所就是一個容器,裏面有不少女生的資料,你把你的標準告訴工做人員,而後剩下的步驟由他們去操做,最後給你就返回一個符合你標準的女盆友,你就和她談戀愛、結婚就好了。
說到這咱們把上面演示過的demo畫圖演示一下
咱們總結一下上面說的4個小問題
DI ( Dependency Injection ):依賴注入
不少人把IOC和DI說成一個東西,籠統來講的話是沒有問題的,可是本質上仍是有所區別的,但願你們可以嚴謹一點,IOC和DI是從不一樣的角度描述的同一件事,IOC是從容器的角度描述,而DI是從應用程序的角度來描述,也能夠這樣說,IOC是設計思想,而DI是具體的實現方式
上面的控制反轉概念實際上是模糊的 (可能只是理解爲容器控制對象這一個層面,很難讓人想到誰來維護對象關係) ,因此後來就有了 「依賴注入」 ,這個就很好理解,很直截了當就能說明IOC容器用來維護對象的依賴關係。
咱們稍微說點其它的,額外說兩個點
須要注意的是,在這樣的組合關係中,一旦某一個對象出現了問題,那麼其餘對象確定回有所影響,這就是耦合性過高的緣故,可是對象的耦合關係是沒法避免的,也是必要的。隨着應用程序愈來愈龐大,對象的耦合關係可能愈來愈複雜,常常須要多重依賴關係,所以,不管是架構師仍是程序員,在面臨這樣的場景的時候,都須要減小這些對象的耦合性。
耦合的關係不只僅是對象與對象之間,也會出如今軟件系統的各個模塊之間,是咱們須要重點解決的問題。而爲了解決對象之間的耦合度太高的問題,咱們就能夠經過IOC來實現對象之間的解耦,spring框架就是IOC理論最最普遍的應用。
從上圖中能夠看到,當引入了第三方的容器以後,幾個對象之間就沒有了耦合關係,所有對象都交由容器來控制,這個容器就至關於粘合劑,將系統的對象粘合在一塊兒發揮做用。
任何一個語言或者任何一個框架想要立於不敗之地,那麼很重要的就是它的生態。Java語言如今爲何那麼火爆,就是由於20多年的歷練,出現了不少技術,這些技術被普遍使用,若是出現新的編程語言想替代Java,短期內沒法替代。Spring框架也同樣,發展到今天,咱們都離不開它了,如今不多的公司不用Spring
這些都是Spring家族的產品,而咱們如今學的包括不久我更新的SpringMVC都是屬於Spring Framework的範疇
因此咱們說Spring不只僅是框架,它主要是一個生態,幾乎在Spring中能找到JavaEE各類解決方案,Spring框架更新的還很頻繁!
ps:Spring全系列我後面打算都更新一遍,組件多,我會一點點更新,你們也是須要一點點積累!也歡迎你們多多提建議!