前置
首先先引入依赖:
<dependencies>
// 辅助加载读取文件
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
// 快速添加构造方法,get set等,简化代码
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
</dependencies>
一、建立一个最基本的基于xml配置文件的IOC容器
功能说明:
首先需要读取xml配置文件,然后注入bean
思路:
- 读取xml文件配置
- 创建BeanDefinition(bean的定义,由于不知道bean的具体类型,引入BeanDefinition记录bean的信息)
- 根据BeanDefinition中的信息,结合反射,创建bean
代码实现:
- 构建xml文件信息(放在项目的resources文件下)
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id = "xxxid" class = "com.minis.xxxclass"></bean>
</beans>
- BeanDefinition的定义以及初始容器的构造
public class BeanDefinition {
private String id;
private String className;
public BeanDefinition(String id, String className) {
this.id = id;
this.className = className;
}
//省略getter和setter
public class ClassPathXmlApplicationContext {
// 保存BeanDefinition
private List<BeanDefinition> beanDefinitions = new ArrayList<>();
// ioc容器,存储bean
private Map<String, Object> singletons = new HashMap<>();
//构造器获取外部配置,解析出Bean的定义,形成内存映像
public ClassPathXmlApplicationContext(String fileName) {
this.readXml(fileName);
this.instanceBeans();
}
private void readXml(String fileName) {
SAXReader saxReader = new SAXReader();
try {
URL xmlPath =
this.getClass().getClassLoader().getResource(fileName);
Document document = saxReader.read(xmlPath);
Element rootElement = document.getRootElement();
//对配置文件中的每一个<bean>,进行处理
for (Element element : (List<Element>) rootElement.elements()) {
//获取Bean的基本信息
String beanID = element.attributeValue("id");
String beanClassName = element.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition(beanID,
beanClassName);
//将Bean的定义存放到beanDefinitions
beanDefinitions.add(beanDefinition);
}
}
}
//利用反射创建Bean实例,并存储在singletons中
private void instanceBeans() {
for (BeanDefinition beanDefinition : beanDefinitions) {
try {
singletons.put(beanDefinition.getId(),
Class.forName(beanDefinition.getClassName()).newInstance());
}
}
}
//这是对外的一个方法,让外部程序从容器中获取Bean实例,会逐步演化成核心方法
public Object getBean(String beanName) {
return singletons.get(beanName);
}
}
测试
测试bean是否能注入成功
- 定义结构
public interface AService {
void sayHello();
}
public class AServiceImpl implements AService {
public void sayHello() {
System.out.println("a service 1 say hello");
}
}
xml:
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id = "aservice" class = "com.minis.test.AServiceImpl"></bean>
</beans>
public class Test1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
AService aService = (AService)ctx.getBean("aservice");
aService.sayHello();
}
}
可以看到,即便在主方法中,没有创建AServiceImpl类,依然能够执行其方法,因为在读取配置的时候已经容器中创建了对应实例。
解耦
先定义一些工厂接口和资源接口(由于上述代码只针对xml,所以添加接口方便扩展)
public interface BeanFactory {
Object getBean(String beanName) throws BeansException;
void registerBeanDefinition(BeanDefinition beanDefinition);
}
public interface Resource extends Iterator<Object> {
}
加载xml文件
public class ClassPathXmlResource implements Resource{
Document document;
Element rootElement;
Iterator<Element> elementIterator;
public ClassPathXmlResource(String fileName) {
SAXReader saxReader = new SAXReader();
URL xmlPath = this.getClass().getClassLoader().getResource(fileName);
//将配置文件装载进来,生成一个迭代器,可以用于遍历
try {
this.document = saxReader.read(xmlPath);
this.rootElement = document.getRootElement();
this.elementIterator = this.rootElement.elementIterator();
}
}
public boolean hasNext() {
return this.elementIterator.hasNext();
}
public Object next() {
return this.elementIterator.next();
}
}
解析xml文件
public class XmlBeanDefinitionReader {
BeanFactory beanFactory;
public XmlBeanDefinitionReader(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void loadBeanDefinitions(Resource resource) {
while (resource.hasNext()) {
Element element = (Element) resource.next();
String beanID = element.attributeValue("id");
String beanClassName = element.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition(beanID, beanClassName);
this.beanFactory.registerBeanDefinition(beanDefinition);
}
}
}
最后我们开头制作的ioc容易就可以存在一个单例工厂(还有其他类型的工厂,所以定义了工厂接口)中
public class SimpleBeanFactory implements BeanFactory{
private List<BeanDefinition> beanDefinitions = new ArrayList<>();
private List<String> beanNames = new ArrayList<>();
private Map<String, Object> singletons = new HashMap<>();
public SimpleBeanFactory() {
}
//getBean,容器的核心方法
public Object getBean(String beanName) throws BeansException {
//先尝试直接拿Bean实例
Object singleton = singletons.get(beanName);
//如果此时还没有这个Bean的实例,则获取它的定义来创建实例
if (singleton == null) {
int i = beanNames.indexOf(beanName);
if (i == -1) {
throw new BeansException();
}
else {
//获取Bean的定义
BeanDefinition beanDefinition = beanDefinitions.get(i);
try {
singleton = Class.forName(beanDefinition.getClassName()).newInstance();
}
//注册Bean实例
singletons.put(beanDefinition.getId(), singleton);
}
}
return singleton;
}
public void registerBeanDefinition(BeanDefinition beanDefinition) {
this.beanDefinitions.add(beanDefinition);
this.beanNames.add(beanDefinition.getId());
}
}
二、容器增强
现在我们将上述过程进行拆分:
- 增加单例Bean的接口定义,把所有bean默认为单例模式
- 预留事件监听接口,方便后续进一步解读代码逻辑
- 扩展BeanDefinition,增加一些属性,现在的BeanDefinition只有id和className
接下来定义一些接口和实现,具体的存放位置可以自己看情况放置
构建单例bean
public interface BeanFactory {
Object getBean(String beanName) throws BeansException;
Boolean containsBean(String name);
void registerBean(String beanName, Object obj);
}
public interface SingletonBeanRegistry {
void registerSingleton(String beanName, Object singletonObject);
Object getSingleton(String beanName);
boolean containsSingleton(String beanName);
String[] getSingletonNames();
}
接口已经定义好了,接下来我们定义一个默认的实现类。
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
//容器中存放所有bean的名称的列表
protected List<String> beanNames = new ArrayList<>();
//容器中存放所有bean实例的map
protected Map<String, Object> singletons = new ConcurrentHashMap<>(256);
public void registerSingleton(String beanName, Object singletonObject) {
synchronized (this.singletons) {
this.singletons.put(beanName, singletonObject);
this.beanNames.add(beanName);
}
}
public Object getSingleton(String beanName) {
return this.singletons.get(beanName);
}
public boolean containsSingleton(String beanName) {
return this.singletons.containsKey(beanName);
}
public String[] getSingletonNames() {
return (String[]) this.beanNames.toArray();
}
protected void removeSingleton(String beanName) {
synchronized (this.singletons) {
this.beanNames.remove(beanName);
this.singletons.remove(beanName);
}
}
}
最后就是单例bean工厂的实现
public class SimpleBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory{
private Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);
public SimpleBeanFactory() {
}
//getBean,容器的核心方法
public Object getBean(String beanName) throws BeansException {
//先尝试直接拿bean实例
Object singleton = this.getSingleton(beanName);
//如果此时还没有这个bean的实例,则获取它的定义来创建实例
if (singleton == null) {
//获取bean的定义
BeanDefinition beanDefinition = beanDefinitions.get(beanName);
if (beanDefinition == null) {
throw new BeansException("No bean.");
}
try {
singleton = Class.forName(beanDefinition.getClassName()).newInstance();
}
//新注册这个bean实例
this.registerSingleton(beanName, singleton);
}
return singleton;
}
public void registerBeanDefinition(BeanDefinition beanDefinition) {
this.beanDefinitions.put(beanDefinition.getId(), beanDefinition);
}
public Boolean containsBean(String name) {
return containsSingleton(name);
}
public void registerBean(String beanName, Object obj) {
this.registerSingleton(beanName, obj);
}
}
注入的属性设置
下面是构造器注入和setter注入的模型,后面在bean注入的时候会用到
public class ArgumentValue {
private Object value;
private String type;
private String name;
public ArgumentValue(Object value, String type) {
this.value = value;
this.type = type;
}
public ArgumentValue(Object value, String type, String name) {
this.value = value;
this.type = type;
this.name = name;
}
//省略getter和setter
}
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
//省略getter
}
- ArgumentValues类
public class ArgumentValues {
private final Map<Integer, ArgumentValue> indexedArgumentValues = new HashMap<>(0);
private final List<ArgumentValue> genericArgumentValues = new LinkedList<>();
public ArgumentValues() {
}
private void addArgumentValue(Integer key, ArgumentValue newValue) {
this.indexedArgumentValues.put(key, newValue);
}
public boolean hasIndexedArgumentValue(int index) {
return this.indexedArgumentValues.containsKey(index);
}
public ArgumentValue getIndexedArgumentValue(int index) {
return this.indexedArgumentValues.get(index);
}
public void addGenericArgumentValue(Object value, String type) {
this.genericArgumentValues.add(new ArgumentValue(value, type));
}
private void addGenericArgumentValue(ArgumentValue newValue) {
if (newValue.getName() != null) {
for (Iterator<ArgumentValue> it =
this.genericArgumentValues.iterator(); it.hasNext(); ) {
ArgumentValue currentValue = it.next();
if (newValue.getName().equals(currentValue.getName())) {
it.remove();
}
}
}
this.genericArgumentValues.add(newValue);
}
public ArgumentValue getGenericArgumentValue(String requiredName) {
for (ArgumentValue valueHolder : this.genericArgumentValues) {
if (valueHolder.getName() != null && (requiredName == null || !valueHolder.getName().equals(requiredName))) {
continue;
}
return valueHolder;
}
return null;
}
public int getArgumentCount() {
return this.genericArgumentValues.size();
}
public boolean isEmpty() {
return this.genericArgumentValues.isEmpty();
}
}
- PropertyValues类
public class PropertyValues {
private final List<PropertyValue> propertyValueList;
public PropertyValues() {
this.propertyValueList = new ArrayList<>(0);
}
public List<PropertyValue> getPropertyValueList() {
return this.propertyValueList;
}
public int size() {
return this.propertyValueList.size();
}
public void addPropertyValue(PropertyValue pv) {
this.propertyValueList.add(pv);
}
public void addPropertyValue(String propertyName, Object propertyValue) {
addPropertyValue(new PropertyValue(propertyName, propertyValue));
}
public void removePropertyValue(PropertyValue pv) {
this.propertyValueList.remove(pv);
}
public void removePropertyValue(String propertyName) {
this.propertyValueList.remove(getPropertyValue(propertyName));
}
public PropertyValue[] getPropertyValues() {
return this.propertyValueList.toArray(new PropertyValue[this.propertyValueList.size()]);
}
public PropertyValue getPropertyValue(String propertyName) {
for (PropertyValue pv : this.propertyValueList) {
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}
public Object get(String propertyName) {
PropertyValue pv = getPropertyValue(propertyName);
return pv != null ? pv.getValue() : null;
}
public boolean contains(String propertyName) {
return getPropertyValue(propertyName) != null;
}
public boolean isEmpty() {
return this.propertyValueList.isEmpty();
}
}
扩展BeanDefinition
@Data
public class BeanDefinition {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
private boolean lazyInit = false;
private String[] dependsOn;
private ArgumentValues constructorArgumentValues;
private PropertyValues propertyValues;
private String initMethodName;
private volatile Object beanClass;
private String id;
private String className;
private String scope = SCOPE_SINGLETON;
public BeanDefinition(String id, String className) {
this.id = id;
this.className = className;
}
}
集中存放BeanDefinition
接下来,我们新增BeanDefinitionRegistry接口。它类似于一个存放BeanDefinition的仓库,可以存放、移除、获取及判断BeanDefinition对象。所以,我们初步定义四个接口对应这四个功能,分别是register、remove、get、contains。
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String name, BeanDefinition bd);
void removeBeanDefinition(String name);
BeanDefinition getBeanDefinition(String name);
boolean containsBeanDefinition(String name);
}
随后调整BeanFactory,新增Singleton、Prototype的判断,获取Bean的类型。
public interface BeanFactory {
Object getBean(String name) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name);
boolean isPrototype(String name);
Class<?> getType(String name);
}
通过代码可以看到,我们让SimpleBeanFactory实现了BeanDefinitionRegistry,这样SimpleBeanFactory既是一个工厂同时也是一个仓库,你可以看下调整后的部分代码。
public class SimpleBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory, BeanDefinitionRegistry{
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
private List<String> beanDefinitionNames = new ArrayList<>();
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
this.beanDefinitionMap.put(name, beanDefinition);
this.beanDefinitionNames.add(name);
if (!beanDefinition.isLazyInit()) {
try {
getBean(name);
} catch (BeansException e) {
}
}
}
public void removeBeanDefinition(String name) {
this.beanDefinitionMap.remove(name);
this.beanDefinitionNames.remove(name);
this.removeSingleton(name);
}
public BeanDefinition getBeanDefinition(String name) {
return this.beanDefinitionMap.get(name);
}
public boolean containsBeanDefinition(String name) {
return this.beanDefinitionMap.containsKey(name);
}
public boolean isSingleton(String name) {
return this.beanDefinitionMap.get(name).isSingleton();
}
public boolean isPrototype(String name) {
return this.beanDefinitionMap.get(name).isPrototype();
}
public Class<?> getType(String name) {
return this.beanDefinitionMap.get(name).getClass();
}
}
修改完BeanFactory这个核心之后,上层对应的 ClassPathXmlApplicationContext部分作为外部集成包装也需要修改。
public class ClassPathXmlApplicationContext implements BeanFactory,
ApplicationEventPublisher{
public void publishEvent(ApplicationEvent event) {
}
public boolean isSingleton(String name) {
return false;
}
public boolean isPrototype(String name) {
return false;
}
public Class<?> getType(String name) {
return null;
}
}
三、依赖注入
构造注入和setter注入
前面提到,注入依赖包括构造器注入,setter注入等,构造器注入主要是通过解析xml文件中的<constructor-arg>标签,setter注入则是<property>
首先先配置xml:
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="aservice" class="com.minis.test.AServiceImpl">
<constructor-arg type="String" name="name" value="abc"/>
<constructor-arg type="int" name="level" value="3"/>
<property type="String" name="property1" value="Someone says"/>
<property type="String" name="property2" value="Hello World!"/>
</bean>
</beans>
填充属性
然后修改测试用例:
public class AServiceImpl implements AService {
private String name;
private int level;
private String property1;
private String property2;
public AServiceImpl() {
}
public AServiceImpl(String name, int level) {
this.name = name;
this.level = level;
System.out.println(this.name + "," + this.level);
}
public void sayHello() {
System.out.println(this.property1 + "," + this.property2);
}
// 在此省略property1和property2的setter、getter方法
}
接着,简化ArgumentValues类,移除暂时未用到的方法。
public class ArgumentValues {
private final List<ArgumentValue> argumentValueList = new ArrayList<>();
public ArgumentValues() {
}
public void addArgumentValue(ArgumentValue argumentValue) {
this.argumentValueList.add(argumentValue);
}
public ArgumentValue getIndexedArgumentValue(int index) {
ArgumentValue argumentValue = this.argumentValueList.get(index);
return argumentValue;
}
public int getArgumentCount() {
return (this.argumentValueList.size());
}
public boolean isEmpty() {
return (this.argumentValueList.isEmpty());
}
}
做完准备工作之后,我们重点来看核心工作:解析 <property>
和 <constructor-arg>
两个标签。我们要在XmlBeanDefinitionReader类中处理这两个标签。
public void loadBeanDefinitions(Resource resource) {
while (resource.hasNext()) {
Element element = (Element) resource.next();
String beanID = element.attributeValue("id");
String beanClassName = element.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition(beanID,
beanClassName);
//处理属性
List<Element> propertyElements = element.elements("property");
PropertyValues PVS = new PropertyValues();
for (Element e : propertyElements) {
String pType = e.attributeValue("type");
String pName = e.attributeValue("name");
String pValue = e.attributeValue("value");
PVS.addPropertyValue(new PropertyValue(pType, pName, pValue));
}
beanDefinition.setPropertyValues(PVS);
//处理构造器参数
List<Element> constructorElements = element.elements("constructor-
arg");
ArgumentValues AVS = new ArgumentValues();
for (Element e : constructorElements) {
String aType = e.attributeValue("type");
String aName = e.attributeValue("name");
String aValue = e.attributeValue("value");
AVS.addArgumentValue(new ArgumentValue(aType, aName, aValue));
}
beanDefinition.setConstructorArgumentValues(AVS);
this.simpleBeanFactory.registerBeanDefinition(beanID,
beanDefinition);
}
}
}
在SimpleBeanFactory类中,就可以编写核心的createBean方法(用于构造器注入和setter注入)
注:这里使用的是通用解析class,所以在beandefinition中,需要保证beandefinition的type是标准类的形式,如java.lang.String
/**
* @param beanDefinition
* @return Object
* @doc: 根据beanDefinition创建bean
* @author 17605
* @date 2025/06/08
*/
private Object createBean(BeanDefinition beanDefinition) throws ClassNotFoundException {
Class<?> clz = null;
Object obj = null;
Constructor<?> con = null;
try {
clz = Class.forName(beanDefinition.getClassName());
// 处理构造器参数
ArgumentValues argumentValues = beanDefinition.getConstructorArgumentValues();
//如果有参数
if (!argumentValues.isEmpty()) {
Class<?>[] paramTypes = new Class<?>[argumentValues.getArgumentCount()];
Object[] paramValues = new Object[argumentValues.getArgumentCount()];
//对每一个参数,分数据类型分别处理
for (int i = 0; i < argumentValues.getArgumentCount(); i++) {
ArgumentValue argumentValue = argumentValues.getIndexedArgumentValue(i);
// 解析类型并获取类
String type = argumentValue.getType();
Class<?> aClass = Class.forName(type);
paramTypes[i] = aClass;
// 将值转为对应的类值
paramValues[i] = aClass.cast(argumentValue.getValue());
}
//按照特定构造器创建实例
con = clz.getConstructor(paramTypes);
obj = con.newInstance(paramValues);
} else {
//如果没有参数,直接创建实例
obj = clz.newInstance();
}
} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
// 处理属性
PropertyValues propertyValues = beanDefinition.getPropertyValues();
if (!propertyValues.isEmpty()) {
for (int i = 0; i < propertyValues.size(); i++) {
//对每一个属性,分数据类型分别处理
PropertyValue propertyValue = propertyValues.getPropertyValueList().get(i);
String pType = propertyValue.getType();
String pName = propertyValue.getName();
Object pValue = propertyValue.getValue();
// 解析类型并获取类
Class<?> paramTypes = Class.forName(pType);
//按照setXxx规范查找setter方法,调用setter方法设置属性
String methodName = "set" + pName.substring(0, 1).toUpperCase() + pName.substring(1);
Method method = null;
try {
method = clz.getMethod(methodName, paramTypes);
method.invoke(obj, pValue);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
return obj;
}
循环依赖
bean的生命周期大致是:实例化 —> 填充属性 —> 初始化
Spring在解决循环依赖的时候是通过设立缓存,Spring使用了三级缓存,理论上二级缓存也可以解决循环依赖,由于此时我们还没有使用到代理类,所以这里我们就使用二级缓存。
将创建好的实例放在earlySingletonObjects(缓存)中,在填充属性的时候,查询是否在缓存中存在,如果存在,就注入(注:此时注入的属性是没有注入过属性的bean)
按照bean的生命周期,我们就可以设置重构SimpleBeanFactory:
private Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);
private List<String> beanDefinitionNames = new ArrayList<>();
private Map<String, Object> earlySingletonObjects = new HashMap<>();
public Object getBean(String beanName) throws BeansException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
// 看容器中是否有Bean实例
Object singleton = singletons.get(beanName);
// 如果还没有这个bean的实例,则获取它的定义来创建实例
if (singleton == null) {
//如果没有bean,则创建bean并注册
BeanDefinition beanDefinition = beanDefinitions.get(beanName);
singleton = createBean(beanDefinition);
this.registerSingleton(beanName, singleton);
// 预留beanpostprocessor位置
// step 1: postProcessBeforeInitialization
// step 2: afterPropertiesSet
// step 3: init-method
// step 4: postProcessAfterInitialization
}
return singleton;
}
private Object createBean(BeanDefinition beanDefinition) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
Class<?> clz = null;
// 如果存在缓存中,代表形成了循环依赖,返回null;
if (earlySingletonObjects.get(beanDefinition.getId()) != null) {
return null;
}
//1. 创建实例
Object obj = doCreateBean(beanDefinition);
//2. 存入缓存
this.earlySingletonObjects.put(beanDefinition.getId(), obj);
clz = Class.forName(beanDefinition.getClassName());
//3. 填充属性
handleProperties(beanDefinition, clz, obj);
//4. 装入容器
singletons.put(beanDefinition.getId(), obj);
//5. 清除缓存
earlySingletonObjects.remove(beanDefinition.getId());
return obj;
}
/**
* @param beanDefinition
* @param clz
* @param obj
* @doc: 填充属性
* @author 17605
* @date 2025/06/09
*/
private void handleProperties(BeanDefinition beanDefinition, Class<?> clz, Object obj) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
// 处理属性
PropertyValues propertyValues = beanDefinition.getPropertyValues();
if (propertyValues != null && !propertyValues.isEmpty()) {
for (int i = 0; i < propertyValues.size(); i++) {
//对每一个属性,分数据类型分别处理
PropertyValue propertyValue = propertyValues.getPropertyValueList().get(i);
String pType = propertyValue.getType();
String pName = propertyValue.getName();
Object pValue = propertyValue.getValue();
String ref = propertyValue.getRef();
// 解析类型并获取类
// 看缓存中是否存在实例
Object o = earlySingletonObjects.get(ref);
Method method = null;
Class<?> paramTypes = ClassLoadUtil.loadClassByClassName(pType);
// 存在实例,则将实例注入 或者是基本数据类型
//TODO 2025/6/9
// 基本数据类型
if (ClassLoadUtil.isLangType(paramTypes)) {
}
// 存在实例
else if (o != null) {
pValue = o;
} else {
// 实例不存在缓存则创建实例
pValue = createBean(beanDefinitions.get(ref));
}
//按照setXxx规范查找setter方法,调用setter方法设置属性
String methodName = "set" + pName.substring(0, 1).toUpperCase() + pName.substring(1);
// 存在实例
try {
method = clz.getMethod(methodName, paramTypes);
method.invoke(obj, pValue);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* @param beanDefinition
* @return Object
* @doc: 创建实例 (调用构造参数)
* @author 17605
* @date 2025/06/09
*/
private Object doCreateBean(BeanDefinition beanDefinition) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> clz = null;
Object obj = null;
Constructor<?> con = null;
clz = Class.forName(beanDefinition.getClassName());
// 处理构造器参数
ArgumentValues argumentValues = beanDefinition.getConstructorArgumentValues();
//如果有参数
if (argumentValues != null && !argumentValues.isEmpty()) {
Class<?>[] paramTypes = new Class<?>[argumentValues.getArgumentCount()];
Object[] paramValues = new Object[argumentValues.getArgumentCount()];
//对每一个参数,分数据类型分别处理
for (int i = 0; i < argumentValues.getArgumentCount(); i++) {
ArgumentValue argumentValue = argumentValues.getIndexedArgumentValue(i);
// 解析类型并获取类
String type = argumentValue.getType();
Object value = argumentValue.getValue();
Class<?> aClass = ClassLoadUtil.loadClassByClassName(type);
paramTypes[i] = aClass;
// 将值转为对应的类值
paramValues[i] = ClassLoadUtil.resolveValue(aClass, value);
}
//按照特定构造器创建实例
con = clz.getConstructor(paramTypes);
obj = con.newInstance(paramValues);
}
// 只有无参构造器
else {
con = clz.getConstructor();
obj = con.newInstance();
}
return obj;
}
/**
* @doc: 构造所有bean
* @author 17605
* @date 2025/06/09
*/
public void refresh() throws ClassNotFoundException, InvocationTargetException, BeansException, NoSuchMethodException, InstantiationException, IllegalAccessException {
for (String beanName : beanDefinitionNames) {
getBean(beanName);
}
}
四、支持注解
前面我们使用的注入方式都是xml配置注入,我们知道Spring中可以使用@Autowire
注入,所以接下俩我们要使我们的容器支持该注解,然后我们就可以知道:
- 为什么构造器注入先于Autowire注入?
- 为什么Autowire注入是setter注入?(通过反射获取set方法设值)
- 为什么Autowire注入和构造器之间形成循环依赖是如何解决的?
先定义注解@Autowire
:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
接下来,我们Bean后处理器,处理在构造器注入完成后的处理,包括注解解析。核心就是:解析被@Autowire修饰的属性,然后在IOC容器中寻找是否有这个属性的bean,然后调用该类的set方法注入。
这也就是为什么@Autowire
需要需要注入的bean事先在IOC中已经创建好了
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private AutowireCapableBeanFactory beanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Object result = bean;
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
if(fields!=null){
//对每一个属性进行判断,如果带有@Autowired注解则进行处理
for(Field field : fields){
boolean isAutowired =
field.isAnnotationPresent(Autowired.class);
if(isAutowired){
//根据属性名查找同名的bean
String fieldName = field.getName();
Object autowiredObj =
this.getBeanFactory().getBean(fieldName);
//设置属性值,完成注入
try {
field.setAccessible(true);
field.set(bean, autowiredObj);
System.out.println("autowire " + fieldName + " for bean
" + beanName);
}
}
}
}
return result;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return null;
}
public AutowireCapableBeanFactory getBeanFactory() {
return beanFactory;
}
public void setBeanFactory(AutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
接下来我们创建一个支持注解的工厂:AutowireCapableBeanFactory
/**
* @param bean
* @param beanName
* @return Object
* @doc: 初始化前方法(注入其他需要注入的属性)
* @author 17605
* @date 2025/06/10
*/
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
//对每一个属性进行判断,如果带有@Autowired注解则进行处理
for (Field field : fields) {
boolean isAutowired = field.isAnnotationPresent(Autowired.class);
if (isAutowired) {
//根据属性名查找同名的bean
String fieldName = field.getName();
// Object autowiredObj = this.getBean(fieldName);
// Class<?> aClass = field.getClass();
// // 按名称匹配失败,按类型再匹配一次
// if (autowiredObj == null){
// autowiredObj = this.getBean()
// }
Class<?> fieldType = field.getType();
try {
// 按类型匹配
Object autowiredObj = this.getBean(fieldType.getName());
// 允许私有属性注入
field.setAccessible(true);
//TODO 2025/6/11 这里要避免重复注入
if (field.get(bean) == null){
field.set(bean, autowiredObj);
System.out.println("autowire " + fieldName + " for bean " + beanName);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
return bean;
}
/**
* @param existingBean
* @param beanName
* @return Object
* @doc: 初始化后方法
* @author 17605
* @date 2025/06/10
*/
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
// Object result = existingBean;
// for (BeanPostProcessor beanProcessor : this.beanPostProcessors) {
// result = beanProcessor.postProcessAfterInitialization(result, beanName);
// if (result == null) {
// return result;
// }
// }
// return result;
return null;
}
protected final Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);
protected final List<String> beanDefinitionNames = new ArrayList<>();
protected final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
public AbstractBeanFactory() {
}
public void refresh() {
for (String beanName : beanDefinitionNames) {
try {
getBean(beanName);
} catch (BeansException | ClassNotFoundException | InvocationTargetException | NoSuchMethodException |
InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
@Override
public Object getBean(String beanName) throws BeansException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
//先尝试直接从容器中获取完整bean实例(按名称匹配)
Object singleton = this.getSingleton(beanName);
if (singleton != null) {
return singleton;
}
// 按名称匹配定义
BeanDefinition beanDefinition = beanDefinitions.get(beanName);
// 按类型匹配定义
if (beanDefinition == null) {
for (Map.Entry<String, BeanDefinition> entry : beanDefinitions.entrySet()) {
if (entry.getValue().getClassName().equals(beanName)) {
beanDefinition = entry.getValue();
break;
}
}
}
// 定义不存在(按名称匹配失败,或者按类型匹配失败)
if (beanDefinition == null) return null;
// 按类型匹配
singleton = singletons.get(beanDefinition.getClassName());
if (singleton != null) {
return singleton;
}
//如果没有完整bean实例,则尝试从毛胚实例中获取构造方法创建的bean(没有填充属性)
singleton = this.earlySingletonObjects.get(beanName);
if (singleton == null) {
//如果连毛胚都没有(没有构造方法创建的实例),则创建bean实例
singleton = doCreateBean(beanDefinition);
}
// 填充属性
this.handleProperties(beanDefinition, Class.forName(beanDefinition.getClassName()), singleton);
// 加入容器中
this.registerBean(beanDefinition.getClassName(), singleton);
// TODO 2025/6/11 测试@Autowired和xml形成的循环依赖是否可以跑通
// KEYPOINT 初始化
// 进行beanpostprocessor处理
// step 1: 初始化前的操作
applyBeanPostProcessorsBeforeInitialization(singleton, beanName);
// step 2: 初始化
if (beanDefinition.getInitMethodName() != null && !beanDefinition.equals("")) {
invokeInitMethod(beanDefinition, singleton);
}
// step 3: 初始化后的操作
applyBeanPostProcessorsAfterInitialization(singleton, beanName);
return singleton;
}
private void invokeInitMethod(BeanDefinition beanDefinition, Object obj) {
Class<?> clz = beanDefinition.getClass();
Method method = null;
try {
method = clz.getMethod(beanDefinition.getInitMethodName());
method.invoke(obj);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean containsBean(String name) {
return containsSingleton(name);
}
public void registerBean(String beanName, Object obj) {
this.registerSingleton(beanName, obj);
}
@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
this.beanDefinitions.put(name, beanDefinition);
this.beanDefinitionNames.add(name);
// 是否在加载时创建实例
// KEYPOINT 这里只是加载时 创建实例,而不是创建完整bean
if (!beanDefinition.isLazyInit()) {
try {
Object o = doCreateBean(beanDefinition);
earlySingletonObjects.put(name, o);
} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException |
InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
到这里我们就可以知道:由于在容器中,根据名称还是根据类型注入,可以根据容器的key设置,以及获取bean的流程控制,实际spring中@Autowire是优先根据类型匹配的,这里我们设置的方案是根据名称匹配。
源码地址:https://gitee.com/daiyuling/mini-spring 持续更新中~~