Spring学习笔记(三):Spring IOC原理及使用

Spring学习笔记(三):Spring IOC原理及使用

一、Bean的初始化
1.1 概述
  • Spring 容器是实例化和管理全部bean 的工厂,Spring 默认将所有的bean 设置成单态模式,无须自己完成单态模式,即对所有相同id 的bean 请求都将返回同一个共享实例。因此,单态模式可大大降低Java 对象在创建和销毁时的系统开销。
  • 功能
  • 标识一个应用环境
  • 利用 BeanFactory 创建 Bean 对象
  • 保存对象关系表
  • 够捕获各种事件
1.2 设计思想
  • 静态工厂方法模式
  • 它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。
//实例化Spring容器
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
//定义Person接口实例
Person p = null;
//通过Spring上下文获得Chinese实例
p = (Person)ctx.getBean("chinese")
  • 单例模式
  • BeanFactory 提供默认单例模式的Bean,模型提供了具有特定名称的对象的共享实例,可以在查询时对其进行检索。Singleton 是默认的也是最常用的对象模型。对于无状态服务对象很理想。
1.3 容器初始化
  • ContextLoader是Spring核心的上下文加载类,ContextLoaderListener通过实现
  • ServletContextListener的contextInitialized方法调用ContextLoader的
    initWebApplicationContext方法实现容器加载
  • initWebApplicationContext
  • 创建WebApplicationContext
  • 加载对应的Spring文件创建里面的Bean实例
  • 将WebApplicationContext放入ServletContext(就是Java Web的全局变量)中
    • configureAndRefreshWebApplicationContext
    • 将WebApplicationContext设置到ServletContext上下文
    • 调用refresh核心方法加载spring容器
二、Bean的生命周期

流程图

  • 若容器实现了流程图中涉及的接口,程序将按照以上流程进行。需要我们注意的是,这些接口并不是必须实现的,可根据自己开发中的需要灵活地进行选择,没有实现相关接口时,将略去流程图中的相关步骤。
分类类型包含方法
Bean自身的方法配置文件中的init-method和destroy-method配置的方法、Bean对象自己调用的方法
Bean级生命周期接口方法BeanNameAware、BeanFactoryAware、InitializingBeanDiposableBean等接口中的方法
容器级生命周期接口方法后置处理器BeanPostProcessor实现类中重写的方法
2.1 Bean的初始化
  • Bean组件在Spring的org.springframework.beans包下。这个包下的所有类主要解决了三件事:Bean的定义、Bean的创建以及对Bean的解析。对Spring的使用者来说唯一需要关心的就是Bean的创建,其他两个由Spring在内部帮你完成了,对你来说是透明的。
  • 当Spring成功解析你定义的一个节点后,在Spring的内部就被转化成BeanDefinition对象。以后所有的操作都是对这个对象完成的。
  • Bean的解析主要就是对Spring配置文件的解析。
2.2 初始化Bean容器
  • 由以上分析可知,初始化Bean容器的关键方法为用ContextLoader的initWebApplicationContext方法,而过程的核心子方法为configureAndRefreshWebApplicationContext方法中调用的refresh方法,该方法的代码如下:

public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
 //1、创建beanFactory工厂
// 准备上下文进行刷新
  this.prepareRefresh();
  // 告诉子类刷新内部beanFactory  创建beanFactory
  ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
  // 配置beanFactory,添加spring本身的工具类
  this.prepareBeanFactory(beanFactory);
  try {
    //2、Spring 功能扩展 
       //2.1允许在上下文子类中对beanFactory进行配置修改                  
       this.postProcessBeanFactory(beanFactory);
       //调用在上下文中注册为bean的beanFactory
       //获取实现BeanFactoryPostProcessor接口的子类。并执行它postProcessBeanFactory 方法
       this.invokeBeanFactoryPostProcessors(beanFactory);
        //2.2创建bean时的自定义操作
      //获取用户定义的实现了 BeanPostProcessor 接口的子类,并执行把它们注册到 BeanFactory 对象中的 beanPostProcessors 变量中。 (可添加用户自定义操作)
        this.registerBeanPostProcessors(beanFactory);
        //3、初始化监听事件和对系统的其他监听者的注册
        this.initMessageSource();
        this.initApplicationEventMulticaster();
        this.onRefresh();
        this.registerListeners();
        //4、实例化所有非惰性初始的bean 
        this.finishBeanFactoryInitialization(beanFactory);
        5、发布被监听的事件
        this.finishRefresh();
    } catch (BeansException var9) {
        if (this.logger.isWarnEnabled()) {
             this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
        }  
        this.destroyBeans();
        this.cancelRefresh(var9);
        throw var9;
    } finally {
        this.resetCommonCaches();
} 
  • 由refresh方法可知,该过程主要分为5步:
    • (1) 构建 BeanFactory
    • (2) Spring 功能扩展,完成容器和Bean实例化前后的自定义操作
    • (3) 注册监听事件
    • (4) 创建 Bean 实例对象
    • (5) 触发被监听的事件
2.3 创建Bean实例
  • 以上初始化容器的过程的finishBeanFactoryInitialization方法主要有两个作用,分别是创建Bean的实例并构建Bean之间的依赖关系,该过程如下:

protected void finishBeanFactoryInitialization(
  ConfigurableListableBeanFactory beanFactory) { 
   .......
  // 停止使用临时的类加载器进行类型匹配
  beanFactory.setTempClassLoader(null); 
  // 允许缓存所有bean定义的元数据,不允许进一步的变化
  beanFactory.freezeConfiguration(); 
  // 实例化除了延迟初始化的所有bean单例
  beanFactory.preInstantiateSingletons(); 
}
  • finishBeanFactoryInitialization方法中,创建Bean实例方法preInstantiateSingletons,该方法的大体流程如下:
    1. 循环获取beanDefinitionNames的beanName
    2. 根据beanName拿到RootBeanDefinition
    3. 对于非抽象的,单例的,非懒加载的bean实例化
      • 判断Bean是否FactoryBean的实现
      • 若是且为SmartFactoryBean并且eagerInit,则直接调用getBean实例化Bean
      • 若为普通bean则直接调用getBean实例化
  • getBean方法最终调用AbstractAutowireCapableBeanFactory.doCreateBean方法,该方法流程如下:
    1. 调用createBeanInstance方法,创建bean实例对象(执行bean的构造方法)
    2. 调用instantiateBean,最终会走到BeanUtils.instantiateClass
    3. 调用populateBean方法,对bean进行填充,注入相关依赖,
    4. 调用方法initializeBean,进行相关初始化工作:
      • 调用applyBeanPostProcessorsBeforeInitialization方法,执行每个BeanPostProcessor的postProcessBeforeInitialization
      • 调用invokeInitMethods方法,执行bean的初始化方法
      • 调用applyBeanPostProcessorsAfterInitialization方法,执行每个BeanPostProcessor的postProcessAfterInitialization方法。

三 使用

3.1 自动化装配
     
public interface Login {
    void login();
}
@Component
public class UserLogin implements Login {
    public void login() {
        System.out.println("login success!");
}

//隐式的Bean发现机制和自动注解
@Component
public class LoginController {
    @Autowired //在属性上添加注解
    @Resource //在属性上添加注解
    private Login login;
    public Login getLogin() {
        return login;
    }
    /**
     * 常用的注解有两种:@Autowired,@Resource
     * @autowired 是通过类的类型装配Bean
     * @Resource 是通过类的名称装配bean,名称默认为字段名称或setter方法
     */
    @Autowired  //按照类型装配,可以在构造方法中添加该注解
    @Resource("userLogin") //注入名称为"userLogin"的Bean
    public LoginController(Login login) {
        this.login = login;
    }
    @Autowired  //在setter方法上添加该注解
    @Resource("userLogin") //注入名称为"userLogin"的Bean
    public void setLogin(Login login) {
        this.login = login;
    }
    public void login() {
        login.login();
    }
}

@Configuration
@ComponentScan
(basePackages{"com.ls.loginModel"})
//扫描bean所在的包,可以配置多个包参数
public class LoginConfig {} //自动化配置类
  • 该流程为:
    1. 带有@Component注解的接口实现类
    2. 可在@Component注解类中添加@autowired注解实现自动装配(属性,构造方法,方法)
    3. @Component注解/ XML配置 启动组件扫描,可配置扫描基础包
3.2 Java代码装配

//Java显示配置
@Configuration
@ComponentScan
(basePackages{"com.ls.loginModel"})
//扫描bean所在的包,可以配置多个包参数
public class LoginConfig {
	//Java方式配置类
    @Bean
    public Login userLogin() {
        return new UserLogin();
    }
    @Bean
    public LoginController loginController(Login login) {
        LoginController controller = new LoginController();
        controller.setLogin(login);
        return controller;
    }
 }
 
3.3 XML装配
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 自动扫描包(自动注入) -->
    <context:component-scan base-package="com.ls.springModel" />
</beans>
//XML方式装配bean
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">
<class="com.ls.springModel.UserLogin"/>
    <bean id="loginController" class="com.ls.springModel.Logintroller">
        <constructor-arg ref="login"></constructor-arg> <!--构造注入 对应构造函数 -->
        <property name="login" ref="login"></property><!--属性注入 对应setter方法  -->
        </bean>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值