<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Spring——春天,Java程式設計世界的春天是由一位音樂家——Rod Johnson帶來的。
Rod Johnson先後編寫了兩本鉅著《Expert One-on-One J2EE Design and Development》、《Expert One-on-One J2EE Development without EJB》,拉起了挑戰正統Java EE框架EJB的大旗。
Rod Johnson不僅是一名旗手,更是開發了Spring這一輕量級框架,像一名勇敢的龍騎兵一樣,對EJB發動了衝鋒,並最終戰勝了EJB,讓Spring成為Java EE事實上的標準。
Spring的兩大核心分別是IOC和AOP,其中最最核心的是IOC。
所謂的IOC(控制反轉):就是由容器來負責控制物件的生命週期和物件間的關係。以前是我們想要什麼,就自己建立什麼,現在是我們需要什麼,容器就給我們送來什麼。
也就是說,控制物件生命週期的不再是參照它的物件,而是容器。對具體物件,以前是它控制其它物件,現在所有物件都被容器控制,所以這就叫控制反轉。
也許你還聽到另外一個概念DI(依賴注入),它指的是容器在範例化物件的時候把它依賴的類注入給它,我們也可以認為,DI是IOC的補充和實現。
Spring是一個成熟的框架,為了滿足擴充套件性、實現各種功能,所以它的實現如同枝節交錯的大樹一樣,現在讓我們把視線從Spring本身移開,來看看一個萌芽版的Spring容器怎麼實現。
Spring的IOC本質就是一個大工廠,我們想想一個工廠是怎麼執行的呢?
生產產品:一個工廠最核心的功能就是生產產品。在Spring裡,不用Bean自己來範例化,而是交給Spring,應該怎麼實現呢?——答案毫無疑問,反射。
那麼這個廠子的生產管理是怎麼做的?你應該也知道——工廠模式。
庫存產品:工廠一般都是有庫房的,用來庫存產品,畢竟生產的產品不能立馬就拉走。Spring我們都知道是一個容器,這個容器裡存的就是物件,不能每次來取物件,都得現場來反射建立物件,得把建立出的物件存起來。
訂單處理:還有最重要的一點,工廠根據什麼來提供產品呢?訂單。這些訂單可能五花八門,有線上籤籤的、有到工廠籤的、還有工廠銷售上門籤的……最後經過處理,指導工廠的出貨。
在Spring裡,也有這樣的訂單,它就是我們bean的定義和依賴關係,可以是xml形式,也可以是我們最熟悉的註解形式。
那對應我們的萌芽版的Spring容器是什麼樣的呢?
Bean可以通過一個組態檔定義,我們會把它解析成一個型別。
為了偷懶,這裡直接用了最方便解析的properties,用一個<key,value>型別的設定來代表Bean的定義,其中key是beanName,value是class
userDao:cn.fighter3.bean.UserDao
bean定義類,組態檔中bean定義對應的實體
public class BeanDefinition { private String beanName; private Class beanClass; //省略getter、setter }
接下訂單之後,就要由銷售向生產部門交接,讓生產部門知道商品的規格、數量之類。
資源載入器,就是來完成這個工作的,由它來完成組態檔中設定的載入。
public class ResourceLoader { public static Map<String, BeanDefinition> getResource() { Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16); Properties properties = new Properties(); try { InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties"); properties.load(inputStream); Iterator<String> it = properties.stringPropertyNames().iterator(); while (it.hasNext()) { String key = it.next(); String className = properties.getProperty(key); BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanName(key); Class clazz = Class.forName(className); beanDefinition.setBeanClass(clazz); beanDefinitionMap.put(key, beanDefinition); } inputStream.close(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return beanDefinitionMap; } }
物件註冊器,這裡用於單例bean的快取,我們大幅簡化,預設所有bean都是單例的。可以看到所謂單例註冊,也很簡單,不過是往HashMap裡存物件。
public class BeanRegister { //單例Bean快取 private Map<String, Object> singletonMap = new HashMap<>(32); /** * 獲取單例Bean * * @param beanName bean名稱 * @return */ public Object getSingletonBean(String beanName) { return singletonMap.get(beanName); } /** * 註冊單例bean * * @param beanName * @param bean */ public void registerSingletonBean(String beanName, Object bean) { if (singletonMap.containsKey(beanName)) { return; } singletonMap.put(beanName, bean); } }
好了,到了我們最關鍵的生產部門了,在工廠裡,生產產品的是車間,在IOC容器裡,生產物件的是BeanFactory。
物件工廠,我們最核心的一個類,在它初始化的時候,建立了bean註冊器,完成了資源的載入。
獲取bean的時候,先從單例快取中取,如果沒有取到,就建立並註冊一個bean
public class BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); private BeanRegister beanRegister; public BeanFactory() { //建立bean註冊器 beanRegister = new BeanRegister(); //載入資源 this.beanDefinitionMap = new ResourceLoader().getResource(); } /** * 獲取bean * * @param beanName bean名稱 * @return */ public Object getBean(String beanName) { //從bean快取中取 Object bean = beanRegister.getSingletonBean(beanName); if (bean != null) { return bean; } //根據bean定義,建立bean return createBean(beanDefinitionMap.get(beanName)); } /** * 建立Bean * * @param beanDefinition bean定義 * @return */ private Object createBean(BeanDefinition beanDefinition) { try { Object bean = beanDefinition.getBeanClass().newInstance(); //快取bean beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean); return bean; } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return null; } }
UserDao.java
我們的Bean類,很簡單
public class UserDao { public void queryUserInfo(){ System.out.println("A good man."); } }
單元測試
public class ApiTest { @Test public void test_BeanFactory() { //1.建立bean工廠(同時完成了載入資源、建立註冊單例bean註冊器的操作) BeanFactory beanFactory = new BeanFactory(); //2.第一次獲取bean(通過反射建立bean,快取bean) UserDao userDao1 = (UserDao) beanFactory.getBean("userDao"); userDao1.queryUserInfo(); //3.第二次獲取bean(從快取中獲取bean) UserDao userDao2 = (UserDao) beanFactory.getBean("userDao"); userDao2.queryUserInfo(); } }
執行結果
A good man.
A good man.
至此,我們一個萌芽版的Spring容器就完成了。
考慮一下,它有哪些不足呢?是否還可以抽象、擴充套件、解耦……
細細想想這些東西,你是不是對真正的Spring IOC容器為何如此複雜,有所理解了呢?
參考:
[1].《Spring揭祕》
[2].小傅哥 《手擼Spring》
[3].《精通Spring4.X企業應用開發實戰》
到此這篇關於手把手帶你實現一個萌芽版的Spring容器的文章就介紹到這了,更多相關Java Spring容器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45