透彻理解SpringIOC设计原理分析
接下来我们带着问题学习
1、 Spring平台组成技术体系有哪些?
2、 SpringIoc容器技术的设计演化?
3、 高级形式容器技术ApplicationContext的初始化细节?
4、 容器中的Bean组件如何装配依赖?
Spring是一个分层框架,由七个体系模块组成。所有的模块都是构建在容器技术上
由上图看出所有的模块都是以SpringCore即Bean容器技术为基础的,换句话说:
SpringIOC容器技术,为我们上层所有模块提供依赖注入,这样上层模块才能正确执行, Java尿性,解耦
SpringIOC都是以面向接口编程, 将IOC容器技术体系勾勒的非常清晰, 实现非常复杂, 子类实现多样性。
容器技术最开始思路?
BeanFactory:完成Bean实例的提供工作,输入参数,产出成品, 可以反复提供
BeanFactory源码分析?
只需要把FileSystemXmlApplicationContext里面的设计运转原理搞懂就窥视我们Ioc容器的体系
public FileSystemXmlApplicationContext(String[]configLocations, boolean refresh, ApplicationContext parent) throws BeansException{ // 调用父类的构造, 确认关系 super(parent); setConfigLocations(configLocations); if (refresh){ refresh(); }}
refresh方法是主方法
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // 初始化beanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }@Override protected final void refreshBeanFactory() throws BeansException { // 如果过旧的bean工厂,销毁清空 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); // 加载我们外部配置的BeanDefinitions字节信息到工厂 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
再进入 AbstractXmlApplicationContext类中的这个方法;这里加入了reader读取器
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 加载xml的读取器到beanFactory中 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); // 关键对BeanDefinition进入载入IOC源码分析, 通过Resouce定位路径来读取 loadBeanDefinitions(beanDefinitionReader); }ResourceLoader如下
/** Pseudo URL prefix for loading from the class path: "classpath:" */ String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
获取资源的方法,Resource可以是下面成千上万种子类, IO定位的对象
通过Reader读取器, 通过Resouce(IO)通道来读取外界配置的beanDefinition的信息applicationContext
然后注册到某个集合容器,String Name(bean id =”xxx”)装配输出这个实例
@Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }
Reader的入口,就是在Resource 的基础上来进行加载, 再进入源码分析
Definition? IOC的内部数据结构.
注册环节:
BeanDefinitionRegistery
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;ApplicationContext.getBean()扫描注解的时候拿到我们需要的实例, getBean 内部隐化