ioc的简单实现
│
│
└─文件目录
│ BeanReference.java----------------------------对Bean的封装
│
├─beans
│ │ AbstractBeanDefinitionReader.java----------抽象类
│ │ BeanDefinition.java------------------------
│ │ BeanDefinitionReader.java------------------接口
│ │ PropertyValue.java-------------------------
│ │ PropertyValues.java------------------------
│ │
│ ├─factory
│ │ AbstractBeanFactory.java---------------抽象类,实现BeanFactory接口
│ │ AutowireCapableBeanFactory.java--------
│ │ BeanFactory.java-----------------------接口,bean的容器
│ │
│ ├─io
│ │ Resource.java--------------------------接口
│ │ ResourceLoader.java--------------------
│ │ UrlResource.java-----------------------
│ │
│ └─xml
│ XmlBeanDefinitionReader.java----------
│
└─context
AbstractApplicationContext.java----------
ApplicationContext.java------------------
ClassPathXmlApplicationContext.java------
bean包下
BeanDefinitionReader接口
定义loadBeanDefinitions(String location)方法,从配置文件中导入BeanDefinitions
AbstractBeanDefinitionReader
实现BeanDefinitionReader接口
封装了Map<String,BeanDefinition> registry;ResourceLoader resourceLoader;
有参构造方法AbstractBeanDefinitionReader(ResourceLoader resourceLoader),初始化两个类变量 registry 和 resourceLoader
两个类变量的get方法
BeanDefinition
bean的内容及元数据,保存在BeanFactory中,包装bean的实体
类变量有
Object bean; //实例化的bean
Class beanClass; //bean的字节码
String beanClassName; //bean的全限定名
PropertyValues propertyValues = new PropertyValues();
setter & getter ...
其中setBeanClassName方法里面用反射实例化class。this.beanClass = Class.forName(beanClassName);
PropertyValues
final List<PropertyValue> propertyValueList
包装一个对象所有的PropertyValue。为什么封装而不是直接用List?因为可以封装一些操作。
addPropertyValue(PropertyValue pv);list.add之前可以对于重复propertyName进行判断,直接用list没法做到
PropertyValue
用于bean的属性注入
类变量
final String name;
final Object value;
bean包下的Factory包:
BeanFactory
接口,bean的容器,定义了根据name获取bean的方法getBean(String name)
AbstractBeanFactory
抽象类,实现BeanFactory接口
封装beanDefinitionMap(类型为ConcurrentHashMap)、beanDefinitionNames(类型为ArrayList)
重写BeanFactory接口 getBean 方法
从beanDefinitionMap里根据name获取BeanDefinition,从BeanDefinition里获取Bean,如果bean为null就创建(doCreateBean(beanDefinition));
方法registerBeanDefinition(String name, BeanDefinition beanDefinition)
注册bean,把name放入ArrayList,把BeanDefinition放入beanDefinitionMap
方法preInstantiateSingletons()
遍历beanDefinitionNames,调用getBean方法
哪里调用的?
定义抽象方法 doCreateBean(BeanDefinition beanDefinition)
需要子类实现
AutowireCapableBeanFactory
继承抽象类 AbstractBeanFactory
方法 applyPropertyValues(Object bean, BeanDefinition mbd)
从 beanDefinition 里获取封装的ArrayList对象获取对象里ArrayList遍历每一个 PropertyValue
通过参数bean获取class对象,获取名为 propertyValue.getName() 的字段
设置字段的 accessible 标志为 true
获取propertyValue封装的object
如果是BeanReference类或者是BeanReference的子类的一个实例,
强制转换成 BeanReference
调用父类的 getBean 方法
设置字段的bean值为从 propertyValue 获取的value???(有疑问,什么意思,不太理解)
方法 createBeanInstance(BeanDefinition beanDefinition)
从 beanDefinition 里获取 beanClass ,然后 newInstance() ,实例化对象
重写抽象方法 doCreateBean
调用 createBeanInstance
把初始化出来的bean设置回 beanDefinition
调用 applyPropertyValues
bean包下的io包:
Resource
接口
spring内部定位资源的接口
定义方法 getInputStream(); 获取输入流
UrlResource
实现Resource接口
类变量
final URL url;
重写父类方法getInputStream();使用URLConnection获取输入流
ResourceLoader
方法 getResource(String location)
先通过this.getClass().getClassLoader().getResource(location);ClassLorder类的方法:URL getResource(String name) 查找具有给定名称的资源
将返回的URL作为参数实例化UrlResource类
外部直接调用ResourceLoader来加载xml文件,然后调用解析xml文件的类就行了
bean包下的xml包:
XmlBeanDefinitionReader
实现了 AbstractBeanDefinitionReader 类
重写了 BeanDefinitionReader 接口的 loadBeanDefinitions 方法
调用父类的 getResourceLoader方法获取ResourceLoader然后resourceLoader.getResource(location).getInputStream();获取输入流
doLoadBeanDefinitions(InputStream inputStream) 使用JDK自带的工具解析xml,略过此过程。。。
context包:
ApplicationContext
接口,继承 BeanFactory 接口
AbstractApplicationContext
抽象类,实现 ApplicationContext 接口
依赖 AbstractBeanFactory
重写 getBean 方法,调用 AbstractBeanFactory 的 getBean 方法
refresh() 为空,应该是简化了,需要后续实现
ClassPathXmlApplicationContext
感觉这个类比较重要
继承AbstractApplicationContext
两个构造函数挺有意思
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
重写了父类的 refresh 方法
初始化 XmlBeanDefinitionReader ,调用它的 loadBeanDefinitions 方法
调用 xmlBeanDefinitionReader.getRegistry() 方法,其实是调用其父类 AbstractBeanDefinitionReader 的方法,获取父类 AbstractBeanDefinitionReader 中封装的 Map<String,BeanDefinition> registry
然后调用 Map 类的 entrySet() 方法, ----返回此映射中包含的映射关系的 Set 视图?----返回Set<Map.Entry<K, V>>
遍历 Map.Entry<String, BeanDefinition> beanDefinitionEntry
调用 beanFactory 的 registerBeanDefinition 方法,注册 Bean ...
│
│
└─文件目录
│ BeanReference.java----------------------------对Bean的封装
│
├─beans
│ │ AbstractBeanDefinitionReader.java----------抽象类
│ │ BeanDefinition.java------------------------
│ │ BeanDefinitionReader.java------------------接口
│ │ PropertyValue.java-------------------------
│ │ PropertyValues.java------------------------
│ │
│ ├─factory
│ │ AbstractBeanFactory.java---------------抽象类,实现BeanFactory接口
│ │ AutowireCapableBeanFactory.java--------
│ │ BeanFactory.java-----------------------接口,bean的容器
│ │
│ ├─io
│ │ Resource.java--------------------------接口
│ │ ResourceLoader.java--------------------
│ │ UrlResource.java-----------------------
│ │
│ └─xml
│ XmlBeanDefinitionReader.java----------
│
└─context
AbstractApplicationContext.java----------
ApplicationContext.java------------------
ClassPathXmlApplicationContext.java------
bean包下
BeanDefinitionReader接口
定义loadBeanDefinitions(String location)方法,从配置文件中导入BeanDefinitions
AbstractBeanDefinitionReader
实现BeanDefinitionReader接口
封装了Map<String,BeanDefinition> registry;ResourceLoader resourceLoader;
有参构造方法AbstractBeanDefinitionReader(ResourceLoader resourceLoader),初始化两个类变量 registry 和 resourceLoader
两个类变量的get方法
BeanDefinition
bean的内容及元数据,保存在BeanFactory中,包装bean的实体
类变量有
Object bean; //实例化的bean
Class beanClass; //bean的字节码
String beanClassName; //bean的全限定名
PropertyValues propertyValues = new PropertyValues();
setter & getter ...
其中setBeanClassName方法里面用反射实例化class。this.beanClass = Class.forName(beanClassName);
PropertyValues
final List<PropertyValue> propertyValueList
包装一个对象所有的PropertyValue。为什么封装而不是直接用List?因为可以封装一些操作。
addPropertyValue(PropertyValue pv);list.add之前可以对于重复propertyName进行判断,直接用list没法做到
PropertyValue
用于bean的属性注入
类变量
final String name;
final Object value;
bean包下的Factory包:
BeanFactory
接口,bean的容器,定义了根据name获取bean的方法getBean(String name)
AbstractBeanFactory
抽象类,实现BeanFactory接口
封装beanDefinitionMap(类型为ConcurrentHashMap)、beanDefinitionNames(类型为ArrayList)
重写BeanFactory接口 getBean 方法
从beanDefinitionMap里根据name获取BeanDefinition,从BeanDefinition里获取Bean,如果bean为null就创建(doCreateBean(beanDefinition));
方法registerBeanDefinition(String name, BeanDefinition beanDefinition)
注册bean,把name放入ArrayList,把BeanDefinition放入beanDefinitionMap
方法preInstantiateSingletons()
遍历beanDefinitionNames,调用getBean方法
哪里调用的?
定义抽象方法 doCreateBean(BeanDefinition beanDefinition)
需要子类实现
AutowireCapableBeanFactory
继承抽象类 AbstractBeanFactory
方法 applyPropertyValues(Object bean, BeanDefinition mbd)
从 beanDefinition 里获取封装的ArrayList对象获取对象里ArrayList遍历每一个 PropertyValue
通过参数bean获取class对象,获取名为 propertyValue.getName() 的字段
设置字段的 accessible 标志为 true
获取propertyValue封装的object
如果是BeanReference类或者是BeanReference的子类的一个实例,
强制转换成 BeanReference
调用父类的 getBean 方法
设置字段的bean值为从 propertyValue 获取的value???(有疑问,什么意思,不太理解)
方法 createBeanInstance(BeanDefinition beanDefinition)
从 beanDefinition 里获取 beanClass ,然后 newInstance() ,实例化对象
重写抽象方法 doCreateBean
调用 createBeanInstance
把初始化出来的bean设置回 beanDefinition
调用 applyPropertyValues
bean包下的io包:
Resource
接口
spring内部定位资源的接口
定义方法 getInputStream(); 获取输入流
UrlResource
实现Resource接口
类变量
final URL url;
重写父类方法getInputStream();使用URLConnection获取输入流
ResourceLoader
方法 getResource(String location)
先通过this.getClass().getClassLoader().getResource(location);ClassLorder类的方法:URL getResource(String name) 查找具有给定名称的资源
将返回的URL作为参数实例化UrlResource类
外部直接调用ResourceLoader来加载xml文件,然后调用解析xml文件的类就行了
bean包下的xml包:
XmlBeanDefinitionReader
实现了 AbstractBeanDefinitionReader 类
重写了 BeanDefinitionReader 接口的 loadBeanDefinitions 方法
调用父类的 getResourceLoader方法获取ResourceLoader然后resourceLoader.getResource(location).getInputStream();获取输入流
doLoadBeanDefinitions(InputStream inputStream) 使用JDK自带的工具解析xml,略过此过程。。。
context包:
ApplicationContext
接口,继承 BeanFactory 接口
AbstractApplicationContext
抽象类,实现 ApplicationContext 接口
依赖 AbstractBeanFactory
重写 getBean 方法,调用 AbstractBeanFactory 的 getBean 方法
refresh() 为空,应该是简化了,需要后续实现
ClassPathXmlApplicationContext
感觉这个类比较重要
继承AbstractApplicationContext
两个构造函数挺有意思
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
重写了父类的 refresh 方法
初始化 XmlBeanDefinitionReader ,调用它的 loadBeanDefinitions 方法
调用 xmlBeanDefinitionReader.getRegistry() 方法,其实是调用其父类 AbstractBeanDefinitionReader 的方法,获取父类 AbstractBeanDefinitionReader 中封装的 Map<String,BeanDefinition> registry
然后调用 Map 类的 entrySet() 方法, ----返回此映射中包含的映射关系的 Set 视图?----返回Set<Map.Entry<K, V>>
遍历 Map.Entry<String, BeanDefinition> beanDefinitionEntry
调用 beanFactory 的 registerBeanDefinition 方法,注册 Bean ...