[SSM]Spring对IoC的实现

目录

四、Spring对IoC的实现

4.1IoC控制反转

4.2依赖注入

4.2.1set注入

4.2.2构造注入

4.3set注入专题

4.3.1注入外部Bean

4.3.2注入内部Bean

4.3.3注入简单类型

4.3.4级联属性赋值

4.3.5注入数组

4.3.6注入List、Set、Map集合

4.3.7注入Properties

4.3.8注入null和空字符串

4.3.9注入的值中含有特殊符号

4.4p命名空间注入

4.5c命名空间注入

4.6util命名空间

4.7基于XML的自动装配

4.7.1根据名称自动装配

4.7.2根据类型自动装配

4.8Spring引入外部属性配置文件


四、Spring对IoC的实现

4.1IoC控制反转

  • 控制反转是一种思想。

  • 控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则、DIP原则。

  • 控制反转,反转的是什么?

    • 将对象的创建权交出去,交给第三方容器负责。

    • 将对象和对象之间的关系维护权交出去,交给第三方容器负责。

  • 控制反转这种思想如何实现?

    • DI(Dependency Injection):依赖注入

4.2依赖注入

  • 依赖注入实现了控制反转的思想。

  • Spring通过依赖注入的方式来完成Bean的管理。

  • Bean的管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

  • 依赖注入:

    • 依赖指的是对象和对象之间的关联关系。

    • 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

  • 依赖注入常见的实现方式包括两种:

    • 第一种:set注入。

    • 第二种:构造注入。

4.2.1set注入

  • set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种机制要求属性必须对外提供set方法。

UserDao

package com.hhb.dao;
​
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
​
public class UserDao {
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);
    public void insert() {
        //使用log4j2日志框架
        logger.info("数据库正在保存用户信息");
    }
}

UserService

package com.hhb.service;
​
import com.hhb.dao.UserDao;
import com.hhb.dao.VipDao;
​
public class UserService {
    private UserDao userDao;
    //set注入的话,必须提供一个set方法
    //Spring容器会调用这个set方法来给userDao属性赋值。
    //set方法必须以set单词开头
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void saveUser() {
        //保存用户信息到数据库
        userDao.insert();
        vipDao.insert();
    }
}

spring.xml



​
    
    
​
    
    
        
        
        
        
    

测试

@Test
    public void testSetDI(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);
        userServiceBean.saveUser();
    }
  • 实现原理:

    • 通过property标签获取到属性名:userDao

    • 通过属性名推断出set方法名:setUserDao

    • 通过反射机制调用setUserDao()方法给属性赋值

    • property标签的name是属性名

    • property标签的ref是要注入的bean对象的id。(通过ref属性来完成bean的装配,这是bean最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)

  • set注入的核心实现原理:通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系。

4.2.2构造注入

  • 核心原理:通过调用构造方法来给属性赋值。

UserDao

package com.hhb.dao;
​
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
​
public class UserDao {
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);
    public void insert() {
        //使用log4j2日志框架
        logger.info("数据库正在保存用户信息");
    }
}

VipDao

package com.hhb.dao;
​
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
public class VipDao {
    private static final Logger logger=LoggerFactory.getLogger(VipDao.class);
​
    public void insert(){
        logger.info("正在保存VIP信息");
    }
}

CustomerService

package com.hhb.service;
​
import com.hhb.dao.UserDao;
import com.hhb.dao.VipDao;
​
public class CustomerService {
    private UserDao userDao;
    private VipDao vipDao;
​
    public CustomerService(UserDao userDao, VipDao vipDao) {
        this.userDao = userDao;
        this.vipDao = vipDao;
    }
​
    public void save() {
        userDao.insert();
        vipDao.insert();
    }
}

beans.xml



​
    
    
​
    
        
        
        
        
    
​
    
        
        
        
    
​
    
        
        
        
        
    

测试

@Test
    public void testConstructDI() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        CustomerService csBean = applicationContext.getBean("csBean", CustomerService.class);
        csBean.save();
​
        CustomerService csBean2 = applicationContext.getBean("csBean2", CustomerService.class);
        csBean2.save();
​
        CustomerService csBean3 = applicationContext.getBean("csBean3", CustomerService.class);
        csBean3.save();
    }
  • 通过测试得知,通过构造方法注入的时候:

    • 可以通过下标

    • 可以通过参数名

    • 也可以不指定下标和参数名,可以类型自动推断

4.3set注入专题

4.3.1注入外部Bean

set-di.xml


​
    
        
    
  • 外部Bean的特点:bean定义到外面,在property标签中使用ref属性进行注入,通常这种方式是常用的。

4.3.2注入内部Bean

set-di.xml

 
     
         
     
 
  • 这种方式作为了解。

4.3.3注入简单类型

第一步:定义User类,提供setter方法

package com.hhb.bean;
​
public class User {
    private String username; // String是简单类型
    private String password;
    private int age; // int是简单类型
​
    public void setUsername(String username) {
        this.username = username;
    }
​
    public void setPassword(String password) {
        this.password = password;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

第二步:set-di.xml


    
    
    
    

第三步:测试

    @Test
    public void testSimpleTypeSet() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
        User user = applicationContext.getBean("userBean", User.class);
        System.out.println(user);
    }
  • 简单类型包括:

    • 基本数据类型

    • 基本数据类型对应的包装类

    • String或其他的CharSequence子类

    • Number子类

    • Date子类

    • Enum子类

    • URL

    • URI

    • Temporal子类

    • Locale

    • Class

    • 以上简单值类型对应的数组类型

SimpleValueType

package com.powernode.spring6.beans;
import java.net.URI;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;
public class A {
 private byte b;
 private short s;
 private int i;
 private long l;
 private float f;
 private double d;
 private boolean flag;
 private char c;
 private Byte b1;
 private Short s1;
 private Integer i1;
 private Long l1;
 private Float f1;
 private Double d1;
 private Boolean flag1;
 private Character c1;
 private String str;
 private Date date;
 private Season season;
 private URI uri;
 private URL url;
 private LocalDate localDate;
 private Locale locale;
 private Class clazz;
 
 // ⽣成setter⽅法
 // ⽣成toString⽅法
}
enum Season {
 SPRING, SUMMER, AUTUMN, WINTER
}
  • 如果把Date当做简单类型的话,日期字符串格式不能随便写。必须按照这种格式写:Wed Oct 19 16:28:13 CST 2022

经典案例:给数据源的属性注入值

MyDataSource

package com.hhb.jdbc;
​
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
​
public class MyDataSource implements DataSource {
    private String driver;
    private String url;
    private String username;
    private String password;
​
    public void setDriver(String driver) {
        this.driver = driver;
    }
​
    public void setUrl(String url) {
        this.url = url;
    }
​
    public void setUsername(String username) {
        this.username = username;
    }
​
    public void setPassword(String password) {
        this.password = password;
    }
​
    @Override
    public String toString() {
        return "MyDataSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
​
    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }
​
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }
​
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }
​
    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
​
    }
​
    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
​
    }
​
    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }
​
    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
​
    @Override
    public  T unwrap(Class iface) throws SQLException {
        return null;
    }
​
    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }
}

set-di.xml


        
        
        
        
    

4.3.4级联属性赋值

Student

package com.hhb.bean;
​
public class Student {
    private String name;
​
    //学生属于哪个班级
    private Clazz clazz;
​
    public void setName(String name) {
        this.name = name;
    }
​
    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }
​
    //使用级联属性赋值,需要get方法
    public Clazz getClazz() {
        return clazz;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", clazz=" + clazz +
                '}';
    }
}

Clazz

package com.hhb.bean;
​
public class Clazz {
    private String name;
​
    public void setName(String name) {
        this.name = name;
    }
​
    @Override
    public String toString() {
        return "Clazz{" +
                "name='" + name + '\'' +
                '}';
    }
}

cascade.xml



​
    
    
        
        
        
        
        
        
    
​
    

4.3.5注入数组

Array1

package com.hhb.bean;
​
import java.util.Arrays;
​
public class Array1 {
    private String[] hobbies;
​
    private Array2[] array2;
​
    public void setArray2(Array2[] array2) {
        this.array2 = array2;
    }
​
    public void setHobbies(String[] hobbies) {
        this.hobbies = hobbies;
    }
​
    @Override
    public String toString() {
        return "Array1{" +
                "hobbies=" + Arrays.toString(hobbies) +
                ", array2=" + Arrays.toString(array2) +
                '}';
    }
}

Array2

package com.hhb.bean;
​
public class Array2 {
    private String name;
​
    public void setName(String name) {
        this.name = name;
    }
​
    @Override
    public String toString() {
        return "Array2{" +
                "name='" + name + '\'' +
                '}';
    }
}

spring-array.xml



​
    
        
    
    
        
    
    
        
    
        
    
        
        
            
                抽烟
                喝酒
                烫头
            
        
        
        
            
                
                
                
            
        
    

4.3.6注入List、Set、Map集合

Person

package com.hhb.bean;
​
import java.util.List;
import java.util.Map;
import java.util.Set;
​
public class Person {
    private List names;
    private Set phones;
    private Map adrrs;
​
    public void setNames(List names) {
        this.names = names;
    }
​
    public void setPhones(Set phones) {
        this.phones = phones;
    }
​
    public void setAdrrs(Map adrrs) {
        this.adrrs = adrrs;
    }
​
    @Override
    public String toString() {
        return "Person{" +
                "names=" + names +
                ", phones=" + phones +
                ", adrrs=" + adrrs +
                '}';
    }
}
​

spring-collection.xml



​
    
        
            
            
                张三
                李四
                王五
                张三
            
        
        
            
            
                110
                120
                110
            
        
        
            
            
                
                
                
                
            
        
    

4.3.7注入Properties

Property

package com.hhb.bean;
​
import java.util.Properties;
​
public class Property {
    private Properties properties;
​
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
​
    @Override
    public String toString() {
        return "Property{" +
                "properties=" + properties +
                '}';
    }
}
  • Properties本质上也是一个Map集合。

  • Properties的父类Hashtable实现了Map接口。

  • Properties的key和value只能是String类型。

spring-properties.xml



​
    
        
            
                com.mysql.cj.jdbc.Driver
                jdbc:mysql://localhost:3306/spring6
                root
                123456
            
        
    

4.3.8注入null和空字符串


    
    
    
    
        
    
    
    
    
    
    

4.3.9注入的值中含有特殊符号

  • XML中有5个特殊字符,分别是:<、>、'、"、&

  • 以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。

    特殊字符 转义字符
    > >
    < <
    ' '
    " "
    & &

    
    
    
        
        
    

4.4p命名空间注入

  • 目的:简化配置

Dog

package com.hhb.bean;
​
import java.util.Date;
​
public class Dog {
    // 简单类型
    private String name;
    private int age;
    // 非简单类型
    private Date birth;
​
    // p命名空间注入底层还是set注入,只不过p命名空间注入可以让spring配置变的更加简单。
    public void setName(String name) {
        this.name = name;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public void setBirth(Date birth) {
        this.birth = birth;
    }
​
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birth=" + birth +
                '}';
    }
}

spring-p.xml




​
    
    
​
    

4.5c命名空间注入

  • c命名空间是简化构造方法注入的。

People

package com.hhb.bean;
​
public class People {
    private String name;
    private String age;
    private Boolean flag;
​
    //c命名空间是简化构造注入的
    //c命名空间注入办法是基于构造方法的
    public People(String name, String age, Boolean flag) {
        this.name = name;
        this.age = age;
        this.flag = flag;
    }
​
    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", flag=" + flag +
                '}';
    }
}

spring-c.xml




​
    
    
    
    

4.6util命名空间

  • 使用util命名空间可以让配置复用。

MyDataSource1

package com.hhb.jdbc;
​
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.logging.Logger;
​
public class MyDataSource1 implements DataSource {
    private Properties properties;
​
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
​
    @Override
    public String toString() {
        return "MyDataSource1{" +
                "properties=" + properties +
                '}';
    }
​
    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }
​
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }
​
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }
​
    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
​
    }
​
    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
​
    }
​
    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }
​
    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
​
    @Override
    public  T unwrap(Class iface) throws SQLException {
        return null;
    }
​
    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }
}

spring-util.xml




​
    
        com.mysql.cj.jdbc.driver
        jdbc:mysql://localhost:3306/spring
        root
        123
    
​
    
    
        
    
​
    
    
        
    

4.7基于XML的自动装配

  • 都是基于set方法的。

4.7.1根据名称自动装配


    
​
    
    
    

4.7.2根据类型自动装配





4.8Spring引入外部属性配置文件

MyDataSource

package com.hhb.jdbc;
​
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
​
public class MyDataSource implements DataSource {
    private String driver;
    private String url;
    private String username;
    private String password;
​
    public void setDriver(String driver) {
        this.driver = driver;
    }
​
    public void setUrl(String url) {
        this.url = url;
    }
​
    public void setUsername(String username) {
        this.username = username;
    }
​
    public void setPassword(String password) {
        this.password = password;
    }
​
    @Override
    public String toString() {
        return "MyDataSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
​
    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }
​
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }
​
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }
​
    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
​
    }
​
    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
​
    }
​
    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }
​
    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
​
    @Override
    public  T unwrap(Class iface) throws SQLException {
        return null;
    }
​
    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }
}

jdbc.properties

jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=123

spring-properties.xml




​
    
    
​
    
    
        
        
        
        
    

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