美文网首页Spring框架学习笔记
02_Spring IOC(控制反转)

02_Spring IOC(控制反转)

作者: 小窗风雨 | 来源:发表于2018-01-20 12:26 被阅读0次

    IOC的概念

    • IOC Inversion of Controller 控制反转。
    • IOC 就是将对象的创建、初始化及销毁交给 spring 容器来处理。

    ApplicationContext 与 BeanFactory 的关系

    1. ApplicationContext 是 BeanFactory 的子接口。
    2. BeanFactory 采用延迟加载的方案,在getBean时才会实例化Bean。
      • XmlBeanFactory
      public void test4() {
          BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
          beanFactory.getBean("helloWorld");
      }
      // 经过测试,BeanFactory在getBean时才实例化Bean。
      
    3. ApplicationContext 在配置文件加载时,就会初始化Bean,并且提供不同应用层的实现。在开发中我们一般使用 ApplicationContext 的实现类:
      • FileSystemXmlApplicationContext 根据文件路径读取xml文件
      public void test5() {
          // 根据系统文件路径读取xml文件
          ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml");
          context.getBean("helloWorld");
      }
      
      • ClassPathXmlApplicationContext 根据classpath路径读取xml文件
      public void test5() {
          // 根据classpath路径读取xml文件
          ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
          context.getBean("helloWorld");
      }
      
      • WebApplicationContext web开发中常用

    Bean的实例化方式

    1. 无参构造方法
      • 编写配置文件 applicationContext.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"
          xsi:schemaLocation="
              http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
      </beans>
      
      • 编写测试方法
      public void test1() {
          ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
          helloWorld.show();
      }
      
    2. 静态工厂方法
      • 编写工厂类,在工厂类中提供一个静态方法,返回Bean对象
      public class HelloWorldFactory {
          public static HelloWorld getInstance() {
              return new HelloWorld();
          }
      }
      
      • 编写配置文件 applicationContext.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"
          xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="helloWorld2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory" factory-method="getInstance"/>
      </beans>
      
      • 编写测试方法
      public void test2() {
          ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld2");
          helloWorld.show();
      }
      
    3. 实例工厂方法
      • 编写工厂类,在工厂类中提供一个非静态方法,返回Bean对象
      public class HelloWorldFactory2 {
          public HelloWorld getInstance() {
              return new HelloWorld();
          }
      }
      
      • 编写配置文件 applicationContext.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"
          xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="helloWorldFactory2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory2"/>
          <bean id="helloWorld3" factory-bean="helloWorldFactory2" factory-method="getInstance"/>
      </beans>
      
      • 编写测试方法
      public void test3() {
          ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld3");
          helloWorld.show();
      }
      

    Bean的别名

    1. 编写配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
        <alias name="helloWorld" alias="a"/>
        <alias name="helloWorld" alias="b"/>
        <alias name="helloWorld" alias="c"/>
    </beans>
    
    1. 编写测试方法
    public void testAlias() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld a = (HelloWorld) context.getBean("a");
        a.show();
        HelloWorld b = (HelloWorld) context.getBean("b");
        b.show();
        HelloWorld c = (HelloWorld) context.getBean("c");
        c.show();
    }
    

    Bean的创建时机

    1. 在 bean 标签中有 lazy-init 属性
      • default,相当于 false,在 spring 容器启动的时候创建对象。
      • true,在 context.getBean 时创建对象。
      • false,在 spring 容器启动的时候创建对象。
    2. lazy-init 属性的意义
      • 如果把 lazy-init 设置为 true ,则当 spring 容器启动的时候,检测不到任何错误,这样会存在很大的安全性隐患。所以一般情况应该设置 lazy-init 为 false/default 。
      • 但是如果一个bean中有一个属性,该属性含有大量的数据,这个时候不希望该bean过早的停留在内存中,这个时候需要用到 lazy-int 为 true 。

    Bean的作用域

    1. 在 bean 标签中有 scope 属性,用于描述 bean 的作用域。
      • singleton,单例模式,代表在 spring ioc 容器中只有一个 bean 实例。(默认的scope)
      • prototype,多例模式,每一次从 spring ioc 容器中获取,都会返回一个新实例。
      • request,用在web开发中,通过 request.setAttribute() 将 bean 对象存储到request域中。
      • session,用在web开发中,通过 session.setAttribute() 将 Bean 对象存储到session域中。
    2. 默认情况下,放入spring容器中的bean是单例的。
      • 将来service层和dao层所有的类将放入到spring容器中,所以默认情况下这两个层的类的实例都是单例的,所以不能把数据声明到属性中。如果声明到属性中,将会成为共享的,涉及到线程安全问题。

    创建时机和作用域的结合

    1. <font color="red">scope="prototype" lazy-init="true"</font> 在 context.getBean 时创建对象
    2. <font color="red">scope="prototype" lazy-init="false"</font> 在 context.getBean 时创建对象,lazy-init为false失效。即在 scope 为 prototype 时,始终在 context.getBean 时创建对象
    3. scope为singleton时,是默认情况。

    Bean的生命周期

    1. Bean的生命周期方法
      • instantiate bean 实例化 Bean 对象
      • populate properties 给 Bean 对象注入属性
      • 如果 Bean 实现 BeanNameAware 执行 setBeanName
      • 如果 Bean 实现 BeanFactoryAware 或 ApplicationContextAware 执行 setBeanFactory 或 setApplicationContext
      • 如果存在类实现 BeanPostProcessor 执行postProcessBeforeInitialization
      • 如果 Bean 实现 InitializingBean 执行 afterPropertiesSet
      • 调用 Bean 中自定义的 init-method 方法
      • 如果存在类实现 BeanPostProcessor 执行postProcessorAfterInitialization
      • 执行业务逻辑代码
      • 如果 Bean 实现 DisposableBean 执行 destroy
      • 调用 Bean 中自定义的 destroy-method 方法
    2. Bean的生命周期测试代码
      • HelloWorld.java
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.BeanNameAware;
      import org.springframework.beans.factory.DisposableBean;
      import org.springframework.beans.factory.InitializingBean;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.ApplicationContextAware;
      
      public class HelloWorld implements BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean {
      
          private String info;
      
          public String getInfo() {
              return info;
          }
      
          public void setInfo(String info) {
              this.info = info;
          }
      
          public HelloWorld() {
              System.out.println("第一步:instantiate bean 实例化Bean对象");
          }
      
          public void show() {
              System.out.println("第九步:show time 执行业务逻辑代码");
          }
      
          public void myInit() {
              System.out.println("第七步:调用 Bean 中自定义的 init-method 方法");
          }
      
          public void myDestroy() {
              System.out.println("第十一步:调用 Bean 中自定义的 destroy-method 方法");
          }
      
          @Override
          public void setBeanName(String arg0) {
              System.out.println("第三步:如果 Bean 实现 BeanNameAware 执行 setBeanName" + info);
          }
      
          @Override
          public void setApplicationContext(ApplicationContext arg0) throws BeansException {
              System.out.println("第四步:如果 Bean 实现 BeanFactoryAware 或 ApplicationContextAware 执行 setBeanFactory 或 setApplicationContext");
          }
      
          @Override
          public void afterPropertiesSet() throws Exception {
              System.out.println("第六步:如果 Bean 实现 InitializingBean 执行 afterPropertiesSet");
          }
      
          @Override
          public void destroy() throws Exception {
              System.out.println("第十步:如果 Bean 实现 DisposableBean 执行 destroy");
          }
      
      }
      
      • MyProcessor.java
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanPostProcessor;
      
      public class MyProcessor implements BeanPostProcessor{
      
          @Override
          public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
              System.out.println("第八步:如果存在类实现 BeanPostProcessor 执行postProcessorAfterInitialization");
              return arg0;
          }
      
          @Override
          public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
              System.out.println("第五步:如果存在类实现 BeanPostProcessor 执行postProcessBeforeInitialization");
              return arg0;
          }
      
      }
      
      • applicationContext.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"
          xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          
          <bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy">
              <property name="info" value="你好啊"></property>
          </bean>
          <!-- 此类是针对所有其他bean类的 -->
          <bean id="myProcessor" class="com.zhangquanli.spring.life.MyProcessor"/>
      
      </beans>
      
      • HelloWorldTest
      import org.junit.Test;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class HelloWorldTest {
          @Test
          public void test1() {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
              HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
              helloWorld.show();
              context.close();
          }
      }
      
    3. Bean的生命周期的说明
      • 第3步和第4步,是让 Bean 了解 spring 容器。
      • 第5步和第8步,可以针对指定 的Bean 使用动态代理进行功能增强。
      • 第6步和第10步,可以实现指定的接口来完成 init 和 destroy 操作。
      • 在开发中,一般不使用第6步和第10步,因为第7步和第11步也可以完成 init 和 destroy 的操作。同时,第7步和第11步的初始化和销毁操作无耦合,只需要在配置文件制定初始化和销毁的方法。
      <bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy">
          <property name="info" value="你好啊"></property>
      </bean>
      
    4. Bean的生命周期的总结
      • 增强 Bean 的功能,可以实现 BeanPostProcessor 来完成。
      • 初始化和销毁操作,可以使用 bean 标签上的 init-method、destroy-method 方法来完成。
      • <font color="red">注意:destroy-method 只在 scope="singleton" 才有效果。</font>

    相关文章

      网友评论

        本文标题:02_Spring IOC(控制反转)

        本文链接:https://www.haomeiwen.com/subject/efftaxtx.html