手寫簡單的Spring基于注解配置的程序

需求說明:

????????自己寫一個簡單的 Spring 容器, 通過讀取類的注解(@Component @Controller@Service @Reponsitory) ,將對象注入到 IOC 容器,自己使用 IO+Annotaion+反射+集合 技術實現

思路分析:


一、新建一個包component并在包下創建bean類

環境配置:導入jar包

新建component包

這里將Servlet層,Service層等等的對象放入component包下,因為手寫的Spring基于注解配置的程序是一個簡化的程序,沒有原生的Spring功能強大,這里就將各個對象放入一個包下面便于io讀取

UserAction類:

package com.study.Spring.component;import org.springframework.stereotype.Controller;
//控制層Servlet
@Controller
public class UserAction {
}

UserComponent類:?

package com.study.Spring.component;import org.springframework.stereotype.Component;
//使用component注解可以將該類掃描放入ioc容器中
@Component
public class UserComponent {
}

UserDao類:?

package com.study.Spring.component;import org.springframework.stereotype.Repository;
//這是持久層、dao
@Repository
public class UserDao {
}

?UserService類:

package com.study.Spring.component;import org.springframework.stereotype.Service;
//這是Service層
@Service
public class UserService {
}

?


二、自定義注解(相當于原配置文件中的component-scan)

新建一個包用于存放自己手寫的程序

創建一個自定義注解:ComponentScan

package com.study.Spring.mySpringByAnnotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 這個自定義的注解的作用相當于原配置文件中的component-scan* @Target(ElementType.TYPE)表示該注解作用的對象* @Retention(RetentionPolicy.RUNTIME)表示該注解的生命周期* String value() default "";表示注解的屬性value用于存放包名(即:要掃描的包路徑),默認是空字符串*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {String value() default "";
}

三、創建一個類代替beans.xml文件

創建一個類:MySpringConfig作用相當于beans.cml文件

package com.study.Spring.mySpringByAnnotation;/*** MySpringConfig這個類作用相當于beans.xml文件* "com.study.Spring.component"這個包名傳給該注解的value屬性*/
@ComponentScan("com.study.Spring.component")
public class MySpringConfig {
}

四、創建MySpringApplicationContext類作為容器對象

這個類相當于容器對象:掃描配置文件,初始化Bean,反射創建Bean,保存Bean都在這里執行

package com.study.Spring.mySpringByAnnotation;import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;/*** 這個類相當于容器對象:掃描配置文件,初始化Bean,反射創建Bean,保存Bean都在這里執行*/
public class MySpringApplicationContext {//容器的屬性:MySpringConfig是配置類的Class對象,用于反射創建注解讀取類名//ioc屬性相當于原生的SingleTonObjects用于存儲單例bean對象private Class MySpringConfig;private final ConcurrentHashMap<String,Object> ioc =new ConcurrentHashMap<>();public MySpringApplicationContext(Class mySpringConfig){this.MySpringConfig=mySpringConfig;//反射獲取自定義的注解對象,再獲取注解中的包名ComponentScan componentScan =(ComponentScan) MySpringConfig.getDeclaredAnnotation(ComponentScan.class);String path = componentScan.value();path= path.replace(".", "/");//根據包名獲取實際工作目錄的路徑,再通過io流獲取掃描的類的絕對路徑
//file:/C:/Users/DELL/IdeaProjects/Spring/out/production/Spring/com/study/Spring/component//這里拿到類加載器用于獲取實際工作目錄ClassLoader classLoader = MySpringConfig.getClassLoader();URL realPath = classLoader.getResource(path);
//     /C:/Users/DELL/IdeaProjects/Spring/out/production/Spring/com/study/Spring/componentString filePath = realPath.getFile();File file = new File(filePath);//通過目錄獲取目錄下的所有Class文件if (file.isDirectory()){File[] files = file.listFiles();for (File item : files) {String name = item.getName();if (name.contains(".class")){//通過字符串的拼接獲取包下面的全類名path = path.replace("/", ".");String className = name.substring(0, name.indexOf("."));//獲取全類名String fullPath=path+"."+className;
//   再根據Class文件進行一次篩選:判斷是否有四種注解的類才進行創建實例對象并存儲在容器中try {//通過classloader獲取的Class對象時輕量級的,不會初始化時調用靜態方法Class<?> aClass = classLoader.loadClass(fullPath);//根據不同類的Class對象判斷是否有指定的注解if (aClass.isAnnotationPresent(Component.class)||aClass.isAnnotationPresent(Controller.class)||aClass.isAnnotationPresent(Service.class)||aClass.isAnnotationPresent(Repository.class)){//如果存在指定的注解那么就通過反射創建Class對象并創建實例對象Class<?> aClass1 = Class.forName(fullPath);//反射創建實例對象作為valueObject instance = aClass1.newInstance();//默認將首字母是小寫的類名作為keyclassName = StringUtils.uncapitalize(className);//將bean保存到容器中ioc.put(className,instance);}} catch (Exception e) {throw new RuntimeException(e);}}}}}public Object getBean(String id){return ioc.get(id);}
}

解釋:

????????獲取配置文件類MySpringConfig的Class對象,就可以用反射創建annotation注解對象,用注解對象獲取包名,有了包名后可以調用ClassLoader的方法得到實際工作目錄,再根據io流的方法+字符串的拼接得到包下面的各個類的全類名,再通過反射得到各個類的Class對象,再進一步篩選,通過反射Class對象調用isAnnotationPresent方法判斷是否存在指定的注解來選擇性初始化對象,最后將對象存儲在concurrentHashmap中,在MySpringApplicationContext類中添加getBean方法獲取bean對象


五、編寫測試類MySpringApplicationContextTest

package com.study.Spring.mySpringByAnnotation;public class MySpringApplicationContextTest {public static void main(String[] args) {MySpringApplicationContext ioc = new MySpringApplicationContext(MySpringConfig.class);Object userAction = ioc.getBean("userAction");Object userComponent = ioc.getBean("userComponent");Object userDao = ioc.getBean("userDao");Object userService = ioc.getBean("userService");System.out.println(userAction);System.out.println(userComponent);System.out.println(userDao);System.out.println(userService);}
}

運行結果:?

通過調試也可以看出已經初始化了四個bean對象?

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

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

相關文章

WSL 導入完整系統包教程

作者&#xff1a; DWDROME 配置環境&#xff1a; OS: Ubuntu 20.04.6 LTS on Windows 11 x86_64Kernel: 5.15.167.4-microsoft-standard-WSL2ros-noetic &#x1f9ed;WSL 導入完整系統包教程 ? 一、準備導出文件 假設你已有一個 .tar 的完整系統包&#xff08;如從 WSL 或 L…

使用selenium來獲取數據集

使用selenium來獲取數據集 1、下載最新的chrome瀏覽器與chromedriver.exe 查看chrome的版本,打開谷歌瀏覽器,點擊右上角的三個點,然后點擊【幫助】, 點擊【關于Google Chrome】 然后去下載同樣為134版本號的chromedriver.exe, 網址:https://googlechromelabs.github.…

(二)VMware:VMware虛擬機安裝CentOS教程

目錄 1、準備CentOS 7鏡像1.1、官網鏡像下載1.2、清華大學開源鏡像下載?1.3、阿里云開源鏡像下載 2、使用 VMware安裝CentOS 72.1、創建虛擬機2.2、選擇自定義安裝2.3、硬件兼容性&#xff0c;保持默認2.4、選擇下載的ISO鏡像2.5、設置虛擬機名稱以及存放磁盤位置2.6、按照需求…

【Agent】Dify Docker 安裝問題 INTERNAL SERVER ERROR

總結&#xff1a;建議大家選擇穩定版本的分支&#xff0c;直接拉取 master 分支&#xff0c;可能出現一下后面更新代碼導致缺失一些環境內容。 啟動報錯 一直停留在 INSTALL 界面 我是通過 Docker 進行安裝的&#xff0c;由于項目開發者不嚴謹導致&#xff0c;遇到一個奇怪的…

MySQL -- 復合查詢

數據庫的查詢是數據庫使用中比較重要的環節&#xff0c;前面的基礎查詢比較簡單&#xff0c;不做介紹&#xff0c;可自行查閱。本文主要介紹復合查詢&#xff0c;并結合用例進行講解。 本文的用例依據Soctt模式的經典測試表&#xff0c;可以自行下載&#xff0c;也可以自己創建…

flutter 開發web端的性能優化

參考資料 Flutter for Web 首次首屏優化 ——JS 分片優化_main.dart.js-CSDN博客文章瀏覽閱讀1.4k次。本文介紹了如何通過延遲加載組件和js分片優化Flutter for Web應用的加載速度。在實踐中&#xff0c;通過按需加載減少js文件大小&#xff0c;使用并行加載提升加載效率。通過…

編譯安裝redis,systemtcl配置redis自啟動,系統并發調優

編譯安裝redis&#xff0c;systemtcl配置redis自啟動&#xff0c;系統并發調優 1、編譯安裝redis wget https://download.redis.io/releases/redis-7.4.2.tar.gz tar -zxf redis-7.4.2.tar.gz cd redis-7.4.2/ make make install/usr/local/bin/redis-server -v2、systemtcl配…

firefly經典藍牙和QProcess、QFileSystemWatcher記錄

QProcess 默認不會啟動一個 shell 來解析命令,而是直接調用操作系統的系統調用來啟動外部程序。也就是通過fork一個子線程或者exec一個子進程來執行命令。 QProcess的參數模式 QProcess 需要明確指定命令的可執行文件路徑或參數列表。 如果命令是一個可執行文件的路徑…

Java定時任務的三重境界:從單機心跳到分布式協調

《Java定時任務的三重境界&#xff1a;從單機心跳到分布式協調》 本文將以生產級代碼標準&#xff0c;揭秘Java定時任務從基礎API到分布式調度的6種實現范式&#xff0c;深入剖析ScheduledThreadPoolExecutor與Quartz Scheduler的線程模型差異&#xff0c;并給出各方案的性能壓…

QT QML實現音頻波形圖進度條,可點擊定位或拖動進度

前言 本項目實現了使用QT QML創建一個音頻波形圖進度條的功能。用戶可以在界面上看到音頻波形圖&#xff0c;并且可以點擊進度條上的位置進行定位&#xff0c;也可以拖動進度條來調整播放進度。可以讓用戶更方便地控制音頻的播放進度&#xff0c;并且通過音頻波形圖可以直觀地…

高速網絡包處理,基礎網絡協議上內核態直接處理數據包,XDP技術的原理

文章目錄 預備知識TCP/IP 網絡模型&#xff08;4層、7層&#xff09;iptables/netfilterlinux網絡為什么慢 DPDKXDPBFPeBPFXDPXDP 程序典型執行流通過網絡協議棧的入包XDP 組成 使用 GO 編寫 XDP 程序明確流程選擇eBPF庫編寫eBPF代碼編寫Go代碼動態更新黑名單 預備知識 TCP/IP…

[每周一更]-(第137期):Go + Gin 實戰:Docker Compose + Apache 反向代理全流程

文章目錄 **1. Go 代碼示例&#xff08;main.go&#xff09;****2. Dockerfile 多段構建**3.構建 Docker 鏡像**4. docker-compose.yml 直接拉取鏡像****5. 運行容器****6. 測試 API**7、配置域名訪問**DNS解析&#xff1a;將域名轉換為IP地址****DNS尋址示例** 8.錯誤記錄 訪問…

SpringMVC基本使用

SpringMVC是什么&#xff1f; Spring MVC 是 Spring 框架中的一個模塊&#xff0c;用于構建基于 MVC&#xff08;Model-View-Controller&#xff09;設計模式的 Web 應用程序。它分離了應用程序的業務邏輯、用戶界面和用戶輸入&#xff0c;使開發更加模塊化和易于維護。 核心…

Qt之MVC架構MVD

什么是MVC架構&#xff1a; MVC模式&#xff08;Model–view–controller&#xff09;是軟件工程中的一種軟件架構模式&#xff0c;把軟件系統分為三個基本部分&#xff1a;模型&#xff08;Model&#xff09;、視圖&#xff08;View&#xff09;和控制器&#xff08;Controll…

Stream 流中 flatMap 方法詳解

&#x1f3af; 1. flatMap() 到底是啥&#xff1f; flatMap() 是 Stream 里的中間操作&#xff0c;它的作用可以分兩步理解&#xff1a; 第一步&#xff1a;對流里的每個元素&#xff0c;先**映射&#xff08;轉換&#xff09;**成一個 Stream。第二步&#xff1a;把多個子流…

(C語言)理解 回調函數 和 qsort函數

一. 回調函數 1. 什么是回調函數&#xff1f; 回調函數&#xff08;Callback Function&#xff09;是通過 函數指針 調用的函數。其本質是&#xff1a; 將函數作為參數傳遞給另一個函數&#xff0c;并在特定條件下被調用&#xff0c;實現 反向控制。 2. 回調函數的使用 回調函…

vscode記錄

vs code 下載安裝&#xff0c;git 配置&#xff0c;插件安裝_vscode安裝git插件-CSDN博客 手把手教你在VS Code中使用 Git_vscode如何輸入git命令-CSDN博客 VS Code | 如何快速重啟VS Code&#xff1f;_vscode 怎么一鍵全部重啟-CSDN博客 1&#xff0c;安裝插件與git集成 2&am…

唯品會商品詳情頁架構設計與實現:高并發場景下的技術實踐?

引言 唯品會作為國內領先的電商平臺&#xff0c;其商品詳情頁需要應對海量用戶的高并發訪問&#xff0c;同時保證低延遲和高可用性。本文將從架構設計、數據庫優化、緩存策略、前端渲染等方面&#xff0c;結合代碼示例&#xff0c;深入解析唯品會商品詳情頁的技術實現。 一、…

大數據學習(80)-數倉分層

&#x1f34b;&#x1f34b;大數據學習&#x1f34b;&#x1f34b; &#x1f525;系列專欄&#xff1a; &#x1f451;哲學語錄: 用力所能及&#xff0c;改變世界。 &#x1f496;如果覺得博主的文章還不錯的話&#xff0c;請點贊&#x1f44d;收藏??留言&#x1f4dd;支持一…

數智讀書筆記系列021《大數據醫療》:探索醫療行業的智能變革

一、書籍介紹 《大數據醫療》由徐曼、沈江、余海燕合著&#xff0c;由機械工業出版社出版 。徐曼是南開大學商學院副教授&#xff0c;在大數據驅動的智能決策研究領域頗有建樹&#xff0c;尤其在大數據驅動的醫療與健康決策方面有著深入研究&#xff0c;曾獲天津優秀博士論文、…