spring 控制反转怎么体现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring 控制反转怎么体现相关的知识,希望对你有一定的参考价值。

考虑一下我们之前在程序中如果需要一个对象会怎么办?一般是使用new关键字,然后后面接一个类,调用构造方法,这样jvm就会给我们生产一个对象。也就是说程序员需要对象的时候完全是自己new的,比如 Person person = new Person();

可是有了Spring之后,我们的对象完全交给Spring去管理类,我们直接在Spring的配置文件里配置好Bean,就可以放心大胆的不用管了.比如如下配置代码:

<bean id="person" class="com.wyq.Spring.Person">
<property name="age" value="12" />
<property name="name" value="Tom"/>

然后接下来,我们要使用这个Bean的时候该怎么办呢?只需要这样一个方法:

ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = ctx.getBean("person",Person.class);

如上图,这样的peron实例对象就由Spring管理的,关于它是生命周期,如何生产你完全不用管,用的时候直接调用Spring提供的方法就行。

这就是控制反转的体现,把对象实例化交给Spring去控制,程序员并不用管。

参考技术A 你要创建的对象它的关联对象被spring容器创建(控制权交给spring容器)

Spring 控制反转(IOC)

Spring 控制反转(IOC)

IOC概念

  • 控制反转,把对象创建和对象间的调用过程,交给Spring进行管理。
  • 使用IOC可以降低对象间的耦合度。
  • IOC底层原理:XML解析,工厂模式,反射。

上一篇博客已经详细讲解了ioc的概念和理解了。初识Spring

现在我们来讲讲 怎么使用 IOC。

一、Spring配置

详细在代码的注解里。

1、别名

<!--    别名(给id为user取别名),如果取了别名,我们也可以通过别名获取到这个对象-->
    <alias name="user" alias="aaaa"/>

2、bean的配置

Spring Ioc容器的核心就是要玩坏bean!

基本属性:

<!--    id: bean的唯一标识符
        class:对象所对应的全限定名:包名+类型
        name:也是别名,而且name可以起多个别名,也可以用逗号,空格,分号分隔-->
    <bean id="user1" class="mq.pojo.User" name="user2,user3 user4;">
        <constructor-arg name="name" value="maomao"/>
    </bean>

scope属性(重点是singleton和prototype):

一般情况下是使用singleton,但是要整合struts2时则要在ActionBean中使用prototype。而request和session属性基本上是用不到的。

singleton(默认值):单例模式,所谓单例对象,就是在spring容器中只会存在一个的实例

prototype属性:多例原型被标记为多例的对象,每次再获得才会创建并且每次创建都是新的对象

request: web环境下,对象与request生命周期一致,也就是每当请求处理完一次,对象将从spring容器中移除

session:web环境下,对象与session生命周期一致

在下一篇博客会详细讲这个属性。

3、import

一般用于团队开发使用,可以将多个配置文件,导入合并成一个

在这里插入图片描述

使用的时候使用总配置文件就行

二、Spring IOC容器

SpringIOC的核心为IOC容器,它主要有两种:
BeanFactory:IOC容器的基本实现,是Spring内部的使用接口,不提供开发人员使用。加载配置文件的时候不会去创建对象,在获取对象使用才去创建对象。

ApplictionContext:BeanFactory接口的子接口,提供更多更强大的功能,一般有开发人员使用,加载配置文件时候就会创建对象。

ApplicationContext的实现有四种方式:

FileSystemXmlApplicationContext:加载配置文件的时候采用的是项目的路径。

ClassPathXmlApplicationContext:加载配置文件的时候根据ClassPath位置。(重点

XmlWebApplicationContext:在Web环境下初始化监听器的时候会加载该类。

AnnotationConfigApplicationContext:根据注解的方式启动Spring 容器。(介绍

1、依赖注入(DI)

  • 依赖:bean对象的创建依赖于容器
  • 注入:bean对象中的所有属性,由容器来注入

环境搭建

  1. 导入Spring相关的jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>
  1. 编写实体类
public class Hello {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "name='" + name + '\\'' +
                '}';
    }
}

构造器注入

1.无参构造创建对象(默认)
  1. 编写beans.xml文件(重点),spring主要就在这个文件里进行一些列的操作
    有点类似Mybatis中的Mapper.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    使用spring创建对象,在spring中这些都称为Bean
        类型 变量名 = new 类型();
        Hello hello =new Hello();
        bean=对象  new Hello();
        id=变量名    class= new 的对象
        property 相当于给对象中的属性设置一个值
-->
    <bean id="hello" class="mq.pojo.Hello">
 <!--  value :具体的值,基本的数据类型
      ref : 引用spring容器中创建好的对象-->
        <property name="name" value="spring"/>
    </bean>
</beans>

测试类
这里使用ClassPathXmlApplicationContext 加载配置文件,也是最常用的方式。

public class MyTest {

    public static void main(String[] args) {
        //获取spring的上下文对象,拿到spring的容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在springspring中管理,我们要使用,直接取
        //getBean:参数就是spring配置文件中bean的id
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

结果:
在这里插入图片描述
name=spring,就是我在bean对象的时候给name属性的value值为spring

2.有参构造创建对象

我们需要在实体类中User中添加一个有参构造的方法

public class UserT {
   private String name;
   public UserT(String name) {
       this.name = name;
  }
   public void setName(String name) {
       this.name = name;
  }
   public void show(){
       System.out.println("name="+ name );
  }
}

编写xml配置文件
三种方式都行

  • 下标赋值

    <!--    第一种,下标赋值-->
        <bean id="user" class="mq.pojo.User">
            <constructor-arg index="0" value="maomao"/>
        </bean>
    
  • 通过类型来创建

    <!--第二种,通过类型创建,不建议使用-->
        <bean id="user" class="mq.pojo.User">
           <constructor-arg type="java.lang.String" value="maomao"/>
        </bean>
    
  • 通过参数名

<!--    第三种,通过参数名-->
    <bean id="user" class="mq.pojo.User">
        <constructor-arg name="name" value="maomao"/>
    </bean>

测试类:

    public static void main(String[] args) {
        //获取spring的上下文对象,拿到spring的容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在springspring中管理,我们要使用,直接取
        //getBean:参数就是spring配置文件中bean的id
        User user = (User) context.getBean("user");
        user.show();
    }

结果
在这里插入图片描述

在这里插入图片描述
小结:
在配置文件加载的时候,容器中管理的对象就已经被初始化了,也就是前面讲Spring配置的时候的单例模式,即对象就被创建了一个。

  • User的对象是由Spring创建的
  • User对象的属性是由bean的value设置

这个过程就是控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring IOC容器来创建和管理的.
反转:程序本身不创建对象,而变成被动的接收对象.

依赖注入:就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收.

我们彻底不用再程序中去改动代码了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loC就是:对象由Spring来创建,管理,装配!

Set方式注入(重点)

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 ,这个例子由几乎所有属性的注入方式,有String、map、list、set、Properties、String[]、实体类(Bean的注入)对象等,如果是刚开始学的,请耐心看完beans.xml里的配置

实体类:
Address 类

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\\'' +
                '}';
    }
}

Student 类

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\\'' +
                ", address=" + address.toString() +
                ", books=" + Arrays.toString(books) +'\\n'+
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\\n' +
                ", info=" + info +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String[] getBooks() {
        return books;
    }
    public void setBooks(String[] books) {
        this.books = books;
    }
    public List<String> getHobbys() {
        return hobbys;
    }
    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }
    public Map<String, String> getCard() {
        return card;
    }
    public void setCard(Map<String, String> card) {
        this.card = card;
    }
    public Set<String> getGames() {
        return games;
    }
    public void setGames(Set<String> games) {
        this.games = games;
    }
    public String getWife() {
        return wife;
    }
    public void setWife(String wife) {
        this.wife = wife;
    }
    public Properties getInfo() {
        return info;
    }
    public void setInfo(Properties info) {
        this.info = info;
    }
}

编写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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="address" class="com.mq.pojo.Address">
        <property name="address" value="长沙"/>
    </bean>

    <bean id="student" class="com.mq.pojo.Student">
<!--  第一种:普通值注入,value-->
        <property name="name" value="小毛"/>
<!--        第二种:Bean注入,ref-->
        <property name="address" ref="address"/>
<!--        数组注入-->
        <property name="books">
            <array>
                <value>java教程</value>
                <value>数据结构</value>
                <value>C语言</value>
                <value>go语言</value>
            </array>
        </property>
<!--        List注入-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>上网</value>
                <value>玩游戏</value>
                <value>打篮球</value>
            </list>
        </property>
<!--        Map注入-->
        <property name="card">
            <map>
                <entry key="银行卡" value="123456"/>
                <entry key="银行卡2" value="123456"/>
            </map>
        </property>
<!--        Set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>CF</value>
                <value>王者荣耀</value>
            </set>
        </property>
<!--        null值注入-->
        <property name="wife">
            <null></null>
        </property>
        <property name="info">
            <props>
                <prop key="学号">20</prop>
                <prop key="性别"></prop>
                <prop key="国籍">中国</prop>
            </props>
        </property>
    </bean>
</beans>

测试类

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }

结果:
在这里插入图片描述

拓展方式的注入

主要有p 命名空间的注入c命名空间注入

实体类

public class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '}';
    }
}
<!--    p 命名空间的注入,可以直接注入属性的值:property-->
    <bean id="user" spring依赖注入,和控制反转。用自己的话说是怎么说的。最好能够用代码来解释

Spring → 03:核心机制

不懂控制反转么?大白话讲清楚spring中这些晦涩的概念

控制反转的实现方式

Spring 控制反转(IOC)

深层理解Spring 控制反转和依赖注入,这一篇文够了