2、Spring_DI

DI

1.概述

  • 概述:Dependency Injection 依赖注入,给对象设置属性,曾经我们需要自己去创建 mapper 对象,才能调用,现在交给 spring 创建,并且使用 DI 注入,直接拿来用,程序员就可以更加关注业务代码而不是创建对象(ioc已经创建好了对象,通过DI来拿到对象使用)
  • 给对象设置属性方式:
    • 构造器
    • set 方法
  • spring 也是通过构造器以及set方法来实现属性设置

2.回顾问题

  • 如果只给了 mapper 对象,那么调用的时候会出现空指针

    2、Spring_DI_第1张图片

  • 解决方式:使用 DI 注入,解决方案如下

    2、Spring_DI_第2张图片

3.构造器依赖注入

3.1.创建学生类

public class Student {
}

3.2.创建Mapper 接口以及实现类

  • 创建 Mapper 接口

    public interface StudentMapper {
        void insert(Student stu);
        
        int delete(Long id);
    }
    
  • 创建 Mapper 实现类

    public class StudentMapperImpl implements StudentMapper{
        public void insert(Student stu) {
            System.out.println("保存学生信息");
        }
    
        public int delete(Long id) {
            System.out.println("删除id="+id+"的学生信息");
            return 1;
        }
    }
    
  • 将 Mapper 交给容器管理

    <bean id="studentMapper" class="cn.sycoder.di.mapper.StudentMapperImpl">bean>
    

3.3.创建 service 接口以及实现类

  • 创建 service 接口

    public interface IStudentService {
        void insert(Student stu);
    
        int delete(Long id);
    }
    
  • 创建 service 实现类

    public class StudentServiceImpl implements IStudentService {
    
        private StudentMapper mapper;
    
        public void insert(Student stu) {
            mapper.insert(stu);
        }
    
        public int delete(Long id) {
            return mapper.delete(id);
        }
    }
    
  • 将 service 交给容器管理

    <bean id="iStudentService" class="cn.sycoder.di.service.impl.StudentServiceImpl">bean>
    

3.4.如果没有使用DI注入直接调用

  • 会产生如下问题

    2、Spring_DI_第3张图片

3.5.配置构造器注入属性

  • 配置 service 构造器

    public class StudentServiceImpl implements IStudentService {
    
        private StudentMapper mapper;
    
        public StudentServiceImpl(StudentMapper mapper){
            this.mapper = mapper;
        }
    
        public void insert(Student stu) {
            mapper.insert(stu);
        }
    
        public int delete(Long id) {
            return mapper.delete(id);
        }
    }
    
  • 配置 xml

    
        <bean id="iStudentService" class="cn.sycoder.di.service.impl.StudentServiceImpl">
            <constructor-arg name="mapper" ref="studentMapper">constructor-arg>
        bean>
    
        <bean id="studentMapper" class="cn.sycoder.di.mapper.StudentMapperImpl">bean>
    
  • 注意:

    • name:构造器的参数名称

    • ref:配置文件中其它 bean 的名称

    • 图示如下

      2、Spring_DI_第4张图片

3.6.构造器配置多个引用类型参数

  • service

    public class StudentServiceImpl implements IStudentService {
    
        private StudentMapper mapper;
    
        private UserMapper userMapper;
    
        public StudentServiceImpl(StudentMapper mapper,UserMapper userMapper){
            this.mapper = mapper;
            this.userMapper = userMapper;
        }
    
        public void insert(Student stu) {
            mapper.insert(stu);
        }
    
        public int delete(Long id) {
            userMapper.delete(id);
            return mapper.delete(id);
        }
    }
    
  • mapper

    public interface UserMapper {
        int delete(Long id);
    }
    
  • mapper 实现类

    public class UserMapperImpl implements UserMapper{
    
        public int delete(Long id) {
            System.out.println("删除id="+id+"的用户信息");
            return 1;
        }
    }
    
  • 配置

    <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 id="iStudentService" class="cn.sycoder.di.service.impl.StudentServiceImpl">
            <constructor-arg name="mapper" ref="studentMapper">constructor-arg>
            <constructor-arg name="userMapper" ref="userMapper">constructor-arg>
        bean>
    
        <bean id="studentMapper" class="cn.sycoder.di.mapper.StudentMapperImpl">bean>
    
        <bean id="userMapper" class="cn.sycoder.di.mapper.UserMapperImpl">bean>
    beans>
    

3.7.构造器配置多个基本数据类型参数

  • service

    public class StudentServiceImpl implements IStudentService {
    
        private String name;
    
        private int age;
    
        private StudentMapper mapper;
    
        private UserMapper userMapper;
    
        public StudentServiceImpl(String name,int age,StudentMapper mapper,UserMapper userMapper){
            this.name = name;
            this.age = age;
            this.mapper = mapper;
            this.userMapper = userMapper;
        }
    
        public void insert(Student stu) {
            mapper.insert(stu);
        }
    
        public int delete(Long id) {
            System.out.println( name+":"+age);
            userMapper.delete(id);
            return mapper.delete(id);
        }
    }
    
  • xml

    
    <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 id="iStudentService" class="cn.sycoder.di.service.impl.StudentServiceImpl">
            <constructor-arg name="userMapper" ref="userMapper">constructor-arg>
            <constructor-arg name="mapper" ref="studentMapper">constructor-arg>
            <constructor-arg type="int" value="18">constructor-arg>
            <constructor-arg type="java.lang.String" value="sy">constructor-arg>
        bean>
    
        <bean id="studentMapper" class="cn.sycoder.di.mapper.StudentMapperImpl">bean>
    
        <bean id="userMapper" class="cn.sycoder.di.mapper.UserMapperImpl">bean>
    beans>
    
  • 这种方式会存在参数覆盖的问题,解决方式,删除 type 添加 index 属性

    
    <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 id="iStudentService" class="cn.sycoder.di.service.impl.StudentServiceImpl">
            <constructor-arg name="userMapper" ref="userMapper">constructor-arg>
            <constructor-arg name="mapper" ref="studentMapper">constructor-arg>
            <constructor-arg index="2" value="18">constructor-arg>
            <constructor-arg index="1" value="1">constructor-arg>
            <constructor-arg type="java.lang.String" value="sy">constructor-arg>
    
        bean>
    
        <bean id="studentMapper" class="cn.sycoder.di.mapper.StudentMapperImpl">bean>
    
        <bean id="userMapper" class="cn.sycoder.di.mapper.UserMapperImpl">bean>
    beans>
    

    4.setter依赖注入

  • 使用 set 方法实现属性的注入

  • 使用 property 属性

    • name:属性名称
    • value:直接给值
    • ref:其它bean的引用

4.1.创建员工类

public class Employee {
}

4.2.创建 mapper 接口以及实现类

  • mapper 接口

    public interface EmployeeMapper {
        int delete(Long id);
    }
    
  • mapper 实现类

    public class EmployeeMapperImpl implements EmployeeMapper {
        public int delete(Long id) {
            System.out.println("删除当前员工id:"+id);
            return 1;
        }
    }
    

4.3.创建 servie 接口以及实现类

  • 创建 service 接口

    public interface IEmployeeService {
        int delete(Long id);
    }
    
  • 创建 service 接口实现类

    public class EmployeeServiceImpl implements IEmployeeService {
    
        private EmployeeMapper mapper;
    
        public int delete(Long id) {
            return mapper.delete(id);
        }
    }
    

4.4.配置 setter 注入

  • 配置bean

    
    <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 id="empMapper" class="cn.sycoder.di.setter.mapper.EmployeeMapperImpl">bean>
    
        <bean id="empService" class="cn.sycoder.di.setter.service.impl.EmployeeServiceImpl">bean>
    beans>
    
  • service 实现中提供 mapper 的setter 方法

    public class EmployeeServiceImpl implements IEmployeeService {
    
        private EmployeeMapper employeeMapper;
    
        public int delete(Long id) {
            return employeeMapper.delete(id);
        }
        
        public void setEmployeeMapper(EmployeeMapper employeeMapper){
            this.employeeMapper = employeeMapper;
        }
    }
    
  • 修改 beans.xml 通过 setter 注入

    
    <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 id="empMapper" class="cn.sycoder.di.setter.mapper.EmployeeMapperImpl">bean>
    
        <bean id="empService" class="cn.sycoder.di.setter.service.impl.EmployeeServiceImpl">
            <property name="employeeMapper" ref="empMapper">property>
        bean>
    beans>
    
  • 获取 service 执行 delete 方法

    @Test
        public void testSetDi(){
            final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("DiSetterBeans.xml");
            final IEmployeeService empService = (IEmployeeService) context.getBean("empService");
            empService.delete(2L);
        }
    
  • setter 注入过程分析

    2、Spring_DI_第5张图片

    4.5.配置多个 setter 方法注入多个属性

  • 给service 添加新的属性以及新的setter方法

    public class EmployeeServiceImpl implements IEmployeeService {
    
        private EmployeeMapper employeeMapper;
    
        private UserMapper userMapper;
    
        public int delete(Long id) {
            return employeeMapper.delete(id);
        }
    
        public void setEmployeeMapper(EmployeeMapper employeeMapper){
            System.out.println("=======使用 setter 注入=======");
            this.employeeMapper = employeeMapper;
        }
    
        public void setUserMapper(UserMapper mapper){
            this.userMapper = mapper;
        }
    }
    
  • 配置 userMapper bean

    
    <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 id="empMapper" class="cn.sycoder.di.setter.mapper.EmployeeMapperImpl">bean>
    
        <bean id="empService" class="cn.sycoder.di.setter.service.impl.EmployeeServiceImpl">
            <property name="employeeMapper" ref="empMapper">property>
        bean>
    
        <bean id="userMapper" class="cn.sycoder.di.constructor.mapper.StudentMapperImpl">bean>
    beans>
    
  • 通过 setter 注入

    
    <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 id="empMapper" class="cn.sycoder.di.setter.mapper.EmployeeMapperImpl">bean>
    
        <bean id="empService" class="cn.sycoder.di.setter.service.impl.EmployeeServiceImpl">
            <property name="employeeMapper" ref="empMapper">property>
            <property name="userMapper" ref="userMapper">property>
        bean>
    
        <bean id="userMapper" class="cn.sycoder.di.constructor.mapper.UserMapperImpl">bean>
    beans>
    
  • 获取 service 操作delete 方法

    @Test
        public void testSetterSDi(){
            final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("DiSetterBeans.xml");
            final IEmployeeService empService = (IEmployeeService) context.getBean("empService");
            empService.delete(2L);
        }
    

4.6.使用 setter 注入简单类型

  • 修改 service 类,提供两个属性 int age = 18,String name = “sy”

    public class EmployeeServiceImpl implements IEmployeeService {
    
        private EmployeeMapper employeeMapper;
    
        private UserMapper userMapper;
        
        private String name;
        
        private int age;
        
        public void setName(String name){
            this.name = name;
        }
        public void setAge(int age){
            this.age = age;
        }
    
        public int delete(Long id) {
            System.out.println(name + ":" + age);
            userMapper.delete(id);
            return employeeMapper.delete(id);
        }
    
        public void setEmployeeMapper(EmployeeMapper employeeMapper){
            System.out.println("=======EmployeeMapper使用 setter 注入=======");
            this.employeeMapper = employeeMapper;
        }
    
        public void setUserMapper(UserMapper mapper){
            System.out.println("=======UserMapper使用 setter 注入=======");
            this.userMapper = mapper;
        }
    }
    
  • 配置 xml 设置值

    
    <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 id="empMapper" class="cn.sycoder.di.setter.mapper.EmployeeMapperImpl">bean>
    
        <bean id="empService" class="cn.sycoder.di.setter.service.impl.EmployeeServiceImpl">
            <property name="employeeMapper" ref="empMapper">property>
            <property name="userMapper" ref="userMapper">property>
            <property name="name" value="sy">property>
            <property name="age" value="18">property>
        bean>
    
        <bean id="userMapper" class="cn.sycoder.di.constructor.mapper.UserMapperImpl">bean>
    beans>
    
  • 可能出现的问题

    2、Spring_DI_第6张图片

4.7.setter 注入总结

  • 对于引用数据类型来说使用
    • < property name=“” ref=“”>
  • 对于简单数据类型
    • < property name=“” value=“”>

5.集合注入

  • List
  • Set
  • Map
  • Array
  • Properties

5.1.添加CollectiosDemo类

public class CollectionsDemo {
    private List<Integer> list;
    private Map<String,String> map;
    private Set<String> set;
    private Properties properties;
    private int[] arr;

    public void print(){
        System.out.println("list:"+list);
        System.out.println("map:"+map);
        System.out.println("set:"+set);
        System.out.println("properties:"+properties);
        System.out.println("arr:"+ Arrays.toString(arr));
    }

    public void setList(List<Integer> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void setArr(int[] arr) {
        this.arr = arr;
    }
}

5.2.配置 bean


<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 id="collectionsDemo" class="cn.sycoder.collections.CollectionsDemo">

        <property name="list">
            <list>
                <value>1value>
                <value>2value>
                <value>3value>
            list>
        property>
        <property name="map">
            <map>
                <entry key="name" value="sy"/>
                <entry key ="age" value="18"/>
            map>
        property>
        <property name="set">
            <set>
                <value>just some stringvalue>
                <value>just stringvalue>
            set>
        property>
        <property name="properties">
            <props>
                <prop key="url">@example.orgprop>
                <prop key="user">rootprop>
                <prop key="password">123456prop>
            props>
        property>
        <property name="arr">
            <array>
                <value>2value>
                <value>2value>
                <value>2value>
            array>
        property>
    bean>
beans>
  • 如果不提供setter 方法会出现如下错误

    2、Spring_DI_第7张图片

6.自动装配

1.概述

  • 概述:IOC容器根据bean所依赖的属性,自动查找并进行自动装配。

2.分类

  • 不启用自动装配
  • byName 通过名称
  • byType 通过类型
  • constructor 通过构造器

3.实操

  • 准备工作

    public class EmployeeService {
        private EmployeeMapperImpl employeeMapper;
        public int delete(Long id) {
            return employeeMapper.delete(id);
        }
        public void setEmployeeMapper(EmployeeMapperImpl employeeMapper){
            System.out.println("=======EmployeeMapper使用 setter 注入=======");
            this.employeeMapper = employeeMapper;
        }
    }
    
    public class EmployeeMapperImpl{
        public int delete(Long id) {
            System.out.println("删除当前员工id:"+id);
            return 1;
        }
    }
    
  • 配置 bean 并且通过 bype 自动装配

    
    <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 id="empService" class="cn.sycoder.autowired.EmpService" autowire="byType">bean>
        <bean id="empMapperImpl" class="cn.sycoder.autowired.EmpMapperImpl">bean>
    
    beans>
    
  • 配置 bean 并且通过 byName 自动装配

    
    <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 id="empService" class="cn.sycoder.autowired.EmpService" autowire="byName">bean>
        <bean id="empMapperImpl" class="cn.sycoder.autowired.EmpMapperImpl">bean>
    
    beans>
    
  • 通过名称和类型的自动装配

    • byName

      • 使用 id 或者是 name 别名
      • 如果自动注入时,有多个相同对象,只能使用 byName
    • byType

      • 根据类型注入

      • 通过 byType 注入要保证容器中只有一个 bean 对象,否则会出现如下错误

        2、Spring_DI_第8张图片

  • 注意:

    • 自动注入的优先级是低于 setter 和 构造器注入的
    • 自动注入只能用于引用类型,不能用于基本数据类型
    • 推荐使用 byType 方式实现自动注入
    • 注入流程
      • byType 根据 getClass 去注入
      • byName 根据属性名称去注入

7.bean scopes

  • 常见的作用域

    作用域 说明
    singleton 单例的
    prototype 多例
    request 请求
    session 会话
  • 单例 singleton

    2、Spring_DI_第9张图片

  • 修改对象变成多个实例的

    2、Spring_DI_第10张图片

  • 注意:容器模式就是以单例的方式创建对象的,如果需要修改成非单例,使用 scope 属性修改即可

  • 以后开发中适合将那些bean对象交给 spring 管理

    • 持久层 mapper
    • 业务层 service
    • 控制层 controller
  • 单例bean会出现线程安全吗

    • 判断bean 对象是否存储数据,如果用来存储数据了,会导致线程安全问题
    • 使用局部变量做存储,方法调用结束就销毁了,所以不存在线程安全问题

8.bean 生命周期

1.概述

  • 概述:生命周期就是一个对象从出生到死亡的过程

2.使用用户类观察生命周期

  • 创建用户类

    public class User {
        private String name;
        public User(){
            System.out.println("构造器执行====");
        }
    
        public void setName(String name) {
            System.out.println("调用 set 方法");
            this.name = name;
        }
        
        public void init(){
            System.out.println("调用 init 方法");
        }
        
        public void destroy(){
            System.out.println("调用销毁方法");
        }
    }
    
  • 配置 bean

    
    <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 id="user" class="cn.sycoder.lifecycle.User" init-method="init" destroy-method="destroy">
            <property name="name" value="sy">property>
        bean>
    beans>
    
  • 获取 bean 出现如下问题,没有打印销毁方法

    • 原因:

      • spring ioc 容器是运行在 jvm 虚拟机中的

      • 执行 test 方法后 jvm 虚拟机开启,spring 加载配置文件创建 bean 对象,调用构造器以及 init 方法

      • test 方法执行完毕的时候, jvm 退出,spring ioc 容器来不及关闭销毁 bean,所以没有去调用 destroy 方法

        2、Spring_DI_第11张图片

    • 解决办法,正常关闭容器

      2、Spring_DI_第12张图片

3.BeanPostProcessor

  • 自定义自己 bean 处理器

    public class MyBeanPostProcessor  implements BeanPostProcessor{
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            //bean 前置处理器
            System.out.println("bean 的前置处理器");
            return bean;
        }
    
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("bean 的后置处理器");
            //bean 后置处理器
            return bean;
        }
    }
    
  • 配置 bean

    
    <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 id="user" class="cn.sycoder.lifecycle.User" init-method="init" destroy-method="destroy">
            <property name="name" value="sy">property>
        bean>
    
        <bean class="cn.sycoder.lifecycle.MyBeanPostProcessor">bean>
    beans>
    

4.生命周期总结

  • bean 对象创建(调用无参构造器)
  • 设置属性通过 setter 方法
  • init 方法前调用 bean 的前置处理器
  • bean 的 init 方法
  • bean 的后置处理器
  • 对象可以正常使用
  • destroy 销毁方法
  • ioc 容器关闭
  • jvm 虚拟机的退出

你可能感兴趣的:(spring,java,后端)