简单手写SpringIOC框架
环境搭建
基于XML方式
项目结构
项目代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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</groupId><artifactId>spring</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.1.RELEASE</version></dependency></dependencies></project>
UserBean.java
packagecom.spring.bean;/**
* @author honey
* @date 2023-08-08 14:58:16
*/publicclassUserBean{}
spring.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><beanid="userBean"class="com.spring.bean.UserBean"/></beans>
SpringTest01.java
packagecom.spring.test;importcom.spring.bean.UserBean;importorg.springframework.context.support.ClassPathXmlApplicationContext;/**
* @author honey
* @date 2023-08-08 14:59:56
*/publicclassSpringTest01{publicstaticvoidmain(String[] args){// 读取spring.xmlClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext("spring.xml");// 从IOC容器中读取对象UserBean userBean = applicationContext.getBean("userBean",UserBean.class);System.out.println(userBean);}}
运行结果
基于注解方式
项目结构
项目代码
ScanBean.java
packagecom.spring.bean.scan;importorg.springframework.stereotype.Component;/**
* @author honey
* @date 2023-08-08 16:37:26
*/@ComponentpublicclassScanBean{}
SpringConfig.java
packagecom.spring.config;importcom.spring.bean.UserBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;/**
* @author honey
* @date 2023-08-08 16:30:21
*/@Configuration@ComponentScan(value ={"com.spring.bean.scan"})publicclassSpringConfig{@Bean(name ="user")publicUserBeanuserBean(){returnnewUserBean();}}
SpringTest02.java
packagecom.spring.test;importcom.spring.bean.UserBean;importcom.spring.bean.scan.ScanBean;importcom.spring.config.SpringConfig;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;/**
* @author honey
* @date 2023-08-08 16:31:25
*/publicclassSpringTest02{publicstaticvoidmain(String[] args){// 加载SpringConfigAnnotationConfigApplicationContext applicationContext =newAnnotationConfigApplicationContext(SpringConfig.class);// 从IOC容器中读取对象UserBean userBean = applicationContext.getBean("user",UserBean.class);System.out.println(userBean);ScanBean scanBean = applicationContext.getBean("scanBean",ScanBean.class);System.out.println(scanBean);}}
运行结果
简单手写SpringIOC框架
核心原理
底层使用map集合管理对象,key=beanId,value=实例对象
privatefinalMap<String,Object> beanMap =newConcurrentHashMap<>();
基于XML方式
原理
基于反射+工厂模式+DOM技术
- 使用DOM技术解析spring.xml文件;
- 获取bean的id和class属性;
- 根据类的完整路径使用反射技术初始化对象;
- 使用工厂模式管理初始化对象;
项目结构
项目代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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</groupId><artifactId>ext-spring-ioc</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency></dependencies></project>
UserBean.java
packagecom.spring.bean;/**
* @author honey
* @date 2023-08-08 16:56:32
*/publicclassUserBean{}
spring.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><beanid="userBean"class="com.spring.bean.UserBean"/></beans>
SpringIocXml.java
packagecom.spring.ext;importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.io.SAXReader;importorg.springframework.core.io.ClassPathResource;importjava.io.File;importjava.io.IOException;importjava.util.List;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/**
* @author honey
* @date 2023-08-08 16:57:17
*/publicclassSpringIocXml{privatefinalMap<String,Object> beanMap =newConcurrentHashMap<>();publicSpringIocXml()throwsIOException,DocumentException{init();}public<T>TgetBean(String name){return(T) beanMap.get(name);}/**
* 初始化IOC容器
*/privatevoidinit()throwsIOException,DocumentException{// 解析spring.xml配置ClassPathResource classPathResource =newClassPathResource("spring.xml");File xmlFile = classPathResource.getFile();SAXReader saxReader =newSAXReader();Document doc = saxReader.read(xmlFile);// 获取根节点Element rootElement = doc.getRootElement();// 获取bean节点信息List<Element> beans = rootElement.elements("bean");for(Element bean : beans){try{String beanId = bean.attribute("id").getValue();String classPath = bean.attribute("class").getValue();// 使用反射机制初始化对象,并将对象存入Map集合Class<?> clazz =Class.forName(classPath);Object object = clazz.newInstance();
beanMap.put(beanId, object);}catch(Exception e){
e.printStackTrace();}}}}
SpringTest01.java
packagecom.spring.test;importcom.spring.bean.UserBean;importcom.spring.ext.SpringIocXml;importorg.dom4j.DocumentException;importjava.io.IOException;/**
* @author honey
* @date 2023-08-08 17:04:35
*/publicclassSpringTest01{publicstaticvoidmain(String[] args)throwsDocumentException,IOException{SpringIocXml springIocXml =newSpringIocXml();UserBean userBean = springIocXml.getBean("userBean");System.out.println(userBean);}}
运行结果
基于注解方式
原理
基于反射+工厂模式实现
- 判断配置类上是否有@Configuration注解;
- 获取配置类中的所有方法,判断方法上是否有@Bean注解,如果有则获取方法的返回值作为实例对象;
- 判断配置类上是否有@ComponentScan注解,如果有则扫描指定包下的所有类,并判断类上是否有@Component注解,如果有则通过反射技术初始化对象;
- 使用工厂模式管理初始化对象/实例对象;
项目结构
项目代码
pom.xml
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.7</version></dependency>
ScanBean.java
packagecom.spring.bean.scan;importorg.springframework.stereotype.Component;/**
* @author honey
* @date 2023-08-09 14:28:33
*/@ComponentpublicclassScanBean{}
SpringConfig.java
packagecom.spring.config;importcom.spring.bean.UserBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;/**
* @author honey
* @date 2023-08-09 14:26:40
*/@Configuration@ComponentScan(value ={"com.spring.bean.scan"})publicclassSpringConfig{@BeanpublicUserBeanuserBean(){returnnewUserBean();}}
SpringIocAnnotation.java
packagecom.spring.ext;importcn.hutool.core.lang.ClassScanner;importcn.hutool.core.util.StrUtil;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;importorg.springframework.stereotype.Component;importjava.lang.annotation.Annotation;importjava.lang.reflect.Method;importjava.util.Map;importjava.util.Set;importjava.util.concurrent.ConcurrentHashMap;/**
* @author honey
* @date 2023-08-09 14:12:21
*/publicclassSpringIocAnnotation{privatefinalObject config;privatefinalMap<String,Object> beanMap =newConcurrentHashMap<>();publicSpringIocAnnotation(Object config){this.config = config;init();}/**
* 初始化IOC容器
*/publicvoidinit(){// 判断配置类上是否有@Configuration注解Configuration configuration =this.config.getClass().getDeclaredAnnotation(Configuration.class);if(configuration ==null){return;}// 处理@Bean注解Class<?> clazz = config.getClass();Method[] declaredMethods = clazz.getDeclaredMethods();for(Method method : declaredMethods){// 判断方法上是否有@Bean注解Bean bean = method.getDeclaredAnnotation(Bean.class);if(bean !=null){try{// 获取beanIdString[] value = bean.value();String beanId = value.length >0? value[0]: method.getName();// 获取方法的返回值Object object = method.invoke(config);
beanMap.put(beanId, object);}catch(Exception e){
e.printStackTrace();}}}// 处理@Component注解ComponentScan componentScan = clazz.getDeclaredAnnotation(ComponentScan.class);if(componentScan !=null){for(String packageName : componentScan.value()){try{// 扫描指定包下的所有类Set<Class<?>> classes =ClassScanner.scanPackage(packageName);for(Class<?> c : classes){// 判断类上是否有@Component注解Annotation component = c.getDeclaredAnnotation(Component.class);if(component !=null){try{// 获取beanIdString beanId =StrUtil.lowerFirst(c.getSimpleName());// 通过反射技术初始化对象Object beanObject = c.newInstance();
beanMap.put(beanId, beanObject);}catch(Exception e){
e.printStackTrace();}}}}catch(Exception e){
e.printStackTrace();}}}}public<T>TgetBean(String name){return(T) beanMap.get(name);}}
SpringTest02.java
packagecom.spring.test;importcom.spring.bean.UserBean;importcom.spring.bean.scan.ScanBean;importcom.spring.config.SpringConfig;importcom.spring.ext.SpringIocAnnotation;/**
* @author honey
* @date 2023-08-09 14:24:36
*/publicclassSpringTest02{publicstaticvoidmain(String[] args){SpringIocAnnotation springIocAnnotation =newSpringIocAnnotation(newSpringConfig());UserBean userBean = springIocAnnotation.getBean("userBean");System.out.println(userBean);ScanBean scanBean = springIocAnnotation.getBean("scanBean");System.out.println(scanBean);}}
运行结果
版权归原作者 Mr. Cappuccino 所有, 如有侵权,请联系我们删除。