Spring学习(一)Spring概述 IOC容器和bean的配置

Spring学习(一)Spring概述 IOC容器和bean的配置

1、Spring概述

1.1、什么是Spring?

  • Spring 是一个开源框架.

  • Spring 为简化企业级应用开发而生. 使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能.

  • Spring 是一个 IOC(DI) 和 AOP 容器框架.

  • Spring优良的特性

    1. 轻量Spring 是非侵入性的 基于Spring开发的应用中的对象可以不依赖于Spring的API
    2. 依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
    3. 面向切面编程:Aspect Oriented Programming——AOP
    4. 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
    5. 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
    6. 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
  • Spring模块

在这里插入图片描述

1.2、Spring的第一个HelloWorld程序

这里是用maven建的项目导入Spring相关的依赖 maven帮我们自动下载(若不是用maven建的则自己导入Spring相关的jar包)

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
</dependencies>

创建一个User实体类

public class User {
    private String name;

    public User() {
    }

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

    public String getName() {
        return name;
    }

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

    public void show(){
        System.out.println("我的名字叫:"+name);
    }

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

注意每次写这种实体类时 最好把无参构造方法写上

Spring配置文件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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 使用bean元素定义一个由IOC容器创建的对象 -->
    <!--id:指定用于引用bean实例的标识-->
	<!--class:指定用于创建bean的全类名 -->
    <bean id="User" class="com.song.pojo.User">
        <property name="name" value="王五"></property>
    </bean>
</beans>

测试

 public static void main(String[] args) {
     //创建IOC容器对象
     ApplicationContext Context = new ClassPathXmlApplicationContext("ApplicationContext.xml");

     //根据id值获取bean实例对象
     User user = (User) Context.getBean("User");

     user.show();
}

2、IOC容器和Bean配置

2.1、IOC和DI

  1. IOC(Inversion of Control):反转控制

    其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式

  2. DI(Dependency Injection):依赖注入

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

2.2、在 Spring 的 IOC 容器里配置 Bean

  • Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
  • Spring 提供了两种类型的 IOC 容器实现.

​ –BeanFactory: IOC 容器的基本实现.

​ –ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.

​ –BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的 应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory

​ –无论使用何种方式, 配置文件时相同的.

2.2.1、ApplicationContext

  • ApplicationContext 的主要实现类:

    ClassPathXmlApplicationContext:从 类路径下加载配置文件

    –FileSystemXmlApplicationContext: 从文件系统中加载配置文件

  • ConfigurableApplicationContext 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭上下文的能力

  • ApplicationContext 在初始化上下文时就实例化所有单例的 Bean

  • WebApplicationContext 是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作

2.2.1、环境搭配置测试

建一个学生基本信息实体类

public class Student {
    private String name;//姓名
    private Integer age;//年龄
    private String books[];//上课的书籍 一个数组
    private CourseTeacher courseTeacher; //每门课老师的姓名
    private List<String> hobbys;//爱好
    private Map<String,String> card;//每个学生的所在地邮政编号
    private Set<String> games;//喜欢的游戏
    private String girlfriend;//是否有女朋友
    private Properties info;

    public String getName() {
        return name;
    }
    
    //等下用来测试构造方法注入的
    public Student(String name) {
        this.name = name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public CourseTeacher getCourseTeacher() {
        return courseTeacher;
    }

    public void setCourseTeacher(CourseTeacher courseTeacher) {
        this.courseTeacher = courseTeacher;
    }

    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 getGirlfriend() {
        return girlfriend;
    }

    public void setGirlfriend(String girlfriend) {
        this.girlfriend = girlfriend;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    public Student() {
        
    }

    //若写courseTeacher.toString()则要把CourseTeacher中属性值写上 不然会出现空指针异常
    @Override
    public String toString() {
        return "Student{" +
                "姓名='" + name + '\'' +
                ", 年龄=" + age +
                ", books=" + Arrays.toString(books) +
                ", courseTeacher=" + courseTeacher + 
                ", 爱好=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", girlfriend='" + girlfriend + '\'' +
                ", info=" + info +
                '}';
    }
}
//每门课程老师的名字
public class CourseTeacher {
    private String math;
    private String chinese;
    private String english;

    public CourseTeacher() {
    }

    public CourseTeacher(String math, String chinese, String english) {
        this.math = math;
        this.chinese = chinese;
        this.english = english;
    }

    public String getMath() {
        return math;
    }

    public void setMath(String math) {
        this.math = math;
    }

    public String getChinese() {
        return chinese;
    }

    public void setChinese(String chinese) {
        this.chinese = chinese;
    }

    public String getEnglish() {
        return english;
    }

    public void setEnglish(String english) {
        this.english = english;
    }

    @Override
    public String toString() {
        return "CourseTeacher{" +
                "math='" + math + '\'' +
                ", chinese='" + chinese + '\'' +
                ", english='" + english + '\'' +
                '}';
    }
}

基本注入

<!--常量注入-->
<bean id="User" class="com.song.pojo.User">
        <property name="name" value="李四"></property>
</bean>

测试

 @Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("User");
     System.out.println(user);
 }

引用其它 Bean注入

    <!--引用其他bean 使用ref-->
    <bean id="CourseTeacher" class="com.song.pojo.CourseTeacher">
        <property name="chinese" value="语文老师"></property>
        <property name="math" value="数学老师"></property>
        <property name="english" value="英语老师"></property>
    </bean>
    <bean id="student2" class="com.song.pojo.Student">
        <property name="name" value="小黄"></property>
        <property name="courseTeacher" ref="CourseTeacher"></property>
    </bean>

测试

    @Test
    public void test02(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        Student student = (Student) context.getBean("student2");

        System.out.println(student);
    }

数组注入

    <!--数组注入-->
    <bean id="student3" class="com.song.pojo.Student">
        <property name="books">
            <array>
                <value>Java入门到精通</value>
                <value>go入门到精通</value>
                <value>C++入门到精通</value>
                <value>数据结构与算法</value>
            </array>
        </property>
    </bean>

List注入

<!--List注入-->
    <bean id="student4" class="com.song.pojo.Student">
        <property name="hobbys">
            <list>
                <value>打篮球</value>
                <value>看动漫</value>
                <value>听歌</value>
            </list>
        </property>
    </bean>

map注入

<!--Map注入-->
    <bean id="student5" class="com.song.pojo.Student">
        <property name="card">
            <map>
                <entry key="广州" value="1334"></entry>
                <entry key="湖北" value="43346"></entry>
            </map>
        </property>
    </bean>

set注入

<bean id="student6" class="com.song.pojo.Student">
        <property name="games">
            <set>
                <value>王者荣耀</value>
                <value>CF</value>
                <value>吃鸡</value>
            </set>
        </property>
</bean>

null注入

<property name="girlfriend"><null/></property>

Propertise注入

<bean id="student7" class="com.song.pojo.Student">
   <property name="info">
     <props>
         <prop key="学号">20190604</prop>
         <prop key="系别">信息工程系</prop>
         <prop key="专业">软件工程</prop>
     </props>
   </property>
</bean>

构造方法注入

    <bean id="student7" class="com.song.pojo.Student">
        <constructor-arg index="0" value="小张" ></constructor-arg>
    </bean>

索引值指定参数位置

综合使用

<bean id="student8" class="com.song.pojo.Student">
        <constructor-arg value="小张" index="0"></constructor-arg>

        <property name="age" value="18"></property>

        <property name="books">
            <array>
                <value>Java入门到精通</value>
                <value>go入门到精通</value>
                <value>C++入门到精通</value>
                <value>数据结构与算法</value>
            </array>
        </property>

        <property name="courseTeacher" ref="CourseTeacher"></property>

        <property name="hobbys">
            <list>
                <value>打篮球</value>
                <value>看动漫</value>
                <value>听歌</value>
            </list>
        </property>

        <property name="card">
            <map>
                <entry key="广州" value="1334"></entry>
                <entry key="湖北" value="43346"></entry>
            </map>
        </property>

        <property name="games">
            <set>
                <value>王者荣耀</value>
                <value>CF</value>
                <value>吃鸡</value>
            </set>
        </property>

        <property name="info">
            <props>
                <prop key="学号">20190604</prop>
                <prop key="系别">信息工程系</prop>
                <prop key="专业">软件工程</prop>
            </props>
        </property>

        <property name="girlfriend"><null/></property>

    </bean>
//测试结果
Student{
   姓名='小张', 
   年龄=18, 
   books=[Java入门到精通, go入门到精通, C++入门到精通, 数据结构与算法], 
   courseTeacher=CourseTeacher{math='数学老师', chinese='语文老师', english='英语老师'},
   爱好=[打篮球, 看动漫, 听歌], 
   card={广州=1334, 湖北=43346}, 
   games=[王者荣耀, CF, 吃鸡], 
   girlfriend='null', 
   info={学号=20190604, 专业=软件工程, 系别=信息工程系}
   }

还有一种工厂方法注入 用得少

2.3、bean的高级配置

  1. 配置信息的继承

  2. 配置信息的继承

    Spring允许继承bean的配置,被继承的bean称为父bean。继承这个父bean的bean称为子bean

    子bean从父bean中继承配置,包括bean的属性配置

    子bean也可以覆盖从父bean继承过来的配置

  3. 父bean可以作为配置模板,也可以作为bean实例。若只想把父bean作为模板,可以设置的abstract 属性为true,这样Spring将不会实例化这个bean

    如果一个bean的class属性没有指定,则必须是抽象bean

    并不是元素里的所有属性都会被继承。比如:autowire,abstract等。

    也可以忽略父bean的class属性,让子bean指定自己的类,而共享相同的属性配置。但此时abstract必须设为true

2.3.1、bean之间的依赖

有的时候创建一个bean的时候需要保证另外一个bean也被创建,这时我们称前面的bean对后面的bean有依赖

依赖关系不等于引用关系

2.3.2、bean的作用域

在Spring中,可以在元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。

默认情况下,Spring只为每个在IOC容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。
在这里插入图片描述

当bean的作用域为单例时,Spring会在IOC容器对象创建时就创建bean的对象实例。而当bean的作用域为prototype时,IOC容器在获取bean的实例时创建bean的实例对象。

2.3.3、bean的生命周期

  1. Spring IOC容器可以管理bean的生命周期,Spring允许在bean生命周期内特定的时间点执行指定的任务。

  2. Spring IOC容器对bean的生命周期进行管理的过程:

  3. 在配置bean时,通过init-method和destroy-method 属性为bean指定初始化和销毁方法

    • 通过构造器或工厂方法创建bean实例
    • 为bean的属性设置值和对其他bean的引用
    • 调用bean的初始化方法
    • bean可以使用了
    • 当容器关闭时,调用bean的销毁方法
  4. bean的后置处理器

    • bean后置处理器允许在调用初始化方法前后对bean进行额外的处理
    • bean后置处理器对IOC容器里的所有bean实例逐一处理,而非单一实例。其典型应用是:检查bean属性的正确性或根据特定的标准更改bean的属性。
    • bean后置处理器时需要实现接口:org.springframework.beans.factory.config.BeanPostProcessor。在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法:
      • postProcessBeforeInitialization(Object, String)
      • postProcessAfterInitialization(Object, String)

    5.添加bean后置处理器后bean的生命周期

  • 通过构造器或工厂方法**创建****bean实例
  • 为bean的属性设置值和对其他bean的引用
  • 将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
  • 调用bean的初始化方法
  • 将bean实例传递给bean后置处理器的postProcessAfterInitialization()**方法
  • bean可以使用了
  • 当容器关闭时调用bean的销毁方法

2.3.4、xml中实现自动装配

自动装配的概念

  • 手动装配:以value或ref的方式明确指定属性值都是手动装配。
  • 自动装配:根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。

装配模式

  • 根据类型自动装配将类型匹配的bean作为属性注入到另一个bean中。若IOC容器中有多个与目标bean类型一致的bean,Spring将无法判定哪个bean最合适该属性,所以不能执行自动装配
  • 根据名称自动装配:必须将目标bean的名称和属性名设置的完全相同
  • 通过构造器自动装配:当bean中存在多个构造器时,此种自动装配方式将会很复杂。建议多使用注解(@autowire)实现自动装配

若想了解更多的Spring建议查看 Spring官网

Spring下载地址

推荐学习Spring的视频 B站 遇见狂神说 或者 尚硅谷

谢谢大家的阅读! 若上面有写错的 欢迎纠正哦!

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页