1、Spring的Beans.xml
一个beans.xml示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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">
<!--配置一个Monster对象-->
<!--
1. 配置monster对象/javaBean
2. 在beans中可以配置多个bean
3. bean表示就是一个java对象
4. class属性是用来指定类的全路径(因为底层是使用反射创建对象)
5. id属性表示该java对象在Spring容器中的ID,通过ID可以获取到该对象
6. <property name="monsterId" value="100"/> 用于给该对象的属性赋值
-->
<bean class="com.hspedu.spring.bean.Monster" id="monster01">
<property name="monsterId" value="100"/>
<property name="name" value="牛魔王"/>
<property name="skill" value="芭蕉扇"/>
</bean>
</beans>
获取Bean对象的过程:
@Test
public void getMonster() {
// 1. 创建容器 ApplicationContext 该容器和容器配置文件关联
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
// 2. 通过getBean获取对应的对象
// 默认返回Object 运行类型肯定是Monster
Object monster01 = ioc.getBean("monster01");
// 3. 输出
System.out.println(monster01); // Monster{monsterId=100, name='牛魔王', skill='芭蕉扇'}
System.out.println(monster01.getClass()); // 运行类型 class com.hspedu.spring.bean.Monster
// 4. 也可以在获取的时候直接指定Class类型
Monster monster = ioc.getBean("monster01", Monster.class);
System.out.println(monster); // Monster{monsterId=100, name='牛魔王', skill='芭蕉扇'}
}
getBean的运行流程:
获取容器中的所有BeanID:
1.1、自定义一个容器HspApplicationContext
自己写一个简单的Spring容器,通过读取beans.xml, 获取第一个JavaBean:Monster对象,并给该对象赋值,放入到容器中,输出该对象的信息
流程:
- 先解析beans.xml
- 得到第一个bean的信息,beanID、Class、属性、属性值
- 使用反射生成对象,并赋值
- 将创建好的bean对象,放入到singletonObjects集合中
- 提供getBean(id)可以返回对应的bean对象
bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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">
<!--配置一个Monster对象-->
<!--
1. 配置monster对象/javaBean
2. 在beans中可以配置多个bean
3. bean表示就是一个java对象
4. class属性是用来指定类的全路径(因为底层是使用反射创建对象)
5. id属性表示该java对象在Spring容器中的ID,通过ID可以获取到该对象
6. <property name="monsterId" value="100"/> 用于给该对象的属性赋值
-->
<bean class="com.hspedu.spring.bean.Monster" id="monster01">
<property name="monsterId" value="100"/>
<property name="name" value="牛魔王"/>
<property name="skill" value="芭蕉扇"/>
</bean>
<bean class="com.hspedu.spring.bean.Monster" id="monster02">
<property name="monsterId" value="1001"/>
<property name="name" value="牛魔王1"/>
<property name="skill" value="芭蕉扇1"/>
</bean>
</beans>
Java代码:
package com.hspedu.spring.hspapplicationcontext;
import com.hspedu.spring.bean.Monster;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: lihaojie
* @Description:
* 1、这个程序用于实现Spring的一个简单容器机制
* 2、后面还会详细的实现
* 3、这里我们实现如何将beans.xml文件进行解析并生成对应对象放入到容器在中
* 4、提供一个方法 getBean(String id) 返回对应的对象
* @DateTime: 2024/1/29 15:14
**/
public class HspApplicationContext {
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 构造器接收一个容器的配置文件 比如beans.xml 该文件默认在src下
public HspApplicationContext(String iocBeanXmlPath) throws Exception {
// 1、得到类加载路径
String path = this.getClass().getResource("/").getPath();
// 2、使用dom4j读取 创建saxReader
SAXReader saxReader = new SAXReader();
// 3、得到文档对象Document
Document document = saxReader.read(new File(path + iocBeanXmlPath));
// 4、得到rootDocument
Element rootElement = document.getRootElement();
// 5、得到第一个bean
Element bean = (Element) rootElement.elements("bean").get(0);
// 6、把id class 属性 都拿出来
String id = bean.attributeValue("id");
String classFullPath = bean.attributeValue("class");
List<Element> property = bean.elements("property");
// 直接获取
Map<String, String> kvs = new HashMap<>();
for (Element element : property) {
String name = element.attributeValue("name");
String value = element.attributeValue("value");
kvs.put(name, value);
}
// 7、使用反射创建对象
Class<?> aClass = Class.forName(classFullPath);
// 这里的o对象就是Monster对象
Monster monster = (Monster)aClass.newInstance();
// 用反射来赋值
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (kvs.containsKey(declaredField.getName())) {
declaredField.setAccessible(true);
declaredField.set(monster, kvs.get(declaredField.getName()));
}
}
// 8、放进容器
singletonObjects.put(id, monster);
}
public Object getBean(String id) {
return singletonObjects.get(id);
}
}
1.2、Spring原生容器结构整理
思考:如果beans.xml中不去配id,会不会报错呢?
答案是不会,会正常运行,系统会默认分配ID,分配ID的规则:
全类名#0,全类名#1 这样的规则来分配ID
可以通过Debug的方式查看:
1.3、Spring配置Bean的基本介绍
Bean的管理分为两方面:
- 创建bean对象
- 给bean注入属性
1.4、从容器中获取bean的方式
1.4.1、按照类型去获取
案例:通过Spring的ioc容器,获取一个bean对象,获取bean的方式要求按照类型获取
但是,如果同类型的bean定义了两个,就会报错,看下面的例子:
这种使用Type赋值的场景有:
- XXXAction/Servlet/Controller/XXXService 在一个线程中只需要一个对象实例的情况
- 在容器配置文件中(比如beans.xml)中给属性赋值,底层是通过setter方法完成的,这也是为什么我们需要提供setter方法原因,没有setter运行会报错的