原理
手写一个简单的Spring容器,用配置文件方式,在配置文件中写入我们想要的bean,bean实例被用到时注册(注册到仓库,或者说缓存),后续我们就可以直接根据bean的名字拿到这个bean的单例。
Spring容器,就是Spring帮忙管理类(JavaBean),我们先写一个简单的单例容器,Bean的配置写在配置文件(beans.properties)中,格式是:
<beanName>:<fullClassName>
要根据名字获取一个bean,就需要用到工厂,当工厂被实例化时,就会用资源加载器,去反射创建bean(也就是beanDefinition),然后存入beanDefinitionMap。
beanDefinition不是一个普通的类,而是一个有beanName和ClassName的类,有了这两项才好被用来创建(反射)和管理(配合注册机)bean的使用实例。
通过资源加载创建的beanDefinition先放置到beanDefinitionMap(一个临时的bean表),每次getBean(通过beanName)的时候,如果注册机已经注册了这个bean,那么直接从注册机获取,否则从beanDefinitionMap中取出beanDefinition,根据beanDefinition的内容反射创建实例,并通过工厂内部的BeanRegister注册机(本质也是一个HashMap)进行注册。(甚至可以理解为缓存)
代码
bean配置
beans.properties 这里边只有一个bean的beanName:fullClassName
userDao:UserDao
bean工厂
BeanFactory.java
import java.util.*;
public class BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
private BeanRegister beanRegister;
public BeanFactory() {
beanRegister = new BeanRegister();
this.beanDefinitionMap = new ResourceLoader().getResource();
}
public Object getBean(String beanName) {
Object bean = beanRegister.getSingletonBean(beanName);
if (bean != null) {
return bean;
}
return createBean(beanDefinitionMap.get(beanName));
}
private Object createBean(BeanDefinition beanDefinition) {
try {
Object bean = beanDefinition.getBeanClass().newInstance();
beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean);
return bean;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
注册机
BeanRegister.java 一个HashMap实现单例注册
import java.util.*;
public class BeanRegister {
private Map<String, Object> singletonMap = new HashMap<>(32);
public Object getSingletonBean(String beanName) {
return singletonMap.get(beanName);
}
public void registerSingletonBean(String beanName, Object bean) {
if (singletonMap.containsKey(beanName)) {
return;
}
singletonMap.put(beanName, bean);
}
}
资源加载
ResourceLoader.java
import java.util.*;
import java.io.*;
public class ResourceLoader {
public static Map<String, BeanDefinition> getResource() {
Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16);
Properties properties = new Properties();
try {
InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties");
properties.load(inputStream);
Iterator<String> it = properties.stringPropertyNames().iterator();
while (it.hasNext()) {
String key = it.next();
String className = properties.getProperty(key);
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanName(key);
Class clazz = Class.forName(className);
beanDefinition.setBeanClass(clazz);
beanDefinitionMap.put(key, beanDefinition);
}
inputStream.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return beanDefinitionMap;
}
}
Bean定义
BeanDefinition.java
public class BeanDefinition {
private String beanName;
private Class beanClass;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
}
Bean原型
UserDao.java
public class UserDao {
public void queryUserInfo(){
System.out.println("A good man.");
}
}
测试
ApiTest.java
public class ApiTest {
public void test_BeanFactory() {
BeanFactory beanFactory = new BeanFactory();
UserDao userDao1 = (UserDao) beanFactory.getBean("userDao");
userDao1.queryUserInfo();
UserDao userDao2 = (UserDao) beanFactory.getBean("userDao");
userDao2.queryUserInfo();
}
public static void main(String[] args) {
new ApiTest().test_BeanFactory();
}
}
参考: 程序员鱼皮《五分钟,手撸一个Spring容器!》
|