02_Spring IOC(控制反转)

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
    
    
        
    
    
    • 编写测试方法
    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
    
    
        
    
    
    • 编写测试方法
    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
    
    
        
        
    
    
    • 编写测试方法
    public void test3() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld3");
        helloWorld.show();
    }
    

Bean的别名

  1. 编写配置文件


    
    
    
    

  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. scope="prototype" lazy-init="true" 在 context.getBean 时创建对象
  2. scope="prototype" lazy-init="false" 在 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
    
    
        
        
            
        
        
        
    
    
    
    • 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步的初始化和销毁操作无耦合,只需要在配置文件制定初始化和销毁的方法。
    
        
    
    
  4. Bean的生命周期的总结
    • 增强 Bean 的功能,可以实现 BeanPostProcessor 来完成。
    • 初始化和销毁操作,可以使用 bean 标签上的 init-method、destroy-method 方法来完成。
    • 注意:destroy-method 只在 scope="singleton" 才有效果。

你可能感兴趣的:(02_Spring IOC(控制反转))