Spring 核心之 Ioc容器实现

    xiaoxiao2021-12-03  22

    Ioc 是在Spring中, 一种控制(依赖)反转模式的实现载体, 而这种模式采用倒置注入的方式解决对象依赖问题,这样可以简化对象依赖管理, 在很大程度上降低面向对象系统开发的复杂性, 控制反转是Spring框架的核心.


    1 . 先看一下Spring Ioc设计所关系到的一系列接口与类的继承实现关系

    最后的 (ClassPathXmlApplicationContext) 和 (XmlWebApplicationContext) 就是我们平时做SpringMVC开发常用到的初始化类对象。

    2 . 介绍说明一下上图中出现的各个接口的作用

    (1). BeanFactory: 访问获取 spring bean 容器中 bean 实例最基础的接口. (2). HierarchicalBeanFactory: 在 BeanFactory 的基础上添加了继承功能, bean工厂可以包含父容器; (3). ConfigurableBeanFactory: 为 BeanFactory 添加配置能力, 指定bean初始化方式等; (4). ListableBeanFactory: 可以加载获取到一系列的bean对象; (5). ConfigurableListableBeanFactory: 提供了分析与修改bean实例的能力, 及单例的预实例化; (6). AutowireCapableBeanFactory: 可以通过注解的方式为一个bean实例提供它所需的其他bean做为它的属性; (7). SimpleAliasRegistry: 一个简单的bean别名注册器; (8). DefaultSingletonBeanRegistry: 注册单例对象实例并运行被所有需要注册的bean所共享, 根据bean name获取; (9). FactoryBeanRegistrySupport: 在DefaultSingletonBeanRegistry上再做了层封装, 相当于一个管理对象可以安全被用户使用; (10). AbstractBeanFactory: 具有可配置bean工厂的全部功能, 同时提供了单例bean缓存, 可以处理, bean别名, bean定义及其子类定义合并, 还有bean的销毁方法等; (11). AbstractAutowireCapableBeanFactory: 实现了默认的bean创建方式, 同时添加了注解注入的功能; (12). BeanDefinitionRegistry: 注册bean定义在父子上下文容器里面; (13). DefaultListableBeanFactory: 一个默认的且完整的 Bean Factory 实现类, 具有bean工厂以上全部功能; (14). EnvironmentCapable: 具有获得一个环境信息对象的能力; (15). MessageSource: 处理相关信息源的能力, 比如支持国际化的实现等 (16). ApplicationEventPublisher: 支持应用程序事件为bean生命周期管理提供便利; (17). ResourcePatternResolver: 获取访问资源; (18). Lifecycle: 定义开始与结束的生命周期控制; (19). Closeable: 用于释放或关闭某些资源对象数据; (20). ApplicationContext: Spring的核心接口, 提供对一个应用的配置; 这个对象时只读的, 除非它的子对象进行重新载入; (21). ConfigurableApplicationContext: 结合了ApplicationContext, 添加了额外的应用程序生命周期等处理入口; (22). WebApplicationContext: 相比ApplicationContext添加了获取ServletContext的方法, 以支持web应用; (23). AbstractApplicationContext: ApplicationContext 的一个抽象实现类, 是SpringIoc容器初始化时的关键对象, 里面有一些列bean创建, 资源处理, 过滤器添加, 相关事件通知等; (24). InitializingBean: 当一个bean实例所依赖所有对象都被Bean factory注入后, 会回调这个接口中的afterPropertiesSet方法; (25). AbstractRefreshableApplicationContext: 实现了AbstractApplicationContext中的refreshBeanFactory方法, 进行spring bean factory的默认创建和bean定义解析载入; (26). BeanNameAware: 可以得到bean的名称; (27). AbstractRefreshableConfigApplicationContext: 在AbstractRefreshableApplicationContext的基础上引入了BeanNameAware和InitializingBean方法; (28). AbstractXmlApplicationContext: 实现了个装载bean的方法; (29). ClassPathXmlApplicationContext: 类路径下加载bean配置文件; (30). ConfigurableWebApplicationContext: 结合WebApplicationContext与ConfigurableApplicationContext; (31). ThemeSource: 获取Theme对象, 后面做资源转换; (32). FileSystemXmlApplicationContext: 文件系统路径下加载bean配置文件; (33). AbstractRefreshableWebApplicationContext: (34). XmlWebApplicationContext: Spring Web应用默认配置在”org.springframework.web.context.ContextLoader.properties”中的, 由”org.springframework.web.context.ContextLoaderListener”加载启动应用上下文的Class对象, 同时里面有bean定义解析的方法实现; (35). XmlBeanDefinitionReader: 读取解析spring配置xml文件中的bean定义信息及其他配置信息; (36). BeanDefinition: Spring bean factory中对bean对象定义的数据对象, 也是Spring Ioc中的核心数据结构对象;

    Spring容器加载启动过程

    3 . Spring Web应用由web.xml加载启动 (1). 首先会有如下两个配置项, 分别在ContextLoader与FrameworkServlet两个内里面有WebApplicationContext的创建加载解析操作;

    <!-- Spring Listener 需要加载的配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-context.xml</param-value> </context-param> // 配置Listener加载Spring应用上下文的父容器 <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> // 配置Listener加载Spring应用上下文的子容器 <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>

    (2). 从配置文件xml解析bean与项目配置信息的关键过程

    /** * Instantiate the WebApplicationContext for this servlet, either a default * {@link org.springframework.web.context.support.XmlWebApplicationContext} * or a {@link #setContextClass custom context class}, if set. * <p>This implementation expects custom contexts to implement the * {@link org.springframework.web.context.ConfigurableWebApplicationContext} * interface. Can be overridden in subclasses. * <p>Do not forget to register this servlet instance as application listener on the * created context (for triggering its {@link #onRefresh callback}, and to call * {@link org.springframework.context.ConfigurableApplicationContext#refresh()} * before returning the context instance. * @param parent the parent ApplicationContext to use, or {@code null} if none * @return the WebApplicationContext for this servlet * @see org.springframework.web.context.support.XmlWebApplicationContext */ protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); wac.setParent(parent); wac.setConfigLocation(getContextConfigLocation()); configureAndRefreshWebApplicationContext(wac); return wac; }

    (3). 创建完WebApplicationContext后进行初始化

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName()); } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); } postProcessWebApplicationContext(wac); applyInitializers(wac); wac.refresh(); }

    (4). 调用ConfigurableApplicationContext接口的refresh, 这个方法很关键, 里面是真正的bean创建与装配,

    @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing // 设置标志量, 这个方式是同步执行的 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 获取到beanFactory, 里面包含了所有bean的定义信息,别名信息等 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 设置一些默认属性, 包括类加载器, 表达式处理器, 过程处理器和context回调处理器等 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 可以加入额外的bean初始过程处理器, 对于web应用这里就会加入一个为ServletConfigAware类型的bean对象设置servlet上下文的处理器; postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 反转提取其他过程处理器,这里会有一个BeanDefinitionRegistryPostProcessor处理器, 如果项目使用了Mybatis, 那还会有个MapperScannerConfigurer的处理器(进行mybatis里面mapper扫描与dao实例植入); invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册一些拦截bean创建过程的处理器, 比如注解注入啊, requestmapping, aop切入等 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 初始化应用上下问的信息源 initMessageSource(); // Initialize event multicaster for this context. // 为应用上下文注册一个事件多路广播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 处理themeSource onRefresh(); // Check for listener beans and register them. // 为事件广播器设置进去需要通知的监听器的名称 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 单例Bean初始化与装配及相关接口回调 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 事件发布 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }

    4 . 几个有用的与Spring上下文及bean初始化进程相关的接口 (1). BeanNameAware: setBeanName方法,可以让该bean感知到在beanFactory中自己的名字; 调度时间是在该bean被实例化并装配好自身所依赖的属性后, 但在 InitializingBean#afterPropertiesSet() 之前; (2). BeanClassLoaderAware: setBeanClassLoader方法,可以让该bean感知到它是被哪个类加载器加载的;调度时间紧跟在 BeanNameAware 之后; (3). BeanClassLoaderAware: setBeanFactory方法,可以让该bean感知到它所在的BeanFactory;调度时间紧跟在 BeanClassLoaderAware之后; (4). InitializingBean: afterPropertiesSet方法, 当一个bean被完全装配完后调用的方法;此时这个bean已经具有了它应该有的所有业务功能; (5). DisposableBean: destroy方法, 在bean被销毁前调用, 可以做一些资源释放或者信息发送等操作; (6). ApplicationContextAware: setApplicationContext方法, 可以得到spring应用上下文的引用;

    转载请注明原文地址: https://ju.6miu.com/read-679989.html

    最新回复(0)