Spring源码-IOC部分-自定义IOC容器及Bean解析注册【4】

本文内容纲要:Spring源码-IOC部分-自定义IOC容器及Bean解析注册【4】

实验环境:spring-framework-5.0.2、jdk8、gradle4.3.1

  • Spring源码-IOC部分-容器简介【1】
  • Spring源码-IOC部分-容器初始化过程【2】
  • Spring源码-IOC部分-Xml Bean解析注册过程【3】
  • Spring源码-IOC部分-自定义IOC容器及Bean解析注册【4】
  • Spring源码-IOC部分-Bean实例化过程【5】
  • Spring源码-IOC部分-Spring是如何解决Bean循环依赖的【6】
  • Spring源码-IOC部分-循环依赖-用实例证明去掉二级缓存会出现什么问题【7】

上文介绍了一些常用容器及初始化、Bean解析过程,源码里面的实现比较复杂,如果我们想要自己实现一个IOC容器,自定义bean配置文件该怎么做呢?

其实只要了解核心思路实现起来是很简单的,只需3步:

1)继承AbstractApplicationContext

2)读取配置文件,封装成beanDefinition对象,存入beanDefinitionMap中

3)调用refresh方法

1、定义配置文件 新建一个文件,格式如下:`user`是bean的名字,`beans.User`是bean的类路径,其中的`id`、`name`是字段属性值

user=beans.User{id:001,name:小明}

user2=beans.User2{id:002,name:小明2}

package beans;

import org.springframework.stereotype.Component;

@Component

public class User {

private int id;

private String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

@Override

public String toString() {

return "User{" +

"id=" + id +

", name='" + name + '\'' +

'}';

}

}

2、既然我们定义好了配置文件格式,那么就需要一个BeanDefinitionReader来针对这类文件进行解析

package context;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.Reader;

import java.io.StringReader;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Objects;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.BeanDefinitionStoreException;

import org.springframework.beans.factory.config.BeanDefinition;

import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

import org.springframework.util.StringUtils;

/**

* 自定义BeanDefinitionReader

*/

public class MyBeanDefinitionReader extends AbstractBeanDefinitionReader {

protected final Log logger = LogFactory.getLog(getClass());

public MyBeanDefinitionReader(BeanDefinitionRegistry registry) {

super(registry);

}

@Override

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

// 解析配置文件

List<BeanDef> beanDefList = parseResource(resource);

beanDefList.forEach(beanDef -> {

// 构造BeanDefinition

BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder

.genericBeanDefinition(beanDef.getClassPath());

// 填充参数

beanDef.getParamMap().forEach(beanDefinitionBuilder::addPropertyValue);

// 注册

super.getBeanFactory().registerBeanDefinition(beanDef.getId(),

beanDefinitionBuilder.getBeanDefinition());

});

return beanDefList.size();

}

private List<BeanDef> parseResource(Resource resource) {

List<BeanDef> beanDefList = new ArrayList<>();

BufferedReader reader = null;

try {

reader = new BufferedReader(new BufferedReader(new InputStreamReader(resource.getInputStream())));

String line = reader.readLine();

while (!StringUtils.isBlank(line)) {

BeanDef beanDef = buildBeanDef(line);

if (!beanDefList.contains(beanDef)) {

beanDefList.add(beanDef);

} else {

throw new RuntimeException("bean定义重复" + beanDef);

}

line = reader.readLine();

}

reader.close();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (reader != null) {

try {

reader.close();

} catch (IOException e1) {

e1.printStackTrace();

}

}

}

return beanDefList;

}

private BeanDef buildBeanDef(String line) {

BeanDef beanDef = new BeanDef();

String[] split = line.split("=");

String id = split[0];

beanDef.setId(id);

String source = split[1];

if (source.contains("{") && source.contains("}")) {

int begin = source.indexOf("{");

int end = source.indexOf("}");

String classPath = source.substring(0, begin);

beanDef.setClassPath(classPath);

String params = source.substring(begin + 1, end);

String[] paramArray = params.split(",");

for (String param : paramArray) {

String[] kv = param.split(":");

beanDef.getParamMap().put(kv[0], kv[1]);

}

} else {

beanDef.setClassPath(source);

}

return beanDef;

}

public static class BeanDef {

private String id;

private String classPath;

private Map<String, Object> paramMap = new HashMap<>();

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getClassPath() {

return classPath;

}

public void setClassPath(String classPath) {

this.classPath = classPath;

}

public Map<String, Object> getParamMap() {

return paramMap;

}

@Override

public boolean equals(Object o) {

if (this == o) {

return true;

}

if (o == null || getClass() != o.getClass()) {

return false;

}

BeanDef beanDef = (BeanDef) o;

return id.equals(beanDef.id) &&

classPath.equals(beanDef.classPath);

}

@Override

public int hashCode() {

return Objects.hash(id, classPath);

}

@Override

public String toString() {

return "BeanDef{" +

"id='" + id + '\'' +

", classPath='" + classPath + '\'' +

", paramMap=" + paramMap +

'}';

}

}

}

3、现在我们可以读取bean配置文件,然后解析成BeanDefinition注册到容器中,于是我们再准备一个容器

package context;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.concurrent.atomic.AtomicBoolean;

import java.util.function.Supplier;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanDefinitionStoreException;

import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import org.springframework.beans.factory.config.AutowireCapableBeanFactory;

import org.springframework.beans.factory.config.BeanDefinition;

import org.springframework.beans.factory.config.BeanDefinitionCustomizer;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.AbstractApplicationContext;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

import org.springframework.core.io.ResourceLoader;

import org.springframework.core.io.support.ResourcePatternResolver;

import org.springframework.lang.Nullable;

import org.springframework.util.Assert;

/**

* 自定义容器实现

*/

public class MyApplicationContext extends AbstractApplicationContext {

private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 创建自定义bean解析器,传入bean注册器beanFactory

private final MyBeanDefinitionReader definitionReader = new MyBeanDefinitionReader(beanFactory);

public MyApplicationContext(String resourcePath) {

this.definitionReader.loadBeanDefinitions(new ClassPathResource(resourcePath));

this.refresh();

}

/**

* 设置父容器,比如spring mvc容器作为子容器,父容器是spring容器

*/

@Override

public void setParent(@Nullable ApplicationContext parent) {

super.setParent(parent);

this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());

}

@Override

public void setId(String id) {

super.setId(id);

}

public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {

this.beanFactory.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding);

}

public void setAllowCircularReferences(boolean allowCircularReferences) {

this.beanFactory.setAllowCircularReferences(allowCircularReferences);

}

//---------------------------------------------------------------------

// ResourceLoader / ResourcePatternResolver override if necessary

//---------------------------------------------------------------------

@Override

public Resource getResource(String location) {

return super.getResource(location);

}

@Override

public Resource[] getResources(String locationPattern) throws IOException {

return super.getResources(locationPattern);

}

@Override

public void setClassLoader(@Nullable ClassLoader classLoader) {

super.setClassLoader(classLoader);

}

@Override

@Nullable

public ClassLoader getClassLoader() {

return super.getClassLoader();

}

//---------------------------------------------------------------------

// Implementations of AbstractApplicationContext's template methods

//---------------------------------------------------------------------

@Override

protected final void refreshBeanFactory() throws IllegalStateException {

this.beanFactory.setSerializationId(getId());

}

@Override

protected void cancelRefresh(BeansException ex) {

this.beanFactory.setSerializationId(null);

super.cancelRefresh(ex);

}

@Override

protected final void closeBeanFactory() {

this.beanFactory.setSerializationId(null);

}

@Override

public final ConfigurableListableBeanFactory getBeanFactory() {

return this.beanFactory;

}

public final DefaultListableBeanFactory getDefaultListableBeanFactory() {

return this.beanFactory;

}

@Override

public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {

assertBeanFactoryActive();

return this.beanFactory;

}

// 子类重写

@Override

public void postProcessBeanFactory(

ConfigurableListableBeanFactory beanFactory) {

if (beanFactory instanceof DefaultListableBeanFactory) {

DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanFactory;

String[] beanDefinitionNames = factory.getBeanDefinitionNames();

System.out.println("step4.1 postProcessBeanFactory子类重写,已经加载beanDefinitionNames " + Arrays.asList(beanDefinitionNames));

}

}

// 子类重写

@Override

protected void onRefresh() throws BeansException {

ConfigurableListableBeanFactory beanFactory = getBeanFactory();

String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();

System.out.println("step9.1 onRefresh子类重写,已经加载beanDefinitionNames " + Arrays.asList(beanDefinitionNames));

}

}

4、测试一下bean能否正常注入到容器中

public class Main {

public static void main(String[] args) {

testMyApplicationContext();

}

private static void testMyApplicationContext() {

String path = "/config/mycontext.txt";

MyApplicationContext context = new MyApplicationContext(path);

System.out.println(context.getBean("user"));

context.close();

}

}

参考资料:

《Spring5核心原理与30个类手写》作者 谭勇德

《Spring源码深度解析》作者 郝佳

《Spring技术内幕》作者 计文柯

本文内容总结:Spring源码-IOC部分-自定义IOC容器及Bean解析注册【4】

原文链接:https://www.cnblogs.com/wwzyy/p/15860179.html

以上是 Spring源码-IOC部分-自定义IOC容器及Bean解析注册【4】 的全部内容, 来源链接: utcz.com/z/362361.html

回到顶部