【Spring5】第二篇:IOC之XML方式

一、传统方式创建对象

缺点:

  • 耦合太高:比如UserService的类有了新的实现,那么就需要修改所有调用UserService的地方

示例:

package com.wells.demo.ioc.tradition;

/**
 * Description 传统方式: 通过 new 对象来调用,带来的问题:
 * 1、耦合高:如果userDao有了新的实现,需要修改所有调用userDao的地方;
 * 因此,为了降低耦合,所以需要工厂模式来做,而Spring恰恰用了:xml配置(注解)、工厂模式、反射来进行bean的创建
 * Created by wells on 2020-07-18 08:26:41
 */

public class UserService {
    public void delUser() {
        System.out.println("delete user");
    }

    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.delUser();
    }
}

二、基于XML方式创建对象

  • 在 spring 配置文件中,使用 bean 标签创建对象;标签里面添加对应属性,就可以实现属性注入
  • 在 bean 标签有很多属性,介绍常用的属性
    • id 属性:唯一标识
    • class 属性:类全路径(包类路径)
  • 创建对象时候,默认执行无参数构造方法完成创建对象

示例:

package com.wells.demo.ioc.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description 通过ApplicationContext读取xml配置文件创建对象
 * Created by wells on 2020-07-18 08:26:41
 */

public class UserService {
    public void addUser() {
        System.out.println("add user");
    }

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

        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.addUser();
    }
}

<bean id="userService" class="com.wells.demo.ioc.xml.UserService"/>

三、基于 XML 方式注入基础属性

DI:依赖注入,就是注入属性

2.1、使用set方式注入属性

package com.wells.demo.ioc.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description 通过set方法注入属性
 * Created by wells on 2020-07-18 22:08:35
 */

public class Book {
    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bname='" + bname + '\'' +
                ", bauthor='" + bauthor + '\'' +
                '}';
    }

    /**
     * 通过set方法注入属性
     */
    @Test
    public void testWiredPropertyBySetter() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Book book = applicationContext.getBean("book", Book.class);
        System.out.println(book.toString());
    }
}

<bean id="book" class="com.wells.demo.ioc.xml.Book">
    
    <property name="bname" value="西游记"/>
    <property name="bauthor" value="吴承恩"/>
bean>

2.2、使用有参构造方法注入属性

package com.wells.demo.ioc.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description 使用有参构造方法注入属性
 * Created by wells on 2020-07-18 22:14:14
 */

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

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

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

    /**
     * 通过有参构造方法注入属性
     */
    @Test
    public void testWiredPropertyByConstructor() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        User user = applicationContext.getBean("user", User.class);
        System.out.println(user.toString());
    }
}

<bean id="user" class="com.wells.demo.ioc.xml.User">
    <constructor-arg name="name" value="wells"/>
    <constructor-arg name="age" value="18"/>
bean>

2.3、使用 p 名称空间注入(了解)

package com.wells.demo.ioc.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description 通过P名称空间注入属性
 * Created by wells on 2020-07-18 22:31:53
 */

public class Person {
    private String name;
    private Integer age;

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

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

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

    @Test
    public void testWiredPropertyByPTag() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Person person = applicationContext.getBean("person", Person.class);
        System.out.println(person.toString());
    }
}

<bean id="person" class="com.wells.demo.ioc.xml.Person" p:name="Tom" p:age="18"/>

四、基于XML注入其他类型属性

4.1、注入 Null 值


<bean id="book" class="com.wells.demo.ioc.xml.Book">
    
    <property name="bname" value="西游记"/>
    <property name="bauthor" value="吴承恩"/>
	
	
    <property name="addr">
        <null/>
    property>
bean>

4.2、属性值包含特殊符号

例如: <、>


<bean id="book" class="com.wells.demo.ioc.xml.Book">
    
    <property name="bname" value="西游记"/>
    <property name="bauthor" value="吴承恩"/>
    
    <property name="addr">
        <null/>
    property>
    
    <property name="btime">
        <value>]]>value>
    property>
bean>

4.3、注入自定义bean

4.3.1、外部创建方式

  • 创建两个类:service 类和 dao 类
  • 在 service 调用 dao 里面的方法
  • 在 spring 配置文件中进行配置

<bean id="empOut" class="com.wells.demo.ioc.xml.Emp">
    <property name="ename" value="Jerry"/>
    <property name="gender" value=""/>
    <property name="dept" ref="deptOut"/>
bean>

<bean id="deptOut" class="com.wells.demo.ioc.xml.Dept">
    <property name="dname" value="技术部"/>
bean>

4.3.2、内部创建方式

部门和员工关系


<bean id="empIn" class="com.wells.demo.ioc.xml.Emp">
    <property name="ename" value="Lily"/>
    <property name="gender" value=""/>
    <property name="dept">
        <bean class="com.wells.demo.ioc.xml.Dept">
            <property name="dname" value="测试部"/>
        bean>
    property>
bean>

4.5、注入自定义bean-级联属性

4.5.1、外部注入


<bean id="empLinkOne" class="com.wells.demo.ioc.xml.Emp">
    <property name="ename" value="Tom"/>
    <property name="gender" value=""/>
    <property name="dept" ref="dept"/>
bean>
<bean name="dept" class="com.wells.demo.ioc.xml.Dept">
    <property name="dname" value="安全部"/>
bean>

4.5.2、内部注入


<bean id="empLinkTwo" class="com.wells.demo.ioc.xml.Emp">
    <property name="ename" value="Daivd"/>
    <property name="gender" value=""/>
    <property name="dept" ref="dept"/>

    
    <property name="dept.dname" value="业务部"/>
bean>

4.6、集合属性注入

  • 注入数组类型属性
  • 注入List集合类型属性:基本类型、自定义类型、抽取
  • 注入Map集合类型属性

<bean id="student" class="com.wells.demo.ioc.xml.Student">
    <property name="course">
        <array>
            <value>线性代数value>
            <value>高等数学value>
        array>
    property>

    
    <property name="books">
        <list>
            <value>《SpringBoot编程思想》value>
            <value>《SpringCloud微服务实战》value>
        list>
    property>

    <property name="teachers">
        <map>
            <entry key="大学物理" value="Tom"/>
            <entry key="高等数学" value="Jerry"/>
        map>
    property>

    
    <property name="courseList">
        <list>
            <ref bean="c1"/>
            <ref bean="c2"/>
        list>
    property>

    <property name="friends" ref="friends"/>
bean>

<bean id="c1" class="com.wells.demo.ioc.xml.Course" p:cname="大学物理"/>
<bean id="c2" class="com.wells.demo.ioc.xml.Course" p:cname="编译原理"/>


<util:list id="friends">
    <value>Lilyvalue>
    <value>Wellsvalue>
util:list>

五、FactoryBean

Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

  • 普通 bean:在配置文件中定义 bean 类型就是返回类型
  • 工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
    • 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
    • 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
package com.wells.demo.ioc.xml;

import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description FactoryBean
 * Created by wells on 2020-07-19 09:21:56
 */

public class MyBean implements FactoryBean<Course> {
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("大学英语");
        return course;
    }

    public Class<?> getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return false;
    }

    @Test
    public void testFactoryBean(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Course course = applicationContext.getBean("myBean", Course.class);
        System.out.println(course.toString());
    }
}

六、Bean实例数

在 Spring 里面,默认情况下,bean 是单实例对象

如何设置单实例还是多实例?

  • 在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
  • scope 属性值
    • 第一个值 singleton,默认值,表示是单实例对象
    • 第二个值 prototype,表示是多实例对象

在这里插入图片描述

singleton 和 prototype 区别

  • 第一 singleton单实例,prototype多实例
  • 第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象;设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建对象,而是在调用 getBean 方法时候创建多实例对象;

七、Bean生命周期

生命周期:从对象创建到对象销毁的过程

7.1、无处理器的bean生命周期(五步)

  • 通过构造器创建 bean 实例(无参数构造)
  • 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
  • 调用 bean 的初始化的方法(需要进行配置初始化的方法)
  • bean 可以使用了(对象获取到了)
  • 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
package com.wells.demo.ioc.xml;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description Bean实例生命周期
 * Created by wells on 2020-07-19 09:30:56
 */

public class Order {
    private String oname;

    public Order() {
        System.out.println("第一步: 通过无参构造方法创建bean实例");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步: 通过set方法注入属性");
    }

    /**
     * Bean初始化方法
     */
    public void initMethod() {
        System.out.println("第三步: 调用bean初始化方法");
    }

    /**
     * Bean销毁方法
     */
    public void destroyMethod() {
        System.out.println("第五步: 调用bean销毁方法");
    }

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

    @Test
    public void testBeanLife() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Order order = applicationContext.getBean("order", Order.class);
        System.out.println("第四步: 使用bean");
        System.out.println(order.toString());

        // 手动调用销毁bean实例
        applicationContext.close();
    }
}

<bean id="order" class="com.wells.demo.ioc.xml.Order" init-method="initMethod" destroy-method="destroyMethod" p:oname="裤子"/>

7.2、有处理器的bean生命周期(七步)

  • 通过构造器创建 bean 实例(无参数构造)
  • 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
  • 把 bean 实例传递到 bean 后置处理器的方法 postProcessBeforeInitialization
  • 调用 bean 的初始化的方法(需要进行配置初始化的方法)
  • ==把 bean 实例传递到 bean 后置处理器的方法 postProcessAfterInitialization ==
  • bean 可以使用了(对象获取到了)
  • 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

需要特别注意的是:processor是对所有的bean生效,因此如果创建多个bean,会被执行多次

package com.wells.demo.ioc.xml;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * Description Bean处理器,需要特别注意的是:这个处理器是对所有的bean生效;所以会出现有几个bean,就执行几次
 * Created by wells on 2020-07-19 09:58:12
 */

public class BeanProcess  implements BeanPostProcessor {
    /**
     * 处理器前置方法
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("处理器前置方法");
        return bean;
    }

    /**
     * 处理器后缀方法
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("处理器后置方法");
        return bean;
    }
}

八、XML自动装配

什么是自动装配?

  • 根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

8.1、根据属性名称自动注入

需要注意的是:类中的属性名,需要与xml中的id名相同

public class Emp {
	// ... 略
    private Dept dept;
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    // ... 略
    @Test
    public void testAutoWiredByNameInXML(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-auto-wired.xml");
        Emp emp = applicationContext.getBean("empByName", Emp.class);
        System.out.println(emp.toString());
    }
}
<bean id="empByName" class="com.wells.demo.ioc.xml.Emp" autowire="byName"/>
<bean id="dept" class="com.wells.demo.ioc.xml.Dept">
    <property name="dname" value="运维部"/>

8.2、根据属性类型自动注入

public class Emp {
	// ... 略
    private Dept dept;
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    // ... 略
    
    @Test
    public void testAutoWiredByTypeInXML(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-auto-wired.xml");
        Emp emp = applicationContext.getBean("empByType", Emp.class);
        System.out.println(emp.toString());
    }
}
<bean id="empByType" class="com.wells.demo.ioc.xml.Emp" autowire="byType"/>


<bean id="dept2" class="com.wells.demo.ioc.xml.Dept">
    <property name="dname" value="运维部"/>
bean>

需要注意的是:xml中不能出现多个类型一样的bean实例,否则会报错,如下图:
【Spring5】第二篇:IOC之XML方式_第1张图片

九、引入外部属性

package com.wells.demo.ioc.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description 
 * Created by wells on 2020-07-19 10:19:12
 */

public class Blog {
    private String bname;

    public void setBname(String bname) {
        this.bname = bname;
    }

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

    @Test
    public void testImportPorp() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-import-prop.xml");
        Blog blog = applicationContext.getBean("blog", Blog.class);
        System.out.println(blog.toString());
    }
}

blog.properties文件内容:

blog.bname=wells

<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 http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:property-placeholder location="blog.properties"/>

    <bean id="blog" class="com.wells.demo.ioc.xml.Blog">
        <property name="bname" value="${blog.bname}"/>
    bean>
beans>

代码示例

Spring IOC XML

你可能感兴趣的:(【Spring5,核心】)