文档章节

Spring IOC容器的理解

z
 zhaoxp0909
发布于 2017/06/02 15:46
字数 1465
阅读 31
收藏 1

Spring是当下主流的开发框架,一个轻量级的DIAOP容器框架,核心思想是IOC和AOP,也是面试中是必问题,开发人员不可不知道,最近和很多面试官交流发现,很多人仅仅是简单知道几个概念,或者大概了解下(我也是这样,时间一长忘了),还是老话好:好记性不如烂笔头。

如何理解IOC

   我的理解是:程序之间的关系由容器管理,组件对象之间的使用关系由主动变成被动,不再直接相互依赖,也就是说组件对象的所有权交给了外部容器管理,使用时通过外部容器获取对象,控制权的转移也就是所谓反转了。目前主流的IOC实现有Spring,EJB,piconcontainer等。

 意义何在?

   在这里不能不说一种软件工程思想——DIP(依赖倒转原则)   

依赖倒置原则
A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

   IOC是DIP的很好体现。解决软件各层之间的解耦,降低了业务对象替换的复杂性,更容易提高开发效率, 

  实现 

    到这里,还要理解对象是如何交由IOC容器管理呢,又如何从IOC容器中获得对象——其实就是所谓的DI和Service Locator,DI就是所谓的依赖注入,  Service Locator就是我们如何从容器中获得对象。

  DI的实现目前有三种方式:

1、使用构造函数
2、属性注入
3、接口注入

 从容器中获得对象,一般我们通过给要使用服务对象指定特定的别名通过工厂模式读取。

spring中依赖注入和Service Locator

使用ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext进行实例化,

1. ApplicationContext fileApplicationContext = new FileSystemXmlApplicationContext( "D:/workSpace/springDemo/src/resourceapplicationcontext.xml ");
2. ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext( "/applicationcontext.xml ");
3. ServletContext servletContext = request.getSession().getServletContext();
   ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);

可以发现 spring的核心结构:

BeanFactory和BeanDefinition

无论是何种方式,使用AbstractApplicationContext#refresh())进行启动:

public void refresh() throws BeansException, IllegalStateException {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//加载配置并将注册bean
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);//为容器的某些子类指定特殊的BeanPost事件处理器
            this.invokeBeanFactoryPostProcessors(beanFactory); //调用所有注册的BeanFactoryPostProcessor的Bean 
            this.registerBeanPostProcessors(beanFactory);  //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 
            this.initMessageSource();//初始化信息源,和国际化相关
            this.initApplicationEventMulticaster();//初始化容器事件传播器.  
            this.onRefresh();//调用子类的某些特殊Bean初始化方法  
            this.registerListeners();//为事件传播器注册事件监听器.  
            this.finishBeanFactoryInitialization(beanFactory);//初始化所有剩余的单态Bean
            this.finishRefresh();//初始化容器的生命周期事件处理器,并发布容器的生命周期事件 
        } catch (BeansException var9) {
            if(this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();//销毁bean
            this.cancelRefresh(var9);//取消启动
            throw var9;
        } finally {
            this.resetCommonCaches();//重置缓存
        }

    }

1.加载配置,DefaultBeanDefinitionDocumentReader读取xml元素委托BeanDefinitionParserDelegate解析并注册bean信息(对应上文中ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory()),并由此构建了BeanFactory

(BeanFactory构建后,在bean未在加载前,我们可通过实现BeanFactoryPostProcessor进行扩展,见后续MyBeanFactoryPostProcessor)

public class BeanDefinitionParserDelegate{
......
/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}
......
}
public class BeanDefinitionReaderUtils {
......
/**
 * Register the given bean definition with the given bean factory.
 * @param definitionHolder the bean definition including name and aliases
 * @param registry the bean factory to register with
 * @throws BeanDefinitionStoreException if registration failed
 */
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String aliase : aliases) {
         registry.registerAlias(beanName, aliase);
      }
   }
}

......
}

MyBeanFactoryPostProcessor

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
        BeanDefinition bd = beanFactory.getBeanDefinition("tester");
        System.out.println("属性值============" + bd.getPropertyValues().toString());
    }
}

2.载入Bean并初始化(文中上部分finishBeanFactoryInitialization方法),检查Bean类的限定名是否存在,如果不存在,异常抛出;

at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
    at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:394)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1397)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1344)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:628)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:597)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1445)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:975)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:752)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:666)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:632)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:680)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:551)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:492)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)

对于bean的初始化进行扩展

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> aClass, String s) throws BeansException {
        System.out.println("postProcessBeforeInstantiation ...." + s);
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInstantiation ...." + s);
        return false;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues propertyValues, PropertyDescriptor[] propertyDescriptors, Object o, String s) throws BeansException {
        System.out.println("postProcessPropertyValues ...." + s);
        return propertyValues;
    }

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization ...." + s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization ...." + s);
        return o;
    }
}
/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization ...." + s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization ...." + s);
        return o;
    }
}

执行结果:

postProcessBeforeInstantiation ....tester
postProcessAfterInstantiation ....tester
postProcessBeforeInitialization ....tester
postProcessBeforeInitialization ....tester
postProcessAfterInitialization ....tester
postProcessAfterInitialization ....tester
postProcessBeforeInstantiation ....myInitializingBeanDisposableBean
postProcessAfterInstantiation ....myInitializingBeanDisposableBean
postProcessBeforeInitialization ....myInitializingBeanDisposableBean
postProcessBeforeInitialization ....myInitializingBeanDisposableBean

下面的实现是所有bean初始化后被执行

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyInitializingBean implements InitializingBean {
   
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("-----------afterPropertiesSet");
    }
}

3.获取bean(也就是在Service Locator):部分bean的初始化使用延迟初始化,也就是第一次向容器索要bean时实例化,通过工厂模式BeanFanctory去管理bean的生命周期(参考其实现类AbstractBeanFactory中createBean、doGetBean、getBean、destroyBean等方法)。

4.bean的销毁

public void destroy() {
    this.close();
}

public void close() {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.doClose();
        if(this.shutdownHook != null) {
            try {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
            } catch (IllegalStateException var4) {
                ;
            }
        }

    }
}

也可自定义

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyInitializingDisposableBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("-----------destroy");
    }
}

参考资料:

http://blog.csdn.net/hongxingxiaonan/article/details/49531891

http://uule.iteye.com/blog/2094609

© 著作权归作者所有

共有 人打赏支持
z
粉丝 1
博文 9
码字总数 12877
作品 0
朝阳
程序员
三条路线告诉你如何掌握Spring IoC容器的核心原理

一、前言 前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一...

Java小铺
08/27
0
0
【Spring学习笔记】--IOC学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YYZZHC999/article/details/82824751 spring ioc原理 Ioc—Inversion of Control,即“控制反转”,不是什么技...

Hepburn_Yang
09/23
0
0
1 Spring核心:IoC容器的实现

依赖控制反转的实现有很多种方式。在Spring中,IoC容器是实现这个模式的载体, 它可以在对象生成或初始化时直接将数据注入到对象中,也可以通过将对象引用注入到对象数据域中的方式来注入对方...

qq_18150351
04/24
0
0
深入理解Spring源码(一)-IOC容器的定位,载入,注册

前言:Spring源码继承,嵌套层次非常多,读起来非常容易晕,小伙伴们在看文章的时候一定要跟着文章的思路自己去源码里点一点,看一看,并且多看几次。就会越来越清晰。下面开始正题 1.Spring...

Meet相识_bfa5
05/01
0
0
阿里老司机带你使用Spring框架快速搭建Web工程项目

摘要:Spring 框架是一个开源的 Java 平台,它为容易而快速的开发出耐用的 Java 应用程序提供了全面的基础设施。借助于Spring框架可以快速搭建Web工程项目,本文中阿里巴巴高级开发工程师嵛山...

萌萌怪兽
05/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis中jdbcType和javaType的对应关系 

Mybatis中jdbcType和javaType的对应关系 1 JDBC Type Java Type 2 CHAR String 3 VARCHAR String 4 LONGVARCHAR String 5 NUMERIC java.math.BigDecimal 6 DECIMAL java.math.BigDecimal 7 ......

DemonsI
15分钟前
2
0
Python中字符串和datetime

遇到的问题: 今天在写一个爬虫时,需要将今天的数据和昨天、一周前的数据做比较。所以就需要一个方法可以方便的计算出指定日期的前几天的日期。比如10月3号,则一周前的日期是9月26号。 问题...

akane_oimo
17分钟前
1
0
企业级 SpringBoot 教程 (四)SpringBoot 整合JPA

JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 JPA 的目标之一是制定一个可以由很多供应商实现的API,并且开发...

itcloud
18分钟前
1
0
白话SpringCloud | 第六章:Hystrix监控面板及数据聚合(Turbine)

前言 前面一章,我们讲解了如何整合Hystrix。而在实际情况下,使用了Hystrix的同时,还会对其进行实时的数据监控,反馈各类指标数据。今天我们就将讲解下Hystrix Dashboard和Turbine.其中Hys...

oKong
29分钟前
1
0
Java JDK 11:现在可以使用所有新功能

删除了CORBA,Java EE和JavaFX支持,但添加了十几个主要新功能 目录 哪里可以下载JDK 11 Java 11 JDK中的新功能 从Java JDK 11中删除了什么 Java Development Kit(JDK)11现已普遍可用,可供...

GuoMengyue
30分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部