Spring(一)IOC初识

官网地址:https://spring.io/

我们进入官网后,点击如下所示。我们会发现许多框架:

其中,Spring Framework,为spring基础框架, 可以视为Spring基础设施,基本上任何其他Spring项目都是以Spring Framework为基础的。

Spring Framework五大功能模块:

功能模块 功能介绍
Core Container 核心容器,在spring环境下使用任何功能都必须基于IOC容器
AOP&Aspects 面向切面编程
Testing 提供了对junit或TestNG测试框架的整合
Data Access/Integration 提供了对数据访问/集成的功能
Spring MVC 提供了面向Web应用程序的集成功能

Spring Framework特性:

非侵入式

控制反转(IOC,翻转资源获取方向,把自己创建资源、向环境索取资源变成环境将资源准备好,我们享受资源注入。)

面向切面编程:AOP:在不修改源代码的基础上增强代码功能。

容器:Spring IOC是一个容器,因为它包含并且管理组建对象的生命周期。

组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在Spring中可以使用XML和Java注解组合这些对象,这使得我们可以基于一个个功能明确、边界清晰的组件有条不絮的搭建超大型复杂应用系统。

声明式:很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现

一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且Spring旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在Spring Framework的基础上全部使用Spring来实现。

IOC容器:

DI:依赖注入

DI是IOC的一种表述方式:即组件以一些预先定义好的方式(例如:setter方法)接受来自容器的资源注入,相对于IOC而言,这种表述更直接。

IOC就是一种反转控制的思想,而DI是对IOC的一种具体实现

IOC容器在Spring中的实现:

Spring提供了IOC容器的两种实现方式:

1、BeanFactory

这是IOC容器的基本实现,是Spring内部使用的接口,面向Spring本身,不提供给开发人员使用。

2.ApplicationContext

BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。

3.ApplicationContext的主要实现类

我们创建项目spring_helloworld.创建完成之后,我们进行配置依赖如下所示:

 <dependencies>
    <!--基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.1</version>
    </dependency>
<!--junit测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

之后我们双击两次shift键进入搜索界面,我们找到如下所示:

我们点击crtl+h,发现接口的方法如下所示:

我们了解如下所示:
 

类型名 简介
ClassPathXmlApplicationContext 通过读取类路径下的XML格式的配置文件创建IOC容器对象
FileSystemXmlApplicationContext 通过文件系统路径读取XML格式的配置文件创建IOC容器对象
ConfigurableApplicationContext ApplicationContext的子接口,包含一些扩展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力。
WebApplicationContext 专门为web应用准备,基于web环境IOC容器对象,并将对象引入存入ServletContext域中

 基于XML管理bean:

我们先创建一个类:

package com.rgf.spring.pojo;

public class HelloWorld {
    public void  sayHello(){
        System.out.println("hello,spring");
    }
}

我们创建一个spring config,spring的配置文件:

我们的配置文件如下所示:

<?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:配置一个bean对象,将对象交给IOC容器来管理
属性:
id:bean的唯一标识,不能重复
class:设置bean对象所对应的类型
-->
    <bean id="helloworld" class="com.rgf.spring.pojo.HelloWorld"></bean>
</beans>

 我们的测试类如下所示:
 

package com.rgf.spring.test;

import com.rgf.spring.pojo.HelloWorld;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloWorldTest {
    @Test
    public void test() {
        //获取ioc容器
        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取IOC容器中的bean对象
        HelloWorld helloworld = (HelloWorld) ioc.getBean("helloworld");
        helloworld.sayHello();


    }
}

 运行之后如下所示:

 我们发现出现如上效果,出现如上效果,因为我们把对象交给了IOC容器来管理,我们获取了IOC容器,我们就可以获取IOC容器里面的对象,然后就可以调用容器里面的方法。

IOC容器创建对象的方式:工厂+反射。

我们创建student实体类如下所示: 我们创建学生类交给ioc容器,

package com.rgf.spring.pojo;

public class Student {
    private  Integer sid;
    private String sname;
    private Integer age;
    private String gender;

    public Student() {
    }

    public Student(Integer sid, String sname, Integer age, String gender) {
        this.sid = sid;
        this.sname = sname;
        this.age = age;
        this.gender = gender;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Integer getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

我们进行设置spring的核心配置:

<?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提供的一个对象,获取这个bean所对应的对象-->
<bean id="studentOne" class="com.rgf.spring.pojo.Student"></bean>
</beans>

我们设置的测试类如下所示:

package com.rgf.sping.test;

import com.rgf.spring.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IOCByXMLTest {
    @Test
    public void  testIOC(){
        //获取IOC容器
       ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");
       //获取bean
        Student studentOne = (Student) ioc.getBean("studentOne");
        System.out.println(studentOne);


    }
}

因为我们当前只是创建了一个对象,并没有为我们当前对象中的成员变量赋值。

我们运行之后如下所示:

我们将我们的实体类里面的无参构造进行删除之后,我们进行运行:

  public Student() {
    }

我们将其删除,运行之后如下所示:

我们发现出现错误。

多个错误的时候我们可以从下往上看,这就是无参构造的错误。 

  IOC在底层使用的是工厂模式,最基本的实现是BeanFactory,我们之前是使用的是new构造方法。spring是如何帮助我们创建对象的呢:我们获取ioc容器是通过配置文件来获取的,我们是通过当前配置的bean标签来创建对象的,bean标签里面的id为唯一标识。我们在解析这个配置文件的时候,就可以获取咱们bean标签的class属性值。知道了我们当前要管理的对象的类型。由于有多个Bean标签,类型无法确定,我们通过反射来创建某个类型的对象。通过反射来创建一个类型,他的实例化对象的时候,默认使用的就是无参构造。所以我们把无参构造删掉之后,就会出现错误。

获取bean的三种方式:

1.根据bean的id获取:

Student studentOne = (Student) ioc.getBean("studentOne");

2.获取bean所需要的类型的class对象:

 Student student = ioc.getBean(Student.class);

我们运行之后如下所示:
 

如果我们在bean里面添加如下代码:

  <bean id="studentOne" class="com.rgf.spring.pojo.Student"></bean>
    <bean id="studentTwo" class="com.rgf.spring.pojo.Student"></bean>

我们发现运行之后,如下所示:

 面对这种情况,我们要确保只有一个,即为单例的。

3.获取bean,获取bean所需要的类型和id

 Student student = ioc.getBean("studentOne", Student.class);

 注意:当根据类型获取Bean时,要求ioc容器中指定类型的bean有且只能有一个

扩展:如果组件类实现了接口,根据接口类型可以获取bean:

我们创建接口Person:

package com.rgf.spring.pojo;

public interface Person {

}

之后我们让该类Student继承该接口:

package com.rgf.spring.pojo;

public class Student implements Person{
    private  Integer sid;
    private String sname;
    private Integer age;
    private String gender;

    public Student() {
    }

    public Student(Integer sid, String sname, Integer age, String gender) {
        this.sid = sid;
        this.sname = sname;
        this.age = age;
        this.gender = gender;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Integer getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

之后我们进入测试类如下所示:

package com.rgf.sping.test;

import com.rgf.spring.pojo.Person;
import com.rgf.spring.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IOCByXMLTest {
    /**
     * 获取bean的三种方式:
     * 1.根据bean的id获取
     * 2.根据bean的类型获取
     * 注意:根据类型获取bean时,要求ioc容器中有且只有一个类型匹配的bean。
     * 若没有任何一个类型匹配的bean,此时抛出异常:NoSuchBeanDefinitionException
     * 若有多个类型类型匹配的bean,此时抛出异常:BeanDefinitionParsingException
     * 3.根据bean的id和类型获取
     * 结论:
     * 根据类型来获取Bean时,在满足bean唯一性的前提下,其实只是看:|对象 instanceof 指定的类型|的返回的结果,
     * 只要返回的是true,就可以认定为和类型匹配,能够获取到。
     * 即通过bean的类型,bean所继承的类的类型,bean所实现的接口的类型都可以获取bean
     */
    @Test
    public void  testIOC(){
        //获取IOC容器
       ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");
       //获取bean,获取bean所需要的类型和id
      //  Student student = ioc.getBean("studentOne", Student.class);
        //System.out.println(student);
        //我们当前通过Student类型获取了bean之后,把咱们所获取的对象通过向上转型赋值给了他的接口对象
        Person student = ioc.getBean(Student.class);
        System.out.println(student);
        Person person = ioc.getBean(Person.class);
        System.out.println(person);

    }
}

我们运行之后如下所示:

 我们可以通过接口类型来获取bean,但是前提是bean是唯一的。

如果一个接口有多个实现类,这些实现类都配置了bean,根据接口类是不可以获取bean的,因为bean是不唯一的呢

根据类型来获取Bean时,在满足bean唯一性的前提下,其实只是看:对象    instanceof  指定的类型的返回的结果,只要返回的是true,就可以认定为和类型匹配,能够获取到。

猜你喜欢

转载自blog.csdn.net/weixin_59448049/article/details/127598836