Spring Ioc容器

作者: LU7IN | 来源:发表于2018-04-08 12:28 被阅读0次

    什么是Ioc?

    控制反转((Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称DI和依赖查找(Dependency Lookup)。

    说得简单一点就是我们在写Java代码的时候我们的对象不需要自己来创建,而是通过容器来帮助我们生成。用我们生活中的例子来说,打个比方,我们想要一辆汽车,我们不可能去自己造一辆汽车,而是去买一辆。

    所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

    Ioc容器的初始化

    image.png
    IoC容器初始化过程主要经过以下几个阶段:
    1.解析阶段:Spring会解析Bean的XML配置文件,将XML元素进行抽象,抽象成Resource对象。
    2.转换阶段:通过Resource对象将配置文件进行抽象后转换成Spring能够理解的BeanDefinition结构。
    3.注册阶段:Spring IoC容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory。
    DefaultListableBeanFactory间接实现了BeanFactory接口,是整个bean加载的核心部分,是Spring注册及加载bean的默认实现,我们可以理解为Spring bean工厂的发动机。

    Spring Bean 定义

    被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的。

    属性 描述
    class 这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
    name 这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。
    scope 这个属性指定由特定的 bean 定义创建的对象的作用域,它将会在 bean 作用域的章节中进行讨论。
    lazy-initialization mode 延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
    initialization 在 bean 的所有必需的属性被容器设置之后,调用回调方法
    destruction 当包含该 bean 的容器被销毁时,使用回调方法

    Spring Bean作用域

    当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为singleton

    Spring框架支持以下五个作用域:

    作用域 描述
    singleton 该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。
    prototype 该作用域将单一 bean 的定义限制在任意数量的对象实例。
    request 该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。
    session 该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
    global-session 该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。

    看下面的例子:第一个是singleton,第二个是prototype

    Hello.java

    package com.tutorialspoint;
    
    public class Hello {
        private String message;
        public void setMessage(String message) {
            this.message = message;
        }
        public void getMessage() {
            System.out.println("Your message is:" + message);
        }
    }
    

    MainApp.java

    package com.tutorialspoint;
    import org.springframework.context.support.AbstractApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
    
        public static void main(String[] args) {
            AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            Hello object1 = (Hello) context.getBean("bean");
            object1.setMessage("这不大傻瓜吗");
            object1.getMessage();
            Hello object2 = (Hello) context.getBean("bean");
            object2.getMessage();
        }
    
    }
    

    Beans.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-3.0.xsd">
    
       <bean id="bean" class="com.tutorialspoint.Hello" scope="singleton">
       </bean>
    </beans>
    

    输出的结果为如图:

    image.png

    Beans.xml中的scope="singleton"改为scope="prototype"后,其余代码不变,输出结果可以猜到了,第二个Bean将不会得到实例化,因此输出的值为空即null

    结果正确:

    image.png

    Spring Bean的生命周期

    Spring的生命周期跟Servlet的生命周期像,都有初始化跟销毁的方法,参数分别为:init-mehtoddestroy-methodinit-method属性指定一个方法,在实例化 bean 时,立即调用该方法。同样,destroy-method指定一个方法,只有从容器中移除 bean 之后,才能调用该方法。

    Hello.java

    package com.tutorialspoint;
    
    public class Hello {
        private String message;
        public void setMessage(String message) {
            this.message = message;
        }
        public void getMessage() {
            System.out.println("Your message is:" + message);
        }
        public void init() {
            System.out.println("bean正在被初始化");
        }
        public void destroy() {
            System.out.println("bean正在被销毁");
        }
    }
    

    MainApp.java

    package com.tutorialspoint;
    import org.springframework.context.support.AbstractApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
    
        public static void main(String[] args) {
            AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            Hello object1 = (Hello) context.getBean("bean");
            object1.setMessage("这不大傻瓜吗");
            object1.getMessage();
            //在非web应用中关闭Ioc容器
            context.registerShutdownHook();
        }
    
    }
    

    Beans.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-3.0.xsd">
    
       <bean id="bean" class="com.tutorialspoint.Hello" init-method="init" destroy-method="destroy">
       </bean>
    </beans>
    
    image.png

    这是关于registryShutdownHook()的详细解释。

    Spring Bean定义继承

    bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。子 bean 的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。你可以定义一个父 bean 的定义作为模板和其他子 bean 就可以从父 bean 中继承所需的配置。当你使用基于 XML 的配置元数据时,通过使用父属性,指定父 bean 作为该属性的值来表明子 bean 的定义。

    看例子:

    Hello.java

    package com.tutorialspoint;
    
    public class Hello {
        private String message1;
        private String message2;
        public void setMessage1(String message) {
            this.message1 = message;
        }
        public void getMessage1() {
            System.out.println("Your message is:" + message1);
        }
        public void setMessage2(String message) {
            this.message2 = message;
        }
        public void getMessage2() {
            System.out.println("Your message is:" + message2);
        }
    }
    

    HelloWorld.java

    package com.tutorialspoint;
    
    public class HelloWorld {
        private String message1;
        private String message2;
        private String message3;
        public void setMessage1(String message){
              this.message1  = message;
           }
    
           public void setMessage2(String message){
              this.message2  = message;
           }
    
           public void setMessage3(String message){
              this.message3  = message;
           }
    
           public void getMessage1(){
              System.out.println("Your message is: " + message1);
           }
    
           public void getMessage2(){
              System.out.println("Your message is:" + message2);
           }
    
           public void getMessage3(){
              System.out.println("Your message is: " + message3);
           }
    }
    

    MainApp.java

    package com.tutorialspoint;
    import org.springframework.context.support.AbstractApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
    
        public static void main(String[] args) {
            AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            Hello obj1 = (Hello) context.getBean("hello");
            obj1.getMessage1();
            obj1.getMessage2();
            HelloWorld obj2 = (HelloWorld) context.getBean("helloworld");
            obj2.getMessage1();
            obj2.getMessage2();
            obj2.getMessage3();
        }
    }
    

    Beans.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-3.0.xsd">
    
       <bean id="hello" class="com.tutorialspoint.Hello">
            <property name="message1" value="message1" />
            <property name="message2" value="message2" />
       </bean>
       <bean id="helloworld" class="com.tutorialspoint.HelloWorld" parent="hello">
            <property name="message1" value="helloworld1" />
            <property name="message3" value="helloworld2"/>
       </bean>
    </beans>
    

    输出结果如下:

    image.png

    可以看出,我们在HelloWorld.java中并未定义有getMessage2()的方法,但是在主类中我们调用了该方法,因此Bean就继承了主类的该方法,所以子类调用的是父类的方法,输出跟父类的结果一致。

    相关文章

      网友评论

        本文标题:Spring Ioc容器

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