手写Spring框架

news/2024/10/9 16:31:22

1. 手写Spring框架

@

目录
  • 1. 手写Spring框架
  • 每博一文案
  • 2. 反射机制的回顾
  • 3. 开始手写 Spring 框架
    • 3.1 第一步:使用 IDE 创建模块myspring
    • 3.2 第二步:准备好我们要管理的Bean
    • 3.3 第三步:准备myspring.xml配置文件
    • 3.4 第四步:编写ApplicationContext接口
    • 3.5 第五步:编写ClassPathXmlApplicationContext
    • 3.6 第六步:确定采用Map集合存储Bean
    • 3.7 第七步:解析配置文件,并实例化所有Bean
    • 3.8 第八步:测试能否获取到Bean
    • 3.9 第九步:给Bean的属性赋值
    • 3.10 第十步:测试是否能够正常赋值成功
    • 3.11 第十一步:打包发布
    • 3.12 第十二步: 站在程序员角度使用我们自己手写的 spring 的 myspring框架
  • 4. 总结:
  • 5. 最后:


每博一文案

特别喜欢一种人
他们的知识储备和信息密度,都远远高于我
但还是愿意认真听我说,那些没有营养的废话
我始终觉得,温柔浪漫跟博学,是人身上最难得的特性
懂得向下兼容的人,走到哪里都是宝藏
太喜欢哪些优秀,却不带优越感的人相处了

2. 反射机制的回顾

我们知道框架一般是由 设计模式+注解+反射 来实现,并进行运用开发的。

所以我们要手写 Spring 框架,就需要先来回顾,回顾Java当中的反射机制,这里是简单的回顾反射 。关于反射机制更加详细的内容,大家可以移步至✏️✏️✏️ Java “框架 = 注解 + 反射 + 设计模式” 之 反射详解-CSDN博客 。

我们知道,想要调用一个方法,就需要明确知道该方法的四个要素:

  1. 调用的是哪个对象的
  2. 哪个方法
  3. 该方法传什么参数
  4. 有无返回值,有返回值的话,又该返回什么值

为了简单的回顾我们的反射机制,下面我们进行一个简单的任务。完成下面的需求

首先你知道以下这几条信息

假设你现在以下信息:1.有这样一个类,类名叫做:com.rainbowsea.reflect.User2.这个类符合javabean规范,属性私有化,对外提供公开的setter和getter方法。3.你还知道这个类当中有一个属性,属性的名字叫做 age4.并且你还知道age属性的类型是 int 类型
请使用反射机制调用set()方法,给 User 对象的age 属性赋值(age 属性赋值为 20 )

在这里插入图片描述

package com.rainbowsea.reflect;public class User {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

下面通过反射机制,获取到为 age 属性值进行赋值操作。在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.test;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class Test2 {/*需求:假设你现在以下信息:1.有这样一个类,类名叫做:com.powernode.reflect.User2.这个类符合javabean规范,属性私有化,对外提供公开的setter和getter方法。3.你还知道这个类当中有一个属性,属性的名字叫做 age4.并且你还知道age属性的类型是 int 类型请使用反射机制调用set()方法,给 User 对象的age 属性赋值*/public static void main(String[] args) {String className = "com.rainbowsea.reflect.User";String propertyName = "age";try {// 通过 反射机制调用setAge(int) 方法// 获取到对应的类Class<?> clazz = Class.forName(className);// 获取对应的方法// 方法名: 这里我们知道set 方法格式为: setAge() set+属性名的首字母大小+后面属性名的小写字母String setMethodName = "set" + propertyName.toUpperCase().charAt(0)+ propertyName.substring(1);// 获取对应的方法名:// 我们知道的属性名就可以,根据属性名获取属性类型// 下面这里获取到的是一个完整的:private int com.rainbowsea.reflect.User.age 类型名Field field = clazz.getDeclaredField(propertyName);// field.getType() 获取到属性的类型,是个简单的类型 intMethod declaredMethod = clazz.getDeclaredMethod(setMethodName, field.getType());//System.out.println(field.getType());// 准备对象Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();Object obj = declaredConstructor.newInstance();// 调用set()方法赋值, 没有返回值(调用 obj 的对象中的,declaredMethod()方法,参数是 30,没有返回值)declaredMethod.invoke(obj,30);System.out.println(obj);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}
}

在这里插入图片描述
成功了,哪我们反射机制就算简单回顾完了,该上正菜了——》手写 Spring 框架


3. 开始手写 Spring 框架

Spring IoC容器的实现原理:工厂模式 + 解析XML + 反射机制
我们给自己的框架起名为:myspring(我的春天)

3.1 第一步:使用 IDE 创建模块myspring

这里我们采用 IDE 当中的Maven 创建一个 名为 myspring的 Module。

在这里插入图片描述

注意:这里是 org.myspringframework 我们现在的角色是一个spring开发者人员。所以我们的包名的命名格式还是要规定一下的。

在这里插入图片描述

打包方式采用 jar,并且还需要引入 dom4jjaxen的依赖,因为要使用它解析XML文件,还有junit依赖。(进行测试)。有上面三个就可以了,这里的话,我再引入一个 log4j2 的依赖,用于日志信息的显示记录。因为我们这里是,自己手写 Spring 框架,所以就不要再引入 Spring的 jar 包内容了。

在这里插入图片描述
在这里插入图片描述

<?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.rainbowsea</groupId><artifactId>myspring</artifactId><version>1.0-SNAPSHOT</version>
<!--    打包方式为 jar --><packaging>jar</packaging><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies>
<!--        dom4j是一个能够解析xml文件的java组件--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency><dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.2.0</version></dependency><!--        单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--        log4j2的依赖--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.19.0</version></dependency></dependencies></project>

3.2 第二步:准备好我们要管理的Bean

准备好我们要管理的Bean(这些Bean在将来开发完框架之后是要删除的
注意包名,不要用 org.myspringframework包了,因为这些Bean不是框架内置的,是将来使用我们写好 Spring 框架方便我们后续测试,基于便于我们手写 Spring 框架进行思考,所以这里我就定义为了。com.rainbowsea.myspring.bean 大家可以自行定义

一共定义了 三个 Bean :User,UserService,UserDao

在这里插入图片描述

package com.rainbowsea.myspring.bean;public class User {private String name;private int age;public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
package com.rainbowsea.myspring.bean;public class UserDao {public void insert() {System.out.println("数据库插入数据");}
}
package com.rainbowsea.myspring.bean;public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save() {userDao.insert();}
}

3.3 第三步:准备myspring.xml配置文件

将来在框架开发完毕之后,这个文件也是要删除的。因为这个配置文件的提供者应该是使用这个框架的程序员。这里我是同样也是为了,用于验证测试,我们手写额Spring框架的。文件名随意,我们这里叫做:myspring.xml。文件放在类路径当中即可,我们这里把文件放到类的根路径下。使用value给简单属性赋值。使用ref给非简单属性赋值。

在这里插入图片描述
因为上面我配置了引入一个 log4j2 的依赖,用于日志信息的显示记录。所以这里,我们还需配置一个关于 log4j2 的配置文件。

在这里插入图片描述

3.4 第四步:编写ApplicationContext接口

ApplicationContext 接口中提供一个getBean()方法,通过该方法可以获取Bean对象。
注意包名:这个接口就是myspring框架中的一员了。

在这里插入图片描述

3.5 第五步:编写ClassPathXmlApplicationContext

ClassPathXmlApplicationContext 是 ApplicationContext 接口的实现类。该类从类路径当中加载myspring.xml 配置文件。

在这里插入图片描述

package org.myspringframework.core;public class ClassPathXmlApplicationContext implements ApplicationContext {@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

3.6 第六步:确定采用Map集合存储Bean

确定采用Map集合存储Bean实例。Map集合的key存储 beanId,value存储Bean实例。Map<String,Object>
在ClassPathXmlApplicationContext类中添加 Map<String,Object>属性。
并且在ClassPathXmlApplicationContext类中添加构造方法,该构造方法的参数接收myspring.xml文件。
同时实现getBean方法。

在这里插入图片描述

package org.myspringframework.core;import java.util.HashMap;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中private Map<String, Object> singletonObjects = new HashMap<>();}@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

3.7 第七步:解析配置文件,并实例化所有Bean

在 ClassPathXmlApplicationContext 的构造方法中解析配置文件,获取所有bean的类名,通过反射机制调用无参数构造方法创建Bean。并且将Bean对象存放到Map集合中。

补充:

首先我们需要,获取到一个名为 SAXReader(这是dom4j 解析xml 文件的核心对象) 的对象以及Document ,用来读取我们当中的myspring.xml'所含的 bean 的配置信息。这两个对象可以读取到 xml 配置文件的信息。

在这里插入图片描述
在这里插入图片描述
同时需要:注意的是:在 java 当中一个 ”//“ 才表示为一个 /

在这里插入图片描述
注意一个向下转型:向下转型的目的是为了使用Element接口更加丰富的方法。

该 Element 可以获取到 <bean> 标签当中的 id 的属性值,和 <bean>标签当中的 class 属性的值

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

package org.myspringframework.core;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中private Map<String, Object> singletonObjects = new HashMap<>();/*** 解析myspring的配置文件,然后初始化所有的Bean对象** @param configLocation spring配置文件的路径,注意:使用的是ClassPathXmlApplicationContext ,所以*                       配置文件应当放到类路径下*/public ClassPathXmlApplicationContext(String configLocation) {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中// 这是dom4j 解析xml 文件的核心对象SAXReader saxReader = new SAXReader();Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);// 获取一个输入流,指向配置文件InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);try {// 读文件Document document = saxReader.read(in);// 获取到所有的 <bean>标签// 注意要两个//,才能表示一个 /List<Node> nodes = document.selectNodes("//bean");// 遍历 bean标签nodes.forEach(node -> {//System.out.println(node);// 向下转型的目的是为了使用Element接口更加丰富的方法Element beanElt = (Element) node;// 获取 <bean>标签当中的id的属性String id = beanElt.attributeValue("id");// 获取 <bean>标签当中的 class 属性String className = beanElt.attributeValue("class");//logger.info("beanName" + id);//logger.info("beanClassName " + className);try {// 通过反射机制创建对象,将其放到Map集合中,提前曝光// 获取class对象Class<?> aClass = Class.forName(className);// 获取无参构造方法实例化BeanConstructor<?> declaredCon = aClass.getDeclaredConstructor();// 调用无参构造方法实例化BeanObject bean = declaredCon.newInstance();// 将Bean 曝光,加入 Map集合singletonObjects.put(id, bean);// 记录日志logger.info(singletonObjects.toString());} catch (Exception e) {e.printStackTrace();}});} catch (Exception e) {e.printStackTrace();}
}@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

3.8 第八步:测试能否获取到Bean

在这里插入图片描述

package com.rainbowsea.myspring.test;import com.rainbowsea.myspring.bean.UserService;
import org.junit.Test;
import org.myspringframework.core.ApplicationContext;
import org.myspringframework.core.ClassPathXmlApplicationContext;public class MySpringTest {@Testpublic void testMySpring() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("myspring.xml");Object user = applicationContext.getBean("user");System.out.println(user);}
}

我们的 myspring.xml 配置文件当中,有三个 bean 对象的配置信息,所以下面应当显示三个 Bean的实例对象。如下显示结果,我们可以看出,是成功获取到了 myspring.xml 配置文件当中所有的 Bean 对象了。

在这里插入图片描述
通过测试Bean已经实例化成功了,属性的值是null,这是我们能够想到的,毕竟我们调用的是无参数构造方法,所以属性都是默认值。
下一步就是我们应该如何给Bean的属性赋值了。

3.9 第九步:给Bean的属性赋值

通过反射机制调用set方法,给Bean的属性赋值。
继续在ClassPathXmlApplicationContext构造方法中编写代码。
补充说明:

我们需要,再次重新把所有的 Bean 标签遍历一次,这一次主要是给对象属性赋值的

在这里插入图片描述
获取到 获取该标签下的所有的属性为 <property>标签,因为 在 <property> 标签当中存放着,我们对属性赋值要的确切的值。

在这里插入图片描述
赋值,这里我们是通过 set 方法进行赋值的,这个简单,我们可以通过反射(对象,方法名,方法参数类型)获取到方法的对象,又可以通过属性名,获取到属性的类型。

在这里插入图片描述
这里最难的部分就是,在我们的 在 <property> 标签当中存放着,我们对属性赋值要的确切的值。但是这个值有两种:简单类型 value 的值,复杂类型 ref 的值。复杂类型就是引用类型,这个我们以及在曝光的时候,就存储到Map当中去了,我们只需要通过对应的beanName 从 Map当前取出来,再通过反射机制调用set方法进行一个赋值。

在这里插入图片描述

简单类型的赋值操作:

简单类型的复杂点,就是一个转换,我们再 myspring.xml 配置文件当中的,属性值都是以字符串的形式存在的,而我们的实际属性的类型,可能是 int,char,double 等等类型的,String 字符串类型不可以直接赋值到其他 int,char 类型当中去,所以我们就需要对我们所赋值的属性进行一个判断,如果该类型是 int 类型,我们就需要将 String 字符串类型转换为我们所需要的 int 类型。

这里我们说明一下:

我们myspring框架说明以下,我们只支持这些类型为简单类型
byte short int long float double boolean char
Byte Short Intger Long Float Double Boolean Character
String*/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完整代码:

package org.myspringframework.core;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中private Map<String, Object> singletonObjects = new HashMap<>();/*** 解析myspring的配置文件,然后初始化所有的Bean对象** @param configLocation spring配置文件的路径,注意:使用的是ClassPathXmlApplicationContext ,所以*                       配置文件应当放到类路径下*/public ClassPathXmlApplicationContext(String configLocation) {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中// 这是dom4j 解析xml 文件的核心对象SAXReader saxReader = new SAXReader();Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);// 获取一个输入流,指向配置文件InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);try {// 读文件Document document = saxReader.read(in);// 获取到所有的 <bean>标签// 注意要两个//,才能表示一个 /List<Node> nodes = document.selectNodes("//bean");// 遍历 bean标签nodes.forEach(node -> {//System.out.println(node);// 向下转型的目的是为了使用Element接口更加丰富的方法Element beanElt = (Element) node;// 获取 <bean>标签当中的id的属性String id = beanElt.attributeValue("id");// 获取 <bean>标签当中的 class 属性String className = beanElt.attributeValue("class");//logger.info("beanName" + id);//logger.info("beanClassName " + className);try {// 通过反射机制创建对象,将其放到Map集合中,提前曝光// 获取class对象Class<?> aClass = Class.forName(className);// 获取无参构造方法实例化BeanConstructor<?> declaredCon = aClass.getDeclaredConstructor();// 调用无参构造方法实例化BeanObject bean = declaredCon.newInstance();// 将Bean 曝光,加入 Map集合singletonObjects.put(id, bean);// 记录日志//logger.info(singletonObjects.toString());//System.out.println(singletonObjects.toString());} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}});// 再次重新把所有的 Bean 标签遍历一次,这一次主要是给对象属性赋值的nodes.forEach(node -> {Element beanElt = (Element) node;// 获取 <bean>标签当中的 id 属性String id = beanElt.attributeValue("id");// 获取<bean>标签当中的 class 属性的值String className = beanElt.attributeValue("class");// 获取Class 对象通过全限定类名+反射机制try {Class<?> aClass = Class.forName(className);// 获取该<bean>标签下的所有的属性为 <property>标签List<Element> propertys = beanElt.elements("property");// 遍历<property> 的所有的属性标签propertys.forEach(property -> {// 获取 <property> 标签下的name 属性名下的值String propertyName = property.attributeValue("name");//logger.info(" <property> 标签下的name 属性名 " + propertyName);// 获取 <property> 标签下的name 属性名下的值// 获取 set 方法名 set+属性名第一个单词大写String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);try {//获取 set 方法// 获取属性类型,通过属性名,可以获取到属性类型Field declaredField = aClass.getDeclaredField(propertyName);// 获取set方法Method setMethod = aClass.getDeclaredMethod(setMethodName, declaredField.getType());// 调用set方法(set方法没有返回值)// 获取 <property> 标签当中的 value 或者是 ref 的具体的值String value = property.attributeValue("value");String ref = property.attributeValue("ref");Object actualValue = null; // 真值if (value != null) {// 说明在<property> 标签当中  这个值是简单类型/*我们myspring框架说明以下,我们只支持这些类型为简单类型byte short int long float double boolean charByte Short Intger Long Float Double Boolean CharacterString*/// 获取属性类型名String propertyTypeSimpleName = declaredField.getType().getSimpleName();switch (propertyTypeSimpleName) {case "byte":actualValue = Byte.parseByte(value);break;case "short":actualValue = Short.parseShort(value);break;case "int":actualValue = Integer.parseInt(value);break;case "long":actualValue = Long.parseLong(value);break;case "float":actualValue = Float.parseFloat(value);break;case "double":actualValue = Double.parseDouble(value);break;case "boolean":actualValue = Boolean.parseBoolean(value);break;case "char":actualValue = value.charAt(0);break;case "Byte":actualValue = Byte.valueOf(value);break;case "Short":actualValue = Short.valueOf(value);break;case "Integer":actualValue = Integer.valueOf(value);break;case "Long":actualValue = Long.valueOf(value);break;case "Float":actualValue = Float.valueOf(value);break;case "Double":actualValue = Double.valueOf(value);break;case "Boolean":actualValue = Boolean.valueOf(value);break;case "Character":// char 仅仅只是一个字符,所以要获取第一个字符actualValue = value.charAt(0);break;case "String":actualValue = value;break;}setMethod.invoke(singletonObjects.get(id), actualValue);}if (ref != null) {// 说明这个值是非简单类型// 因为是非简单类型,那么它提前曝光的,就存放到了集合当前去了。setMethod.invoke(singletonObjects.get(id), singletonObjects.get(ref));}} catch (Exception e) {throw new RuntimeException(e);}});} catch (ClassNotFoundException e) {throw new RuntimeException(e);}});} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

3.10 第十步:测试是否能够正常赋值成功

注意: 不要导错包了,我们这里导入的是,我们自己手写的Spring框架的包。

在这里插入图片描述
在这里插入图片描述


3.11 第十一步:打包发布

将多余的类以及配置文件删除,当然,我们这里并不是真正的开发 Spring 框架,所以不删除也是没有关系的(只是需要注意不要导错jar 包了)。这里我们使用maven打包发布。关于 Maven 的使用上的内容,想要了解更多的。大家可以移步:✏️✏️✏️ Maven_ChinaRainbowSea的博客-CSDN博客。各种细节内容都是截屏标志了的,这个大家放心。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.12 第十二步: 站在程序员角度使用我们自己手写的 spring 的 myspring框架

第一步: 我们新建一个名为: myspring-text 的模块,进行一个我们手写的Spring 的框架的测试。

在这里插入图片描述
第二步: 引入我们自己编写的Spring 框架,不要引错了。

在这里插入图片描述
在这里插入图片描述

第三步: 编写准备一些Bean 对象用于测试,我们自己编写的 Spring 框架

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.myspring.bean;public class Vip {private String name;private int age;private double height;public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setHeight(double height) {this.height = height;}@Overridepublic String toString() {return "Vip{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}
}
package com.rainbowsea.myspring.bean;public class OrderDao {public void insert() {System.out.println("插入数据");}
}
package com.rainbowsea.myspring.bean;public class OrderService {private OrderDao orderDao;public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}public void generate() {orderDao.insert();}
}

第四步: 运行,测试,我们编写的Spring 的框架是否成功。

注意:导入的是我们自己编写的Spring 框架。不要导错了。

在这里插入图片描述
从我们的运行结果上看,我们编写的Spring 框架是没有问题的。

4. 总结:

  1. 框架一般是由 设计模式+注解+反射 来实现,并进行运用开发的。而这里我们的Spring IoC容器的实现原理:工厂模式 + 解析XML + 反射机制

  2. 我们知道,想要调用一个方法,就需要明确知道该方法的四个要素:

    1. 调用的是哪个对象的
    2. 哪个方法
    3. 该方法传什么参数
    4. 有无返回值,有返回值的话,又该返回什么值
  3. 引入 dom4jjaxen的依赖,因为要使用它解析XML文件, SAXReader(这是dom4j 解析xml 文件的核心对象) 的对象以及Document ,用来读取我们当中的myspring.xml'所含的 bean 的配置信息。这两个对象可以读取到 xml 配置文件的信息。

    在这里插入图片描述

  4. 编写Spring 框架比较难的点,就是:简单类型的复杂点,就是一个转换,我们再 myspring.xml 配置文件当中的,属性值都是以字符串的形式存在的,而我们的实际属性的类型,可能是 int,char,double 等等类型的,String 字符串类型不可以直接赋值到其他 int,char 类型当中去,所以我们就需要对我们所赋值的属性进行一个判断,如果该类型是 int 类型,我们就需要将 String 字符串类型转换为我们所需要的 int 类型。

  5. 注意:我们手写的Spring 框架不并不是完完全全按照,真正的Spring框架来编写的,这是大部分思路是一致的,对应不同需要上的处理可能不太一致,这一点希望大家可以明白。

  6. 我们手写Spring 框架是为了,更好的理解Spring 框架的原理,从而不惧怕Spring的使用,在使用上更加的灵活,得心易手。

5. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/27920.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

腾讯公益赛团队博客10(2024.5.6)

未完成 在线医生、聊天室功能进行中 在多人手机端测试程序的可行性已完成 sos、帮扶基本功能、登录注册、主页

腾讯公益赛团队冲刺博客9(2024.5.3)

未完成 在线医生、聊天室、多人弹窗进行中 在线数据库的连接,保证不同的网络都可以连接到一个数据库已完成 sos、帮扶的基本功能,登录注册和主页

第三十八天:Ansible playbook--Role角色

角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即 可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目…

腾讯公益赛冲刺团队博客1(2024.4.23)

未完成 项目还没开始进行中 登录注册已完成 无

腾讯公益赛冲刺团队博客4(2024.4.26)

未完成 sos功能后端,在线医生、社交功能进行中 帮扶功能的后端已完成 sos、帮扶前端、登录注册、主页

腾讯公益赛冲刺团队博客3(2024.4.25)

未完成 sos和帮扶功能的后端界面,以及其他两个功能进行中 sos和帮扶功能的前端已完成 登录注册和主页

c#的try-catch-finally

在编码过程中经常出现这样的代码int Tec(){int i = 0;try{int c = i / 0;return c;}catch{return 0;}} 然后我们来看反编译后的代码 编译器会把结果保存到一个result的中间变量中,然后最后统一返回

Verilog插件:补全模块实例模板

Intellij IDEA插件Verilog Language Support,v2024.2.0版本特性。