你的位置:首页 > Java教程

[Java教程]Spring IOC容器源码浅析


     控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找。依赖注入应用比较广泛。把控制权从具体的对象手中交给平台或者是框架。

2 BeanFactory是基本的功能接口

public interface BeanFactory {  //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,  //如果需要得到工厂本身,需要转义      String FACTORY_BEAN_PREFIX = "&";  //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。  Object getBean(String name) throws BeansException;  //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。  Object getBean(String name, Class requiredType) throws BeansException;  //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean  boolean containsBean(String name);  //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件  boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  //这里对得到bean实例的Class类型  Class getType(String name) throws NoSuchBeanDefinitionException;  //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  String[] getAliases(String name);}

    BeanFactory只是对IOC容器中的基本行为作了定义,但是并没有管理如何加载baen.

spring提供了一个BeanFactory的基本实现----

  ClassPathResource res = new ClassPathResource("beans.);  DefaultListableBeanFactory factory = new DefaultListableBeanFactory();  = new 




  • 创建IOC配置文件的抽象资源
  • 创建一个BeanFactory
  •  

public class extends DefaultListableBeanFactory {  //这里为容器定义了一个默认使用的bean定义读取器  private final new this);  public throws BeansException {    this(resource, null);  }  //在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。  public throws BeansException {    super(parentBeanFactory);    this.reader.loadBeanDefinitions(resource);  }




ApplicationContext

  ApplicationContext = new FileSystem



      继承Messagesource,可以支持不同的信息源

      访问资源,ResourceLoader和Resource,可以从不同的地方来获取Bean的定义资源

      支持应用事件,继承了ApplicationEvnetPublisher接口

     ApplicationContext允许上下文嵌套 - 通过保持父上下文可以维持一个上下文体系 - 这个体系我们在以后对Web容器中的上下文环境的分析中可以清楚地看到。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。这个我们在分析Web容器中的上下文环境时也能看到。
ApplicationContext提供IoC容器的主要接口,在其体系中有许多抽象子类比如AbstractApplicationContext为具体的BeanFactory的实现,比如FileSystem
     BeanFactory 是一个接口,在实际应用中我们一般使用ApplicationContext来使用IOC容器,它们也是IOC容器展现给应用开发者的使用接口。对应用程序开发者来说,可以认为BeanFactory和ApplicationFactory在不同的使用层面上代表了SPRING提供的IOC容器服务。

     FileSystem

  ApplicationContext = new FileSystempublic FileSystemboolean refresh, ApplicationContext parent)      throws BeansException {    super(parent);    this.configLocations = configLocations;    if (refresh) {      //这里是IoC容器的初始化过程,其初始化过程的大致步骤由AbstractApplicationContext来定义      refresh();    }  }




     refresh的模板在AbstractApplicationContext:refresh的模板在AbstractApplicationContext:refresh的模板在AbstractApplicationContext:

  public void refresh() throws BeansException, IllegalStateException {    synchronized (this.startupShutdownMonitor) {      synchronized (this.activeMonitor) {        this.active = true;      }      // 这里需要子类来协助完成资源位置定义,bean载入和向IOC容器注册的过程      refreshBeanFactory();      ............   }




     这个方法包含了整个BeanFactory初始化的过程,对于特定的FileSystem

在Abstract

  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {    // 这里使用    new //这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的    ///因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给    beanDefinitionReader.setResourceLoader(this);    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));    initBeanDefinitionReader(beanDefinitionReader);    //这里转到定义好的    loadBeanDefinitions(beanDefinitionReader);  




     转到beanDefinitionReader中进行处理:

  protected void loadBeanDefinitions(throws BeansException, IOException {    Resource[] configResources = getConfigResources();    if (configResources != null) {      //调用      reader.loadBeanDefinitions(configResources);    }    String[] configLocations = getConfigLocations();    if (configLocations != null) {      reader.loadBeanDefinitions(configLocations);    }  }

     转到beanDefinitionReader中进行处理:

  protected void loadBeanDefinitions(throws BeansException, IOException {    Resource[] configResources = getConfigResources();    if (configResources != null) {      //调用      reader.loadBeanDefinitions(configResources);    }    String[] configLocations = getConfigLocations();    if (configLocations != null) {      reader.loadBeanDefinitions(configLocations);    }  }




     而在作为其抽象父类的AbstractBeanDefinitionReader中来定义载入过程:

  public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {   //这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader   ResourceLoader resourceLoader = getResourceLoader();   .........//如果没有找到我们需要的ResourceLoader,直接抛出异常    if (resourceLoader instanceof ResourcePatternResolver) {      // 这里处理我们在定义位置时使用的各种pattern,需要ResourcePatternResolver来完成      try {        Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);        int loadCount = loadBeanDefinitions(resources);        return loadCount;      }     ........    }    else {      // 这里通过ResourceLoader来完成位置定位      Resource resource = resourceLoader.getResource(location);      // 这里已经把一个位置定义转化为Resource接口,可以供      int loadCount = loadBeanDefinitions(resource);      return loadCount;    }  }





     当我们通过ResourceLoader来载入资源,别忘了了我们的GenericApplicationContext也实现了ResourceLoader接口:

  public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {    public Resource getResource(String location) {      //这里调用当前的loader也就是DefaultResourceLoader来完成载入      if (this.resourceLoader != null) {        return this.resourceLoader.getResource(location);      }      return super.getResource(location);    }  .......  }

     而我们的FileSystem

  public Resource getResource(String location) {    //如果是类路径的方式,那需要使用ClassPathResource来得到bean文件的资源对象    if (location.startsWith(CLASSPATH_URL_PREFIX)) {      return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());    }    else {      try {        // 如果是URL方式,使用UrlResource作为bean文件的资源对象        URL url = new URL(location);        return new UrlResource(url);      }      catch (MalformedURLException ex) {        // 如果都不是,那我们只能委托给子类由子类来决定使用什么样的资源对象了        return getResourceByPath(location);      }    }  }

     我们的FileSystem

 protected Resource getResourceByPath(String path) {    if (path != null && path.startsWith("/")) {      path = path.substring(1);    }    //这里使用文件系统资源对象来定义bean文件    return new FileSystemResource(path);  } 

     这样代码就回到了FileSystem

  public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    .......    try {      //这里通过Resource得到InputStream的IO流      InputStream inputStream = encodedResource.getResource().getInputStream();      try {        //从InputStream中得到        InputSource inputSource = new InputSource(inputStream);        if (encodedResource.getEncoding() != null) {          inputSource.setEncoding(encodedResource.getEncoding());        }        //这里是具体的解析和注册过程        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());      }      finally {        //关闭从Resource中得到的IO流        inputStream.close();      }    }      .........  }  protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)      throws BeanDefinitionStoreException {    try {      int validationMode = getValidationModeForResource(resource);      //通过解析得到DOM,然后完成bean在IOC容器中的注册      Document doc = this.documentLoader.loadDocument(          inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);      return registerBeanDefinitions(doc, resource);    }  .......  }

 

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {    if (delegate.isDefaultNamespace(root)) {      NodeList nl = root.getChildNodes();      for (int i = 0; i < nl.getLength(); i++) {        Node node = nl.item(i);        if (node instanceof Element) {          Element ele = (Element) node;          if (delegate.isDefaultNamespace(ele)) {            parseDefaultElement(ele, delegate);          }          else {            delegate.parseCustomElement(ele);          }        }      }    }    else {      delegate.parseCustomElement(root);    }  }