簡單實現Spring容器(二) 封裝BeanDefinition對象放入Map

階段2:

 // 1.編寫自己的Spring容器,實現掃描包,得到bean的class對象.2.掃描將 bean 信息封裝到 BeanDefinition對象,并放入到Map.

思路:

1.將 bean 信息封裝到 BeanDefinition對象中,再將其放入到BeanDefinitionMap集合中,集合的結構大概是
key[beanName]–value[beanDefintion]
key--------->對應指定的名字,未指定則以類的首字母小寫為其名字
value------->對應封裝好的BeanDefintion對象

2.因為bean的作用域可能是singleton,也可能是prototype,所以Spring需要掃描到bean信息,保存到集合,這樣當getBean()根據實際情況處理.

具體實現

1.加一個自定義Scope注解

package com.elf.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author 45~* @version 1.0* Scope 可以指定一個Bean的作用范圍[singleton,prototype]*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {//通過value可以指定singleton,prototypeString value() default "";
}

2.在MonsterService.java上加上@Scope多實例注解

package com.elf.spring.component;
import com.elf.spring.annotation.Component;
import com.elf.spring.annotation.Scope;/*** @author 45~* @version 1.0* 說明 MonsterService 是一個Servic*/
@Component //把MonsterService注入到我們自己的spring容器中
@Scope(value = "prototype")
public class MonsterService {}

3.準備ioc包下寫一個BeanDefinition.java 用于封裝記錄Bean信息.

package com.elf.spring.ioc;/*** @author 45~* @version 1.0* BeanDefinition 用于封裝和記錄Bean的信息 [1.scope 2.存放bean對應的Class對象,反射可以生成對應的對象]*  2:因為將來getBean()時有可能是多實例,有可能是動態生成的,還要存放bean的class對象*/
public class BeanDefinition {private String scope;private Class clazz;//存放bean的class對象public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}public Class getClazz() {return clazz;}public void setClazz(Class clazz) {this.clazz = clazz;}@Overridepublic String toString() {return "BeanDefinition{" +"scope='" + scope + '\'' +", clazz=" + clazz +'}';}
}

3.pom.xml文件引入jar包下的工具類commons-lang,完成首字母小寫的功能.而不用springframework自帶的StringUtils工具類
在這里插入圖片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.elf</groupId><artifactId>elf-myspring1207</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency></dependencies></project>

4.容器文件,把構造器里邊的方法抽取出來封裝成一個方法,直接在構造器中調用,使代碼簡潔.
這里完成生成BeanDefinition對象并放入到Map里面

添加內容1:
//定義屬性BeanDefinitionMap -> 存放BeanDefinition對象(多例對象)private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();//定義屬性SingletonObjects -> 存放單例對象 (跟原生容器的名字保持一致)//因為將來存放單例池的時候肯定要指定單例對象是對應哪個Bean的,所以k用String來充當//存放單例對象的類型是不確定的,可能是Dog,Cat,或者其他的對象,所以用Objectprivate ConcurrentHashMap<String,Object> singletonObjects =new ConcurrentHashMap<>();
添加內容2:
//先得到beanName(有可能通過經典4注解,例如Component注解的value值來指定)//1.得到類上的Component注解,此時的clazz已經是當前bean的class對象,通過類加載器得到的 反射知識Component componentAnnotation = cla.getDeclaredAnnotation(Component.class);//2.得到配置的valueString beanName = componentAnnotation.value();if("".equals(beanName)){//如果沒有寫value,空串//將該類的類名首字母小寫作為beanName//StringUtils其實是在springframework的框架下面的類,而這里本身我就是要自己寫所以不用beanName = StringUtils.uncapitalize(className);}//3.將Bean的信息封裝到BeanDefinition對象中,然后將其放入到BeanDefinitionMap集合中BeanDefinition beanDefinition = new BeanDefinition();//!!!多看看這里多理解beanDefinition.setClazz(cla);//由類加載器通過反射得到對象,Class<?> cla = classLoader.loadClass(classFullName);//4.獲取Scope值if (cla.isAnnotationPresent(Scope.class)){//如果配置了Scope,就獲取它配置的值Scope scopeAnnotatiion = cla.getDeclaredAnnotation(Scope.class);beanDefinition.setScope(scopeAnnotatiion.value());}else{//如果沒有配置Scope,就以默認的值singletonbeanDefinition.setScope("singleton");}//將beanDefinitionMap對象放入MapbeanDefinitionMap.put(beanName,beanDefinition);}else {//如果該類沒有使用了@Component注解,說明是一個Spring beanSystem.out.println("這不是一個Spring bean" + cla + " 類名=" + className);}

容器文件

package com.elf.spring.ioc;import com.elf.spring.annotation.*;
import org.apache.commons.lang.StringUtils;import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;/*** @author 45~* @version 1.0*/
public class ElfSpringApplicationContext {//第一步,掃描包,得到bean的class對象,排除包下不是bean的,因此還沒有放到容器中//因為現在寫的spring容器比原先的基于注解的,要更加完善,所以不會直接把它放在ConcurrentHashMapprivate Class configClass;//定義屬性BeanDefinitionMap -> 存放BeanDefinition對象private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();//定義屬性SingletonObjects -> 存放單例對象 (跟原生容器的名字保持一致)//因為將來存放單例池的時候肯定要指定單例對象是對應哪個Bean的,所以k用String來充當//存放單例對象的類型是不確定的,可能是Dog,Cat,或者其他的對象,所以用Objectprivate ConcurrentHashMap<String,Object> singletonObjects =new ConcurrentHashMap<>();//構造器public ElfSpringApplicationContext(Class configClass) {beanDefinitionScan(configClass);//調用封裝方法,簡潔System.out.println("beanDefinitionMap=" + beanDefinitionMap);}//構造器結束//該方法完成對指定包的掃描,并將Bean信息封裝到BeanDefinition對象,再放入到Map中public void beanDefinitionScan(Class configClass){this.configClass = configClass;/**獲取要掃描的包:1.先得到ElfSpringConfig配置的 @ComponentScan(value= "com.elf.spring.component")2.通過 @ComponentScan的value => 即要掃描的包 **/ComponentScan componentScan =(ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);String path = componentScan.value();System.out.println("要掃描的包path=" + path);/*** 得到要掃描包下的所有資源(類.class)* 1.得到類的加載器 -> APP類加載器是可以拿到 target目錄下的classes所有文件的* 2.通過類的加載器獲取到要掃描的包的資源url => 類似一個路徑* 3.將要加載的資源(.class)路徑下的文件進行遍歷 => io*/ClassLoader classLoader = ElfSpringApplicationContext.class.getClassLoader();path = path.replace(".", "/"); // 把.替換成 /URL resource = classLoader.getResource(path);System.out.println("resource=" + resource);File file = new File(resource.getFile());if (file.isDirectory()) {File[] files = file.listFiles();for (File f : files) { //把所有的文件都取出來System.out.println("============================");System.out.println("f.getAbsolutePath()=" + f.getAbsolutePath());String fileAbsolutePath = f.getAbsolutePath();//到target的classes目錄下了//這里只處理.class文件if (fileAbsolutePath.endsWith(".class")) {//1.獲取類名String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1,fileAbsolutePath.indexOf(".class"));//2.獲取類的完整路徑(全類名)String classFullName = path.replace("/", ".") + "." + className;System.out.println("classFullName=" + classFullName);//3.判斷該類是否需要注入,就看是不是有注解@Component @Service @Contoller @Re....try {Class<?> cla = classLoader.loadClass(classFullName);if (cla.isAnnotationPresent(Component.class) ||cla.isAnnotationPresent(Controller.class) ||cla.isAnnotationPresent(Service.class) ||cla.isAnnotationPresent(Repository.class)) {//演示機制//如果該類使用了@Component注解,說明是一個Spring beanSystem.out.println("這是一個Spring bean=" + cla + " 類名=" + className);//先得到beanName(有可能通過經典4注解,例如Component注解的value值來指定)//1.得到類上的Component注解,此時的clazz已經是當前bean的class對象,通過類加載器得到的 反射知識Component componentAnnotation = cla.getDeclaredAnnotation(Component.class);//2.得到配置的valueString beanName = componentAnnotation.value();if("".equals(beanName)){//如果沒有寫value,空串//將該類的類名首字母小寫作為beanName//StringUtils其實是在springframework的框架下面的類,而這里本身我就是要自己寫所以不用beanName = StringUtils.uncapitalize(className);}//3.將Bean的信息封裝到BeanDefinition對象中,然后將其放入到BeanDefinitionMap集合中BeanDefinition beanDefinition = new BeanDefinition();//!!!多看看這里多理解beanDefinition.setClazz(cla);//由類加載器通過反射得到對象,Class<?> cla = classLoader.loadClass(classFullName);//4.獲取Scope值if (cla.isAnnotationPresent(Scope.class)){//如果配置了Scope,就獲取它配置的值Scope scopeAnnotatiion = cla.getDeclaredAnnotation(Scope.class);beanDefinition.setScope(scopeAnnotatiion.value());}else{//如果沒有配置Scope,就以默認的值singletonbeanDefinition.setScope("singleton");}//將beanDefinitionMap對象放入MapbeanDefinitionMap.put(beanName,beanDefinition);}else {//如果該類沒有使用了@Component注解,說明是一個Spring beanSystem.out.println("這不是一個Spring bean" + cla + " 類名=" + className);}} catch (Exception e) {e.printStackTrace();}}}//遍歷文件for循環結束System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");}}//編寫放法返回容器中的對象public Object getBean(String name) {return null;}
}

運行結果

beanDefinitionMap={
monsterService=BeanDefinition{scope=‘prototype’, clazz=class com.elf.spring.component.MonsterService},

monsterDao=BeanDefinition{scope=‘singleton’, clazz=class com.elf.spring.component.MonsterDao}
}
ok
在這里插入圖片描述
這里存在一個問題:單例多例對象都是放在beanDefinitionMap, singletonObjects里沒有單例對象.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213817.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213817.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213817.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL行鎖范圍分析(行鎖、間隙鎖、臨鍵鎖)

MySQL 中鎖的概念 排它鎖&#xff08;Exclusive Lock&#xff09; X 鎖&#xff0c;也稱為寫鎖&#xff0c;若事務T對對象A加上X鎖&#xff0c;則只允許T讀取和修改A&#xff0c;其他任何事物都不能再對A 加任何鎖&#xff0c;直到T釋放A上的鎖。 SELECT…FOR UPDATE 對讀取的…

風控之Android設備指紋技術

標識性參數——Android ID、IMEI、OAID非標識性參數 非標識性參數——手機運營商 1 設備指紋 簡單來講&#xff0c;設備指紋是指用于標識出該設備的設備特征。可以是單一設備特征&#xff0c;也可以是多種設備特征的組合&#xff0c;以方便風控系統對設備的唯一性進行識別。…

產品入門第一講:Axure的安裝以及基本使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一個在CSDN分享筆記的博主。&#x1f4da;&#x1f4da; ??? &#x1f31f;在這里&#xff0c;我要推薦給大家我的專欄《Axure》。&#x1f3af;&#x1f3af; &#x1f680;無論你是編程小白&#xff0c;還是有…

未來教師行業發展前景

親愛的老師們&#xff0c;你是否對未來教師行業的發展前景感到好奇和期待&#xff1f;作為一名老師&#xff0c;我深知教育行業的重要性和挑戰&#xff0c;但同時也看到了其中蘊含的巨大機遇。 一、技術融合與在線教育 技術的飛速發展正在改變著教育的面貌。在線教育平臺的崛起…

算法基礎十一

組合 給定兩個整數 n 和 k&#xff0c;返回范圍 [1, n] 中所有可能的 k 個數的組合。 示例 1&#xff1a; 輸入&#xff1a;n 4, k 2 輸出&#xff1a; [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 示例 2&#xff1a; 輸入&#xff1a;n 1, k 1 輸出&#xff1a;[[1]…

用C語言了解文件那些下 ‘流‘ 事

本篇會加入個人的所謂‘魚式瘋言’??????魚式瘋言:??????此瘋言非彼瘋言,而是理解過并總結出來通俗易懂的大白話,我會盡可能的在每個概念后插入魚式瘋言,幫助大家理解的&#xff0c;可能說的不是那么嚴謹.但小編初心是能讓更多人能接受我們這個概念 前言 &#…

uniapp實戰 —— 自定義頂部導航欄

效果預覽 下圖中的紅框區域 范例代碼 src\pages.json 配置隱藏默認頂部導航欄 "navigationStyle": "custom", // 隱藏默認頂部導航src\pages\index\components\CustomNavbar.vue 封裝自定義頂部導航欄的組件&#xff08;要點在于&#xff1a;獲取屏幕邊界…

理解Go中的指針

引言 當你用Go編寫軟件時,你將編寫函數和方法。你可以將數據作為參數傳遞給這些函數。有時,函數需要數據的本地副本,而你希望原始數據保持不變。例如,如果你是一家銀行,你有一個函數向用戶顯示根據他們選擇的儲蓄計劃而產生的余額變化,你不希望在客戶選擇計劃之前更改他…

OpenAI在中國,申請GPT-6、GPT-7商標

根據最新商標信息顯示&#xff0c;OpenAI已經在中國提交了GPT-6和GPT-7的商標注冊信息&#xff0c;分類是科學儀器和網站服務兩大類。申請日期是今年的11月2日&#xff0c;目前處于審核狀態。 該申請由知識產權代理公司完成&#xff0c;但申請人的地址正是OpenAI在美國公司的地…

Echarts圖表title使用富文本

rich中有配置的話&#xff08;如a&#xff09;使用該樣式&#xff0c;沒有配置樣式的話&#xff08;如b&#xff09;使用外層textstyle的樣式&#xff0c;textstyle沒有樣式的話使用默認樣式 const option1 {tooltip: {trigger: "item",},title: {text: ["{a|1…

Java代碼審計之SpEL表達式注入漏洞分析

文章目錄 前言SpEL表達式基礎基礎用法安全風險案例演示 CVE-2022-22963漏洞簡述環境搭建反彈shell CVE漏洞調試分析本地搭建調試分析補丁分析 總結 前言 表達式注入是 Java 安全中一類常見的能夠注入命令并形成 RCE 的漏洞&#xff0c;而常見的表達式注入方式有 EL 表達式注入…

124.(leaflet篇)leaflet禁止地圖移動,縮放,雙擊

地圖之家總目錄(訂閱之前必須詳細了解該博客) 完整代碼工程包下載,運行如有問題,可“私信”博主。效果如下所示: 下面獻上完整代碼,代碼重要位置會做相應解釋 <!DOCTYPE html> <html>

深入探索HTTPS加密技術與新興安全趨勢:保衛隱私的未來之路

在前文中&#xff0c;我們了解了HTTPS加密協議的工作原理和應用場景。然而&#xff0c;隨著技術的不斷發展和網絡安全威脅的不斷演變&#xff0c;HTTPS加密技術也在不斷進化。在本篇博文中&#xff0c;我們將更深入地探討HTTPS加密技術&#xff0c;并介紹一些新興的安全趨勢&am…

css中的 box-sizing: border-box

box-sizing: border-box 是 CSS 中的一個盒子模型屬性&#xff0c;用于指定元素的盒子模型的計算方式。默認的盒子模型是 content-box&#xff0c;而使用 border-box 則表示元素的寬度和高度包括了元素的邊框和內邊距&#xff0c;而不僅僅是內容的寬度和高度。 在默認的 conte…

【Docker】使用docker-compose搭建django+vue工程文章

我們嘗試使用docker-compose編排一個后端基于django,前端基于vue,數據庫為postgresql并使用nginx進行反向代理的web工程。 工程準備 Docker 安裝Docker 安裝docker-compose django 在python3.7的環境下創建 修改settings.py文件 修改 將靜態文件收集路徑添加進 ,筆…

pip指定優先從豆瓣源下載包

對于 Unix/macOS 系統&#xff0c;使用以下命令&#xff1a; pip config set global.index-url https://pypi.douban.com/simple/ 對于 Windows 系統&#xff0c;打開命令提示符或PowerShell&#xff0c;并使用相同的命令&#xff1a; pip config set global.index-url http…

react re-render的解決方案

問題代碼 import {Dispatch, FC, SetStateAction, useState} from reactimport ./App.cssconst Child: FC<{ m: number, setM: Dispatch<SetStateAction<number>> }> (props) > {const {m, setM } propsreturn (<div><button onClick{() &…

阿里java社招一面

1、項目所負責的功能介紹&#xff1b;B用戶對A用戶的用餐評價進行評論以及B用戶對評論進行追評的話怎么設計數據庫結構&#xff1b;菜品好評度排行榜怎么實現的 2、clickhouse為什么快 3、線程池有哪幾種&#xff0c;分別說說定義和優缺點&#xff1b;多線程使用過程中要注意…

XUbuntu22.04之8款免費UML工具(一百九十七)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

前端知識筆記(四)———JQuery 自動刷新頁面但不閃爍的實現方法

在本文中&#xff0c;我們將介紹如何使用jQuery實現自動刷新頁面但不出現閃爍的效果。通常情況下&#xff0c;當我們需要自動刷新頁面時&#xff0c;使用簡單的location.reload()方法即可實現&#xff0c;但這會導致頁面在刷新時出現短暫的白屏或閃爍。為了解決這個問題&#x…