文档章节

Spring IOC容器的理解

z
 zhaoxp0909
发布于 2017/06/02 15:46
字数 1465
阅读 41
收藏 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
IoC容器的实现( IoC 容器概述和在 Spring 中的应用场景)

1 IoC 容器概述 1.1 IOC 容器和依赖反转模式 我们日常的 java 项目开发都是由两个或多个类的彼此合作来实现业务逻辑的,这使得每个对象都需要与其合作的对象的引用(称为所依赖的对象),如果...

偷星辰夜
2017/11/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring核心概念--Spring01

小生初出程序茅庐,走上编程之路,还请各位大佬多多管照。 初学Spring框架: 创建HelloWorldSpring项目 用eclipse开发Web项目,添加jar包: commons-logging-1.2.jar log4j-1.2.17.jar spring-...

小橙子的曼曼
29分钟前
2
0
MySQL 运行状态监控方法

一、通过shell脚本监控mysql的qps,tps,io详细见附件脚本《mysqlgather.sh》 因在脚本中直接设置密码会提示告警信息,需要在my.cnf文件中的[client]标签下增加默认的用户名和密码,并重启mys...

PeakFang-BOK
33分钟前
2
0
ROS实操笔记 四 topic (主题)

主题 消息以一种发布/订阅的方式传递。一个节点可以在一个给定的主题中发布消息。一个节点针对某个主题关注与订阅特定类型的数据。可能同时有多个节点发布或者订阅同一个主题的消息。总体上,...

placido
34分钟前
1
0
【NLP】【六】gensim之doc2vec

【一】总述 doc2vec是指将句子、段落或者文章使用向量来表示,这样可以方便的计算句子、文章、段落的相似度。 【二】使用方法介绍 1. 预料准备 def read_corpus(fname, tokens_only=False):...

muqiusangyang
37分钟前
0
0
node中process.nextTick & promise & 异步IO & setTimeout & setImmediate 的优先级

process.nextTick > promise > setTimeout > 异步IO > setImmediate

小草先森
43分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部