六、spring原理(2)IOC原理

本文深入探讨Spring框架的核心组件,包括IOC容器的实现原理,不同作用域的Bean管理,以及依赖注入的多种方式。同时,详细介绍了Bean的生命周期,帮助读者全面理解Spring的工作机制。

一、Spring IOC

Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。 

Spring 启动时读取应用程序提供的 Bean配置信息,并在Spring容器中生成一份相应的 Bean配置注册表,然后根据这张注册表实例化 Bean,装配好 Bean 之间的依赖关系,为上层应用提供准备就绪的运行环境。其中Bean缓存池为HashMap实现 

    

 二、Spring IOC容器实现

1.BeanFactory(框架的基础设施)

BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层 的 BeanFactory。 

①BeanDefinitionRegistry注册表

Spring 配置文件中每一个节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示, 它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册 BeanDefinition 对象的方法。 

②BeanFactory 顶层接口

位于类结构树的顶端 ,它最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的 Bean,BeanFactory 的功能通过其他的接口得到不断扩展

③ListableBeanFactory

该接口定义了访问容器中 Bean 基本信息的若干方法,如查看 Bean 的个数、获取某一类型 Bean 的配置名、查看容器中是否包括某一 Bean 等方法

④HierarchicalBeanFactory父子级联

IoC 容器的接口,子容器可以通过接口方法访问父容器

通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可以引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean

⑤ConfigurableBeanFactory

是一个重要的接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法

⑥AutowireCapableBeanFactory自动装配

定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法

⑦SingletonBeanRegistry 运行期间注册单例 Bean

定义了允许在运行期间向容器注册单实例 Bean 的方法;对于单实例( singleton)的 Bean 来说,BeanFactory会缓存 Bean 实例,所以第二次使用 getBean() 获取 Bean 时将直接从 IoC 容器的缓存中获取 Bean 实例。

Spring 在 DefaultSingletonBeanRegistry 类中提供了一 个用于缓存单实例 Bean 的缓存器,它是一个用HashMap 实现的缓存器,单实例的 Bean 以 beanName 为键保存在这个HashMap 中。 

⑧依赖日志框架

在初始化 BeanFactory 时,必须为其提供一种日志框架,比如使用Log4J, 即在类路径下提供 Log4J 配置文件,这样启动 Spring 容器才不会报错。 

2.ApplicationContext (面向开发应用)

ApplicationContext 由 BeanFactory 派生而来,提供了更多面向实际应用的功能。 ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基础上,还通过多个其他的接口扩展了 BeanFactory 的功能

①ClassPathXmlApplicationContext:

默认从类路径加载配置文件 

②FileSystemXmlApplicationContext:

默认从文件系统中装载配置文件 

③ApplicationEventPublisher:

让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。 

④MessageSource:

为应用提供 i18n 国际化消息访问的功能

⑤ResourcePatternResolver :

所有 ApplicationContext 实现类都实现了类似于 PathMatchingResourcePatternResolver 的功能,可以通过带前缀的 Ant 风格的资源文件路径装载 Spring 的配置文件。 

⑥LifeCycle:

该接口是 Spring 2.0 加入的,该接口提供了 start()和 stop()两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被 ApplicationContext 实现及具体Bean 实现, ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean,以达到管理和控制 JMX、任务调度等目的

⑦ConfigurableApplicationContext

扩展于 ApplicationContext,它新增加了两个主要的方法: refresh()和 close(),让 ApplicationContext 具有启动、刷新和关闭应用上下 文的能力。在应用上下文关闭的情况下调用 refresh()即可启动应用上下文,在已经启动 的状态下,调用 refresh()则清除缓存并重新装载配置信息,而调用 close()则可关闭应用上下文。

3.WebApplication 体系架构 

WebApplicationContext 是专门为 Web 应用准备的,它允许从相对于 Web 根目录的路径中装载配置文件完成初始化工作。从 WebApplicationContext 中可以获得 ServletContext 的引用,整个 Web 应用上下文对象将作为属性放置到 ServletContext 中,以便 Web 应用环境可以访问 Spring 应用上下文。 

三、Spring Bean

1. Spring Bean作用域

Spring 3 中为 Bean 定义了 5 中作用域,分别为 singleton(单例)、prototype(原型)、 request、session和global session

①singleton :单例模式 (多线程下不安全)

singleton:单例模式,Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个 Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的。Singleton 作用域是 Spring中的缺省作用域,也可以显示的将Bean定义为singleton模式,

配置为: <bean id="userDao" class="com.ioc.UserDaoImpl" scope="singleton"/> 

②prototype: 原型模式 每次使用时创建

prototype:原型模式,每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建 一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton 作用域。 

配置为:<bean id="userDao" class="com.ioc.UserDaoImpl" scope="prototype"/> 

③Request :一次 request一个实例

request:在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的Bean,而且该bean仅在当前Http Request内有效,当前Http请求结束,该bean 实例也将会被销毁。 

配置为:<bean id="loginAction" class="com.cnblogs.Login" scope="request"/> 

④session 

session:在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请 求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次 session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session 请求 内有效,请求结束,则实例将被销毁。 

配置为:<bean id="userPreference" class="com.ioc.UserPreference" scope="session"/> 

⑤global Session 

global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在 使用portlet context时有效。 

2.Spring Bean 生命周期 

①实例化

实例化一个Bean,也就是我们常说的new。 

②IOC 依赖注入 

按照Spring上下文对实例化的Bean进行配置,也就是IOC注入。 

③setBeanName 实现

如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String) 方法,此处传递的就是Spring配置文件中Bean的id 值 

④BeanFactoryAware 实现

如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory, setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean, 只需在Spring配置文件中配置一个普通的Bean就可以)。 

⑤ApplicationContextAware 实现

如果这个Bean已经实现了ApplicationContextAware接口,会调用 setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也 可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法)

⑥postProcessBeforeInitialization 接口实现 初始化预处理

如果这个Bean关联了BeanPostProcessor接口,将会调用 postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术。 

⑦init-method 

如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。 

⑧postProcessAfterInitialization

如果这个Bean关联了BeanPostProcessor接口,将会调用 postProcessAfterInitialization(Object obj, String s)方法。 注:以上工作完成以后就可以应用这个 Bean 了,那这个 Bean 是一个 Singleton 的,所以一 般情况下我们调用同一个 id 的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton。 

⑨Destroy 过期自动 清理阶段

当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用那个其实现的destroy()方法

⑩destroy-method 自配置清理

最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。 

注:

bean 标签有两个重要的属性(init-method 和 destroy-method)。用它们你可以自己定制 初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。 
<bean id="" class="" init-method="初始化方法"  destroy-method="销毁方法"> 

四、

1.Spring 依赖注入四种方式 

①构造器注入

 /*带参数,方便利用构造器进行注入*/       
public CatDaoImpl(String message){         
  this. message = message;       
}  
<bean id="CatDaoImpl" class="com.CatDaoImpl"> 
  <constructor-arg value=" message "></constructor-arg>   
</bean> 

②setter方法注入

 public class Id {     
  private int id;     
  public int getId() {
    return id;  
  }     
  public void setId(int id) {
     this.id = id;
   }  
 }   
<bean id="id" class="com.id ">
  <property name="id" value="123"></property>  
</bean> 

③静态工厂注入

静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让 spring 管理所有对象,我们不能直接通过"工厂类.静态方法()"来获取对象,而是依然通过 spring 注入的形式获取: 

public class DaoFactory {   //静态工厂     
  public static final FactoryDao getStaticFactoryDaoImpl(){       
    return new StaticFacotryDaoImpl();     
  }   
}    
public class SpringAction {           
  private FactoryDao staticFactoryDao;  //注入对象   
  //注入对象的 set 方法     
  public void setStaticFactoryDao(FactoryDao staticFactoryDao) {           
    this.staticFactoryDao = staticFactoryDao;     
  }   
}   

//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法     
<bean name="springAction" class=" SpringAction" >         
  <!--使用静态工厂的方法注入对象,对应下面的配置文件-->         
  <property name="staticFactoryDao" ref="staticFactoryDao"></property>              
</bean>       
<!--此处获取对象的方式是从工厂类中获取静态方法-->   
<bean name="staticFactoryDao" class="DaoFactory"  
factory-method="getStaticFactoryDaoImpl"></bean> 
 

④实例工厂

实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先 new 工厂类,再调用普通的实例方法: 

public class DaoFactory {   //实例工厂    
   public FactoryDao getFactoryDaoImpl(){   
      return new FactoryDaoImpl();  
  }   
}  
public class SpringAction {   
   private FactoryDao factoryDao;      //注入对象    
   public void setFactoryDao(FactoryDao factoryDao) {   
      this.factoryDao = factoryDao;   
    }   
}   

<bean name="springAction" class="SpringAction">   
    <!--使用实例工厂的方法注入对象,对应下面的配置文件-->   
    <property name="factoryDao" ref="factoryDao"></property>   
</bean>   
<!--此处获取对象的方式是从工厂类中获取实例方法-->   
<bean name="daoFactory" class="com.DaoFactory"></bean>   
<bean name="factoryDao" factory-bean="daoFactory" 
 factory-method="getFactoryDaoImpl"></bean>

2. 5 种不同方式的自动装配 

Spring装配包括手动装配和自动装配,手动装配是有基于 xml装配、构造方法、setter方法等

自动装配有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入

①no:

默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。 

②byName:

通过参数名自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。 

③byType:

通过参数类型自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被 设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。 

④constructor:

这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。 

⑤autodetect:

首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值