設計模式實戰:自定義SpringIOC(親手實踐)

上一篇:設計模式實戰:自定義SpringIOC(理論分析)

自定義SpringIOC(親手實踐)

上一篇文章,我們介紹了SpringIOC容器的核心組件及其作用,下面我們來動手仿寫一個SpringIOC容器,讓我們對SpringIOC容器理解地更加透徹!Start Go Go Go!

自定義SpringIOC

對下面的配置文件進行解析,并自定義SpringIOC,對涉及到的對象進行管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans><bean id="courseService" class="com.hopeful.service.impl.CourseServiceImpl"><property name="courseDao" ref="courseDao"></property></bean><bean id="courseDao" class="com.hopeful.dao.impl.CourseDaoImpl"></bean>
</beans>

1) 創建與Bean相關的pojo類

  • PropertyValue類: 用于封裝 bean 的屬性,體現到上面的配置文件就是封裝 bean 標簽的子標簽 property 標簽數據。

/*** 該類用來封裝bean標簽下的property子標簽的屬性*      1.name屬性*      2.ref屬性*      3.value屬性: 給基本數據類型及string類型數據賦的值**/
public class PropertyValue {private String name;private String ref;private String value;public PropertyValue() {}public PropertyValue(String name, String ref, String value) {this.name = name;this.ref = ref;this.value = value;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRef() {return ref;}public void setRef(String ref) {this.ref = ref;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}
}
  • MutablePropertyValues類: 一個bean標簽可以有多個property子標簽,所以再定義一個MutablePropertyValues類,用來存儲并管理多個PropertyValue對象。
package com.mashibing.framework.beans;import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;/*** 該類用來存儲和遍歷多個PropertyValue對象**/
public class MutablePropertyValues implements Iterable<PropertyValue>{//定義List集合,存儲PropertyValue的容器private final List<PropertyValue> propertyValueList;//空參構造中 初始化一個listpublic MutablePropertyValues() {this.propertyValueList = new ArrayList<PropertyValue>();}//有參構造 接收一個外部傳入的list,賦值propertyValueList屬性public MutablePropertyValues(List<PropertyValue> propertyValueList) {if(propertyValueList == null){this.propertyValueList = new ArrayList<PropertyValue>();}else{this.propertyValueList = propertyValueList;}}//獲取當前容器對應的迭代器對象@Overridepublic Iterator<PropertyValue> iterator() {//直接獲取List集合中的迭代器return propertyValueList.iterator();}//獲取所有的PropertyValuepublic PropertyValue[] getPropertyValues(){//將集合轉換為數組并返回return propertyValueList.toArray(new PropertyValue[0]); //new PropertyValue[0]聲明返回的數組類型}//根據name屬性值獲取PropertyValuepublic PropertyValue getPropertyValue(String propertyName){//遍歷集合對象for (PropertyValue propertyValue : propertyValueList) {if(propertyValue.getName().equals(propertyName)){return propertyValue;}}return null;}//判斷集合是否為空,是否存儲PropertyValuepublic boolean isEmpty(){return propertyValueList.isEmpty();}//向集合中添加public MutablePropertyValues addPropertyValue(PropertyValue value){//判斷集合中存儲的propertyvalue對象.是否重復,重復就進行覆蓋for (int i = 0; i < propertyValueList.size(); i++) {//獲取集合中每一個 PropertyValuePropertyValue currentPv = propertyValueList.get(i);//判斷當前的pv的name屬性 是否與傳入的相同,如果相同就覆蓋if(currentPv.getName().equals(value.getName())){propertyValueList.set(i,value);return this;}}//沒有重復this.propertyValueList.add(value);return this;  //目的是實現鏈式編程}//判斷是否有指定name屬性值的對象public boolean contains(String propertyName){return getPropertyValue(propertyName) != null;}
}
  • BeanDefinition類: 用來封裝 bean 信息的,主要包含id(即 bean 對象的名稱)、class(需要交由spring管理的類的全類名)及子標簽property數據。
/*** 封裝Bean標簽數據的類,包括id與class以及子標簽的數據**/
public class BeanDefinition {private String id;private String className;private MutablePropertyValues propertyValues;public BeanDefinition() {propertyValues = new MutablePropertyValues();}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public MutablePropertyValues getPropertyValues() {return propertyValues;}public void setPropertyValues(MutablePropertyValues propertyValues) {this.propertyValues = propertyValues;}
}

2) 創建注冊表相關的類

BeanDefinition 對象存取的操作, 其實是在BeanDefinitionRegistry接口中定義的,它被稱為是BeanDefinition的注冊中心。

//源碼
public interface BeanDefinitionRegistry extends AliasRegistry {void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;boolean containsBeanDefinition(String beanName);String[] getBeanDefinitionNames();int getBeanDefinitionCount();boolean isBeanNameInUse(String beanName);
}

BeanDefinitionRegistry繼承結構圖如下:

在這里插入圖片描述

BeanDefinitionRegistry接口的子實現類主要有以下兩個:

  • DefaultListableBeanFactory:在該類中定義了如下代碼,就是用來注冊bean

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    
  • SimpleBeanDefinitionRegistry:在該類中定義了如下代碼,就是用來注冊bean

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
    
  • 自定義BeanDefinitionRegistry接口定義了注冊表的相關操作,定義如下功能:
public interface BeanDefinitionRegistry {//注冊BeanDefinition對象到注冊表中void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);//從注冊表中刪除指定名稱的BeanDefinition對象void removeBeanDefinition(String beanName) throws Exception;//根據名稱從注冊表中獲取BeanDefinition對象BeanDefinition getBeanDefinition(String beanName) throws Exception;//判斷注冊表中是否包含指定名稱的BeanDefinition對象boolean containsBeanDefinition(String beanName);//獲取注冊表中BeanDefinition對象的個數int getBeanDefinitionCount();//獲取注冊表中所有的BeanDefinition的名稱String[] getBeanDefinitionNames();
}
  • SimpleBeanDefinitionRegistry類, 該類實現了BeanDefinitionRegistry接口,定義了Map集合作為注冊表容器。
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {beanDefinitionMap.put(beanName,beanDefinition);}@Overridepublic void removeBeanDefinition(String beanName) throws Exception {beanDefinitionMap.remove(beanName);}@Overridepublic BeanDefinition getBeanDefinition(String beanName) throws Exception {return beanDefinitionMap.get(beanName);}@Overridepublic boolean containsBeanDefinition(String beanName) {return beanDefinitionMap.containsKey(beanName);}@Overridepublic int getBeanDefinitionCount() {return beanDefinitionMap.size();}@Overridepublic String[] getBeanDefinitionNames() {return beanDefinitionMap.keySet().toArray(new String[1]);}
}

3) 創建解析器相關的類

BeanDefinitionReader 接口

  • BeanDefinitionReader 用來解析配置文件并在注冊表中注冊 bean 的信息。定義了兩個規范:
    • 獲取注冊表的功能,讓外界可以通過該對象獲取注冊表對象;
    • 加載配置文件,并注冊bean數據
/*** 該類定義解析配置文件規則的接口**/
public interface BeanDefinitionReader {//獲取注冊表對象BeanDefinitionRegistry getRegistry();//加載配置文件并在注冊表中進行注冊void loadBeanDefinitions(String configLocation) throws Exception;
}

XmlBeanDefinitionReader類

  • XmlBeanDefinitionReader 是專門用來解析 xml 配置文件的。該類實現 BeanDefinitionReader 接口并實現接口中的兩個功能。
/*** 該類是對XML文件進行解析的類**/
public class XmlBeanDefinitionReader implements BeanDefinitionReader {//聲明注冊表對象(將配置文件與注冊表解耦,通過Reader降低耦合性)private BeanDefinitionRegistry registry;public XmlBeanDefinitionReader() {registry = new SimpleBeanDefinitionRegistry();}@Overridepublic BeanDefinitionRegistry getRegistry() {return registry;}//加載配置文件@Overridepublic void loadBeanDefinitions(String configLocation) throws Exception {//使用dom4j解析xmlSAXReader reader = new SAXReader();//獲取配置文件,類路徑下InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);//獲取document文檔對象Document document = reader.read(is);Element rootElement = document.getRootElement();//解析bean標簽parseBean(rootElement);}private void parseBean(Element rootElement) {//獲取所有的bean標簽List<Element> elements = rootElement.elements();//遍歷獲取每個bean標簽的屬性值和子標簽propertyfor (Element element : elements) {String id = element.attributeValue("id");String className = element.attributeValue("class");//封裝到beanDefinitionBeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setId(id);beanDefinition.setClassName(className);//獲取propertyList<Element> list = element.elements("property");MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();//遍歷,封裝propertyValue,并保存到mutablePropertyValuesfor (Element element1 : list) {String name = element1.attributeValue("name");String ref = element1.attributeValue("ref");String value = element1.attributeValue("value");PropertyValue propertyValue = new PropertyValue(name,ref,value);mutablePropertyValues.addPropertyValue(propertyValue);}//將mutablePropertyValues封裝到beanDefinitionbeanDefinition.setPropertyValues(mutablePropertyValues);System.out.println(beanDefinition);//將beanDefinition注冊到注冊表registry.registerBeanDefinition(id,beanDefinition);}}
}

4) 創建IOC容器相關的類

1) BeanFactory接口

在該接口中定義 IOC 容器的統一規范和獲取bean對象的方法。

/*** IOC容器父接口**/
public interface BeanFactory {Object getBean(String name)throws Exception;//泛型方法,傳入當前類或者其子類<T> T getBean(String name ,Class<? extends T> clazz)throws Exception;
}

2) ApplicationContext 接口

該接口的所有的子實現類對 bean 對象的創建都是非延時的,所以在該接口中定義 refresh() 方法,該方法主要完成以下兩個功能:

  • 加載配置文件。
  • 根據注冊表中的 BeanDefinition 對象封裝的數據進行 bean 對象的創建。
/*** 定義非延時加載功能**/
public interface ApplicationContext extends BeanFactory {//進行配置文件加載,并進行對象創建void refresh();
}

3) AbstractApplicationContext類

  • 作為 ApplicationContext 接口的子類,所以該類也是非延時加載,所以需要在該類中定義一個Map集合,作為bean對象存儲的容器。
  • 聲明 BeanDefinitionReader 類型的變量,用來進行 xml 配置文件的解析,符合單一職責原則。
  • BeanDefinitionReader 類型的對象創建交由子類實現,因為只有子類明確到底創建BeanDefinitionReader 哪兒個子實現類對象。
/*** ApplicationContext接口的子實現類*      創建容器對象時,加載配置文件,對bean進行初始化**/
public abstract class AbstractApplicationContext implements ApplicationContext {//聲明解析器變量protected BeanDefinitionReader beanDefinitionReader;//定義存儲bean對象的Map集合protected Map<String,Object> singletonObjects = new HashMap<>();//聲明配置文件類路徑的變量protected String configLocation;@Overridepublic void refresh() {//加載beanDefinition對象try {beanDefinitionReader.loadBeanDefinitions(configLocation);//初始化beanfinishBeanInitialization();} catch (Exception e) {e.printStackTrace();}}//bean初始化protected  void finishBeanInitialization() throws Exception {//獲取對應的注冊表對象BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();//獲取beanDefinition對象String[] beanNames = registry.getBeanDefinitionNames();for (String beanName : beanNames) {//進行bean的初始化getBean(beanName);}};
}

4) ClassPathXmlApplicationContext類

該類主要是加載類路徑下的配置文件,并進行 bean 對象的創建,主要完成以下功能:

  • 在構造方法中,創建 BeanDefinitionReader 對象。
  • 在構造方法中,調用 refresh() 方法,用于進行配置文件加載、創建 bean 對象并存儲到容器中。
  • 重寫父接口中的 getBean() 方法,并實現依賴注入操作。
/*** IOC容器具體的子實現類,加載XML格式配置文件**/
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{public ClassPathXmlApplicationContext(String configLocation) {this.configLocation = configLocation;//構建解析器對象this.beanDefinitionReader = new XmlBeanDefinitionReader();this.refresh();}//跟據bean的對象名稱獲取bean對象@Overridepublic Object getBean(String name) throws Exception {//判斷對象容器中是否包含指定名稱的bean對象,如果包含就返回,否則自行創建Object obj = singletonObjects.get(name);if(obj != null){return obj;}//自行創建,獲取beanDefinition對象BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();BeanDefinition beanDefinition = registry.getBeanDefinition(name);//通過反射創建對象String className = beanDefinition.getClassName();Class<?> clazz = Class.forName(className);Object beanObj = clazz.newInstance();//CourseService與UserDao存依賴,所以要將UserDao一同初始化,進行依賴注入MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();for (PropertyValue propertyValue : propertyValues) {//獲取name屬性值String propertyName = propertyValue.getName();//獲取Value屬性String value = propertyValue.getValue();//獲取ref屬性String ref = propertyValue.getRef();//ref與value只能存在一個if(ref != null && !"".equals(ref)){//獲取依賴的bean對象,拼接set set+CourseObject bean = getBean(ref);String methodName = StringUtils.getSetterMethodFieldName(propertyName);//獲取所有方法對象Method[] methods = clazz.getMethods();for (Method method : methods) {if(methodName.equals(method.getName())){//執行該set方法method.invoke(beanObj,bean);}}}if(value != null && !"".equals(value)){String methodName = StringUtils.getSetterMethodFieldName(propertyName);//獲取methodMethod method = clazz.getMethod(methodName, String.class);method.invoke(beanObj,value);}}//在返回beanObj之前 ,需要將對象存儲到Map容器中this.singletonObjects.put(name,beanObj);return beanObj;}@Overridepublic <T> T getBean(String name, Class<? extends T> clazz) throws Exception {Object bean = getBean(name);if(bean == null){return null;}return clazz.cast(bean);}
}

5) 自定義IOC容器測試

第一步: 將我們寫好的自定義IOC容器項目,安裝到maven倉庫中,使其他項目可以引入其依賴

//依賴信息
<dependencies><dependency><groupId>com.hopeful</groupId><artifactId>user_defined_springioc</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>

第二步: 創建一個新的maven項目,引入上面的依賴

第三步: 完成代碼編寫

  • dao
public interface CourseDao {public void add();
}public class CourseDaoImpl implements CourseDao {//value注入private String courseName;public String getCourseName() {return courseName;}public void setCourseName(String courseName) {this.courseName = courseName;}public CourseDaoImpl() {System.out.println("CourseDaoImpl創建了......");}@Overridepublic void add() {System.out.println("CourseDaoImpl的add方法執行了......" + courseName);}
}
  • service
public interface CourseService {public void add();
}public class CourseServiceImpl implements CourseService {public CourseServiceImpl() {System.out.println("CourseServiceImpl創建了......");}private CourseDao courseDao;public void setCourseDao(CourseDao courseDao) {this.courseDao = courseDao;}@Overridepublic void add() {System.out.println("CourseServiceImpl的add方法執行了......");courseDao.add();}
}
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans><bean id="courseService" class="com.mashibing.test_springioc.service.impl.CourseServiceImpl"><property name="courseDao" ref="courseDao"></property></bean><bean id="courseDao" class="com.mashibing.test_springioc.dao.impl.CourseDaoImpl"><property name="courseName" value="java"></property></bean>
</beans>
  • Controller
public class CourseController{public static void main(String[] args) {//1.創建Spring的容器對象ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//2.從容器對象中獲取CourseService對象CourseService courseService = context.getBean("courseService", CourseService.class);//3.調用UserService的add方法courseService.add();}
}

在此,我們就已經實現了專屬自己的IOC容器,是不是突然發現平時感覺很高深的Sping IoC容器也不是那么復雜!離大佬又近了一步,哈哈!

6) 案例中使用到的設計模式

  • 工廠模式:這個使用工廠模式 + 配置文件的方式。
  • 單例模式:Spring IOC管理的bean對象都是單例的,此處的單例不是通過構造器進行單例的控制的,而是spring框架對每一個bean只創建了一個對象。
  • 模板方法模式:AbstractApplicationContext 類中的 finishBeanInitialization() 方法調用了子類的 getBean() 方法,因為 getBean() 的實現和環境息息相關。
  • 迭代器模式。對于 MutablePropertyValues 類定義使用到了迭代器模式,因為此類存儲并管理PropertyValue 對象,也屬于一個容器,所以給該容器提供一個遍歷方式。

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

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

相關文章

力扣面試150(42/150)

7.28 20. 有效的括號 給定一個只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判斷字符串是否有效。 有效字符串需滿足&#xff1a; 左括號必須用相同類型的右括號閉合。左括號必須以正確的順序閉合。每個右括號都有一…

基于黑馬教程——微服務架構解析(二):雪崩防護+分布式事務

之前的兩篇文章我們介紹了微服務的基礎概念及其服務間通信機制。本篇將深入探討微服務的核心保障&#xff1a;服務保護與分布式事務。一、微服務保護問題描述&#xff1a; 在一個購物車的微服務中&#xff0c;倘若某一項服務&#xff08;服務A&#xff09;同一時刻訪問的數據十…

LeetCode: 429 N叉樹的層序遍歷

題目描述給定一個 N 叉樹&#xff0c;返回其節點值的層序遍歷&#xff08;即從左到右&#xff0c;逐層訪問每一層的所有節點&#xff09;。示例輸入格式&#xff08;層序序列化&#xff09;&#xff1a;輸入示意&#xff1a;1/ | \3 2 4/ \5 6輸出&#xff1a;[[1], [3,2,4…

使用phpstudy極簡快速安裝mysql

使用 phpStudy 極簡快速安裝 MySQL 的完整指南&#xff1a; 一、phpStudy 簡介 phpStudy 是一款 Windows 平臺下的 PHP 環境集成包&#xff0c;包含&#xff1a; Apache/Nginx PHP 5.x-7.x MySQL 5.5-8.0 phpMyAdmin 二、安裝步驟 1. 下載安裝包 訪問官網下載&#xf…

git lfs使用

apt install git lfs 或者下載二進制文件加到環境變量 https://github.com/git-lfs/git-lfs/releases git lfs install git lfs clone huggingface文件路徑 如果訪問不了hugggingface.co用hf-mirror.com替代&#xff0c;國內下載速度還是挺快的 先按照pip install modelscope m…

6、CentOS 9 安裝 Docker

&#x1f433; CentOS 9 安裝 Docker 最全圖文教程&#xff08;含鏡像源優化與常見問題解決&#xff09;標簽&#xff1a;CentOS 9、Docker、容器技術、開發環境、國內鏡像源 適合讀者&#xff1a;后端開發、運維工程師、Linux 初學者&#x1f4cc; 前言 在 CentOS 9 上安裝 Do…

SystemV消息隊列揭秘:原理與實戰

目錄 一、消息隊列的基本原理 1、基本概念 2、基本原理 3、消息類型的關鍵作用 4、重要特性總結 5、生命周期管理 6、典型應用場景 二、System V 消息隊列的內核數據結構 1、消息隊列的管理結構 msqid_ds&#xff08;消息隊列標識符結構&#xff09; 關鍵字段解析 2…

5 分鐘上手 Firecrawl

文章目錄Firecrawl 是什么&#xff1f;本地部署驗證mcp安裝palyground&#x1f525; 5 分鐘上手 FirecrawlFirecrawl 是什么&#xff1f; 一句話&#xff1a; 開源版的 “最強網頁爬蟲 清洗引擎” ? 自動把任意網頁 → 結構化 Markdown / JSON ? 支持遞歸整站抓取、JS 渲染…

算法訓練營day31 貪心算法⑤56. 合并區間、738.單調遞增的數字 、968.監控二叉樹

貪心算法的最后一篇博客&#xff01;前面兩道題都是比較簡單的思路&#xff0c;重點理解一下最后一道題即可。有一說一&#xff0c;進入到貪心算法這一章節之后&#xff0c;我的博客里和代碼注釋里的內容明顯少了很多&#xff0c;因為很多貪心的題目我覺得不需要很復雜的文字說…

Jenkins流水線部署+webhook2.0

文章目錄1. 環境2. 用到的插件3. 流水線部署腳本1. 環境 Centos7Jenkins2.5.0JDKopen17阿里云倉庫 注意&#xff1a;這個版本兼容需要特別注意&#xff0c;要不然會很麻煩 2. 用到的插件 Generic Webhook Trigger 3. 流水線部署腳本 兼容鉤子部署&#xff08;webhook&…

IDM下載失敗排查

網絡連接問題排查檢查網絡連接是否穩定&#xff0c;確保能夠正常訪問互聯網 測試其他下載工具或瀏覽器是否能夠正常下載 嘗試關閉防火墻或殺毒軟件&#xff0c;排除安全軟件攔截的可能性代理和VPN設置檢查確認IDM的代理設置是否正確&#xff0c;是否與系統代理一致 檢查是否使用…

Anaconda安裝時的幾個操作

一、安裝Anaconda 其實Anaconda的安裝比較簡單&#xff0c;點擊next就好了。在安裝中需要注意以下兩點&#xff1a; 1、選擇安裝路徑 在安裝時&#xff0c;路徑最好選擇非C盤&#xff0c;且路徑中不要出現中文&#xff0c;以免后期運行代碼時出現不必要的錯誤。 我安裝時&…

網易易盾、騰訊ACE等主流10款游戲反外掛系統對比

本文將深入對比10款游戲反外掛系統&#xff1a;1.網易易盾&#xff1b;2.Ricochet Anti?Cheat&#xff1b;3.BattlEye&#xff1b;4.幾維安全手游智能反外掛系統&#xff1b;5.伏魔AI反外掛&#xff1b;6.Riot Vanguard&#xff1b;7.Xigncode3&#xff1b;8.盛大GPK&#xff…

wpa_supplicant-2.10交叉編譯

參考文章:https://blog.csdn.net/weixin_45783574/article/details/145810790 1、Openssl交叉編譯 1.1 下載openssl-1.1.1t.tar.gz 下載網址: https://openssl-library.org/source/old/1.1.1/index.html1.2 編譯 sudo tar xvf openssl-1.1.1t.tar.gz cd openssl-1.1

源碼解讀SpringCloudAlibaba Nacos2.x

Nacos 服務注冊 Nacos 服務注冊時&#xff0c;客戶端會將自己的信息注冊到Nicosserver上&#xff0c;形成key-value組合&#xff0c;其中key通常是服務名稱&#xff0c;value是實例地址信息。在二點X版本中&#xff0c;客戶端通過Spring Boot的擴展機制(例如web_initialized事件…

Windows 11 下 Anaconda 命令修復指南及常見問題解決

Windows 11 下 Anaconda 命令修復指南及常見問題解決 在使用 Anaconda 過程中&#xff0c;可能會遇到環境損壞、更新失敗、包依賴沖突等問題。本文整理了一套通過命令行修復 Anaconda 的完整方案&#xff0c;適用于 Windows 11 系統&#xff0c;同時補充了權威參考鏈接供深入學…

安寶特案例丨全球連線!安寶特Vuzix與RodsCones共筑實時手術教育平臺

安寶特Vuzix與合作伙伴Rods&Cones協作&#xff0c;為Rocamed在布拉格UROSANIT診所舉辦的創新型實時手術直播研討會提供技術賦能。 本次直播通過合作伙伴Rods&Cones軟件平臺搭載安寶特Vuzix智能眼鏡&#xff0c;成功連接來自9國、3大洲、6個時區的27位醫生&#xff0c;…

【Spring Boot 快速開發】一、入門

目錄Spring Boot 簡介Web 入門Spring Boot 快速入門HTTP 協議概述請求協議響應協議解析協議TomcatSpring Boot 簡介 Spring Boot 是由 Pivotal 團隊&#xff08;后被 VMware 收購&#xff09;開發的基于 Spring 框架的開源項目&#xff0c;于 2014 年首次發布。其核心目標是簡…

laravel chunkById導出數據亂序問題

2025年7月28日17:47:29 這幾天在做數據導出優化&#xff0c;使用xlswriter作為導出組件&#xff0c;但是發現在 使用 $base->chunkById(2000, function ($list) use ($writer, $sheet1) { 發現導出的數據是亂的&#xff0c;偶爾有些重復&#xff0c;偶爾有些少了&#xff0c…

Spring IOC與DI

spring的兩大思想:IOC與AOP一、ioc的概念什么叫控制翻轉?之前:對象的使用方,創建對象,對象的控制權,在對象的使用方手中.spring:對象的控制權交給了spring.舉個例子:智能駕駛,之前車的使用權在人手中,而現在在ai手中,這就是控制反轉.什么叫ioc:之前車企生產車需要做整個車,費事…