代码编织梦想

目录

三. IOC相关内容

3.1 Bean基础配置

3.1.1 bean标签的id与class属性

3.1.2 bean的name属性

3.1.3 bean的scope属性

3.1.4 bean基础配置小结

3.2 Bean实例化

3.2.1 构造方法实例化(默认)

3.2.2 静态工厂实例化

3.2.3 实例工厂实例化

3.2.4 FactoryBean

3.3 bean的生命周期

3.3.1 生命周期概述

3.3.2 生命周期设置

3.3.3 使用close方法关闭容器

3.3.4 注册钩子关闭容器

3.3.5 InitializingBean, DisposableBean接口

四.DI相关内容

4.1 setter注入

4.1.1 注入引用数据类型

4.1.2 注入简单数据类型

4.2 构造器注入

4.2.1 构造器注入引用数据类型

4.2.2 构造器注入多个引用数据类型

4.2.3 构造器注入多个简单数据类型

4.2.4 总结

4.3 自动配置

4.3.1 什么是自动装配

4.3.2 自动装配方式有哪些?

4.3.3 如何进行自动装配

4.3.3 注意事项

4.4 集合注入

4.4.1 注入数组类型数据

4.4.2 注入List类型数据

4.4.3 注入Set类型数据

4.4.4 注入Map类型数据

4.4.5 注入Properties类型数据


三. IOC相关内容

通过前面两个案例,我们已经学习了 bean如何定义配置 DI如何定义配置 以及 容器对象如何获取 的内容,接下来主要是把这三块内容展开进行详细的讲解,深入的学习下这三部分的内容,首先是bean基础配置

3.1 Bean基础配置

3.1.1 bean标签的id与class属性

我们通过一张图来说明bean标签的功能、使用方式。并顺便介绍一下id和class属性的作用,我们通过一张图来描述下

3.1.2 bean的name属性

bean的name属性用来定义别名, 首先通过下面这张图简单了解一下name属性
接下来通过一个案例来具体理解name属性的作用、用法
步骤:
第一步:搭建一个和上面 已经完成Ioc和DI的案例 一样的环境, 接下来就可以在这个环境的基础上来学习下bean的别名配置
第二步:配置别名
打开spring的配置文件applicationContext.xml
​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔-->
    <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>
    <!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype-->
    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
​

第三步:根据name属性获取容器中bean对象

public class AppForName {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//此处根据bean标签的id属性和name属性的任意一个值来获取bean对象
BookService bookService = (BookService) ctx.getBean("service4");
bookService.save();
}
}

步骤3:运行程序

测试结果为:

3.1.3 bean的scope属性

Ioc容器中的bean默认都是单例,如果想要变成非单例,可以通过scope属性改变
1. 通过scope属性将bean设为单例
2.  通过scope属性将bean设为非单例
3. scope使用后续思考
bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象, bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高。表现层对象、 业务层对象、 数据层对象、 工具对象都适合交给Spring容器管理,但 封装实例的域对象,因为会引发线程安全问题,所以不适合交给Spring容器管理。

3.1.4 bean基础配置小结

3.2 Bean实例化

对象已经能交给Spring的IOC容器来创建了,但是容器是如何来创建对象的呢?
实例化bean有三种方式,分别为构造方法实例化、静态工厂实例化,实例工厂实例化。 bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。 基于这个知识点出发,我们来说明spring中bean的三种创建方式

3.2.1 构造方法实例化(默认)

步骤1:准备需要被创建的类

准备一个BookDao和BookDaoImpl类

public interface BookDao {
public void save();
}

public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}

}

步骤2:将类配置到Spring容器

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
​

步骤3:编写运行程序

public class AppForInstanceBook {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();

}
}

步骤4:类中提供构造函数测试

在BookDaoImpl类中添加一个无参构造函数,并打印一句话,方便观察结果。

public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}

}
运行程序,如果控制台有打印构造函数中的输出,说明Spring容器在创建对象的时候也走的是构造函数
步骤5: 将构造函数改成private测试
public class BookDaoImpl implements BookDao {
private BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}

}
运行程序,能执行成功,说明内部走的依然是构造函数,能访问到类中的私有构造方法,显而易见Spring底层用的是反射

步骤6: 构造函数中添加一个参数测试

public class BookDaoImpl implements BookDao {
private BookDaoImpl(int i) {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}

}
运行程序,
程序会报错,说明Spring底层使用的是类的无参构造方法。

3.2.2 静态工厂实例化

接下来研究Spring中的第二种bean的创建方式 静态工厂实例化 :

3.2.2.1 静态工厂方式创建对象

在讲这种方式之前,我们需要先回顾一个知识点是使用工厂来创建对象的方式:
(1)准备一个OrderDao和OrderDaoImpl类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
(2)创建一个工厂类OrderDaoFactory并提供一个==静态方法==
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
return new OrderDaoImpl();
}
}
(3)编写AppForInstanceOrder运行类,在类中通过工厂获取对象
public class AppForInstanceOrder {
public static void main(String[] args) {
//通过静态工厂创建对象
OrderDao orderDao = OrderDaoFactory.getOrderDao();
orderDao.save();
}
}
(4)运行后,可以查看到结果
如果代码中对象是通过上面的这种方式来创建的,如何将其交给Spring来管理呢?

3.2.2.2 静态工厂实例化步骤

这就要用到Spring中的静态工厂实例化的知识了,具体实现步骤为:
(1)在spring的配置文件application.properties中添加以下内容:
   
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
class:工厂类的类全名
factory-mehod:具体工厂类中创建对象的方法名
对应关系如下图:
(2)在AppForInstanceOrder运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceOrder {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");

orderDao.save();

}
}
(3)运行后,可以查看到结果
看到这,可能有人会有疑问,这种方式在工厂类中不也是直接new对象的,和我自己直接new没什么太大的区别,而且静态工厂的方式反而更复杂,这种方式的意义是什么?
主要的原因是:
  • 在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少,如:
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");//模拟必要的业务操作
        return new OrderDaoImpl();
    }
}
之前new对象的方式就无法添加其他的业务内容,重新运行,查看结果:
介绍完静态工厂实例化后,这种方式一般是用来兼容早期的一些老系统,所以==了解为主==。

3.2.3 实例工厂实例化

1. 实例工厂创建对象
(1)准备一个UserDao和UserDaoImpl类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
(2)创建一个工厂类OrderDaoFactory并提供一个普通方法,注意此处和静态工厂的工厂类不一样的地方是方法不是静态方法
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
(3)编写AppForInstanceUser运行类,在类中通过工厂获取对象
public class AppForInstanceUser {
public static void main(String[] args) {
//创建实例工厂对象
UserDaoFactory userDaoFactory = new UserDaoFactory();
//通过实例工厂对象创建对象
UserDao userDao = userDaoFactory.getUserDao();
userDao.save();
}
(4)运行后,可以查看到结果
对于上面这种实例工厂的方式如何交给Spring管理呢?
2. 实例工厂实例化的步骤
第一步:在Spring的配置文件中添加以下内容
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
实例化工厂运行的顺序是:
  • 创建实例化工厂对象,对应的是第一行配置
  • 调用对象中的方法来创建bean,对应的是第二行配置
    • factory-bean:工厂的实例对象
    • factory-method:工厂对象中的具体创建对象的方法名,对应关系如下:
第二步: 从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceUser {
    public static void main(String[] args) {
        ApplicationContext ctx = new
            ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}
第三步: 运行后,可以查看到结果

3.2.4 FactoryBean

实例工厂实例化的方式已经介绍完了,配置的过程还是比较复杂,Spring为了简化 实例工厂实例化, 就提供了一种叫 FactoryBean 的方式来简化开发。
1. FactoryBean的使用 使用步骤
第一步 创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    //返回所创建类的Class对象
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}
第二步:在Spring的配置文件中进行配置
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
第三步:AppForInstanceUser运行类不用做任何修改,直接运行
2.  FactoryBean接口的三个方法
方法一:getObject(),被重写后,在方法中进行对象的创建并返回
T getObject() throws Exception;
方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象
Class<?> getObjectType();
方法三:没有被重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单例,默认true,
default boolean isSingleton() {
        return true;
}

3.3 bean的生命周期

3.3.1 生命周期概述

  • 首先理解下什么是生命周期?
    • 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。
  • bean生命周期是什么?
    • bean对象从创建到销毁的整体过程。
  • bean生命周期控制是什么?
    • 在bean创建后到销毁前做一些事情。

3.3.2 生命周期设置

bean的生命周期控制有两个阶段:
  • bean创建之后,想要添加内容,比如用来初始化需要用到资源
  • bean销毁之前,想要添加内容,比如用来释放用到的资源
第一步: 添加初始化和销毁方法
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    //表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destory...");
    }
}
第二步: 配置生命周期
在Spring配置文件中进行如下配置
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

第三步:运行程序

运行AppForLifeCycle打印结果为:
从结果中可以看出,init方法执行了,但是destroy方法却未执行,这是为什么呢?
  • Spring的IOC容器是运行在JVM中
  • 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行
  • main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了
  • 所以没有调用对应的destroy方法 知道了出现问题的原因,具体该如何解决呢?

3.3.3 使用close方法关闭容器

  • ApplicationContext中没有close方法
  • 需要将ApplicationContext更换成ClassPathXmlApplicationContext
    ClassPathXmlApplicationContext ctx = new
    ClassPathXmlApplicationContext("applicationContext.xml");
  • 调用ctx的close()方法
    ctx.close();
  • 运行程序,就能执行destroy方法的内容

  3.3.4 注册钩子关闭容器

  • 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
  • 调用ctx的registerShutdownHook()方法
      ctx.registerShutdownHook();
    注意: registerShutdownHook在ApplicationContext中也没有
  • 运行后,查询打印结果
两种方式介绍完后,close和registerShutdownHook选哪个?
相同点:这两种都能用来关闭容器
不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。
分析上面的实现过程,会发现添加初始化和销毁方法,即需要编码也需要配置,实现起来步骤比较多也比较乱。

3.3.5 InitializingBean DisposableBean接口

Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置 init-method destroy-method
   步骤:
   第一步:让类实现这二个接口,并重 写接口中 两个方法 afterPropertiesSet destroy
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}
 第二步:重新运行AppForLifeCycle类

四.DI相关内容

4.1 setter注入

4.1.1 注入引用数据类型

步骤一:在类中声明属性并提供setter方法
public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    private UserDao userDao;
    
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
}

步骤二: 配置文件中进行注入配置

在applicationContext.xml配置文件中使用property标签注入

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
​

步骤三:运行AppForDISet类,查看结果,说明userDao已经成功注入。

4.1.2 注入简单数据类型

步骤一:声明属性并提供setter方法

在BookDaoImpl类中声明对应的简单数据类型的属性,并提供对应的setter方法

public class BookDaoImpl implements BookDao {

private String databaseName;
private int connectionNum;

public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}

public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}

public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}

步骤2:配置文件中进行注入配置

在applicationContext.xml配置文件中使用property标签注入

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="10"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
​
说明:
value:后面跟的是简单数据类型,对于参数类型,Spring在注入的时候会自动转换,但是不能写成
   <property name="connectionNum" value="abc"/>
这样的话,spring在将 abc 转换成int类型的时候就会报错。

 

步骤3:运行程序

运行AppForDISet类,查看结果,说明userDao已经成功注入。

注意: 两个property注入标签的顺序可以任意。

4.2 构造器注入

4.2.1 构造器注入引用数据类型

步骤1:删除setter方法并提供构造方法

在BookServiceImpl类中将bookDao的setter方法删除掉,并添加带有bookDao参数的构造方法

public class BookServiceImpl implements BookService{
private BookDao bookDao;

public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}

public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}

步骤2:配置文件中进行配置构造方式注入

在applicationContext.xml中配置

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
​
说明:
标签 <constructor-arg>
  • name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。
  • ref属性指向的是spring的IOC容器中其他bean对象。

  步骤3:运行程序

运行AppForDIConstructor类,查看结果,说明bookDao已经成功注入。

4.2.2 构造器注入多个引用数据类型

步骤1:提供多个属性的构造函数

 在BookServiceImpl声明userDao并提供多个参数的构造函数

public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;

public BookServiceImpl(BookDao bookDao,UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}

public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}

步骤2:配置文件中配置多参数注入

在applicationContext.xml中配置注入

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>
​

说明:这两个<contructor-arg>的配置顺序可以任意 

步骤3:运行程序

运行AppForDIConstructor类,查看结果,说明userDao已经成功注入。

4.2.3 构造器注入多个简单数据类型

步骤1:添加多个简单属性并提供构造方法

修改BookDaoImpl类,添加构造方法

public class BookDaoImpl implements BookDao {
    private String databaseName;
    private int connectionNum;
​
    public BookDaoImpl(String databaseName, int connectionNum) {
        this.databaseName = databaseName;
        this.connectionNum = connectionNum;
    }
​
    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}

步骤2:配置完成多个属性构造器注入

在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 http://www.springframework.org/schema/beans/spring-beans.xsd">
​
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg name="databaseName" value="mysql"/>
        <constructor-arg name="connectionNum" value="666"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
</beans>

说明:这两个<contructor-arg>的配置顺序可以任意

步骤3:运行程序

运行AppForDIConstructor类,查看结果

上面已经完成了构造函数注入的基本使用,但是会存在一些问题:

  • 当构造函数中方法的参数名发生变化后,配置文件中的name属性也需要跟着变

  • 这两块存在紧耦合,具体该如何解决?

在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,大家都以了解为主。

方式一:删除name属性,添加type属性,按照类型注入

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <constructor-arg type="int" value="10"/>
    <constructor-arg type="java.lang.String" value="mysql"/>
</bean>
  • 这种方式可以解决构造函数形参名发生变化带来的耦合问题

  • 但是如果构造方法参数中有类型相同的参数,这种方式就不太好实现了

方式二:删除type属性,添加index属性,按照索引下标注入,下标从0开始

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <constructor-arg index="1" value="100"/>
    <constructor-arg index="0" value="mysql"/>
</bean>
  • 这种方式可以解决参数类型重复问题

  • 但是如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题

介绍完两种参数的注入方式,具体我们该如何选择呢?

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现

    • 强制依赖指对象在创建的过程中必须要注入指定的参数

  2. 可选依赖使用setter注入进行,灵活性强

    • 可选依赖指对象在创建过程中注入的参数可有可无

  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨

  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入

  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入

  6. ==自己开发的模块推荐使用setter注入==

4.2.4 总结

这节中主要讲解的是Spring的依赖注入的实现方式:

  • setter注入

    • 简单数据类型

      <bean ...>
          <property name="" value=""/>
      </bean>
    • 引用数据类型

      <bean ...>
          <property name="" ref=""/>
      </bean>
  • 构造器注入

    • 简单数据类型

      <bean ...>
          <constructor-arg name="" index="" type="" value=""/>
      </bean>
    • 引用数据类型

      <bean ...>
          <constructor-arg name="" index="" type="" ref=""/>
      </bean>
  • 依赖注入的方式选择上

    • 建议使用setter注入

    • 第三方技术根据情况选择

4.3 自动配置

自动配置可以简化Spring的依赖注入

4.3.1 什么是自动装配

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

4.3.2 自动装配方式有哪些?

  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启用自动装配

4.3.3 如何进行自动装配

自动装配只需要修改applicationContext.xml配置文件即可
​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="com.itheima.dao.impl.BookDaoImpl"/>
    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
</beans>
​
注意:
  • 需要注入属性的类中对应属性的setter方法不能省略
  • 被注入的对象必须要被Spring的IOC容器管理
  • 按照类型在Spring的IOC容器中如果找到多个对象,会报 NoUniqueBeanDefinitionException
一个类型在IOC中有多个对象,还想要注入成功,这个时候就需要按照名称注入,配置方式为:
​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="Index of /schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byName"/>
</beans>
​

4.3.3 注意事项

按照名称注入中的名称指的是什么?
  • bookDao是private修饰的,外部类无法直接方法
  • 外部类只能通过属性的set方法进行访问
  • 对外部类来说,setBookDao方法名,去掉set后首字母小写是其属性名
    • 为什么是去掉set首字母小写?
    • 这个规则是set方法生成的默认规则,set方法的生成是把属性名首字母大写前面加set形成的方法名
  • 所以按照名称注入,其实是和对应的set方法有关,但是如果按照标准起名称,属性名和set对应的名是一致的
  • 如果按照名称去找对应的bean对象,找不到则注入Null
  • 当某一个类型在IOC容器中有多个对象,按照名称注入只找其指定名称对应的bean对象,不会报错
两种方式介绍完后,以后用的更多的是==按照类型==注入。
最后对于依赖注入,需要注意一些其他的配置特征:
  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

4.4 集合注入

前面我们已经能完成引入数据类型和简单数据类型的注入,但是还有一种数据类型==集合==,集合中既可以装简单数据类型也可以装引用数据类型

常见的集合类型有:
  • 数组
  • List
  • Set
  • Map
  • Properties
针对不同的集合类型,该如何实现注入呢?

4.4.1 注入数组类型数据

<property name="array">
        <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
        </array>
</property>

4.4.2 注入List类型数据

<property name="list">
        <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>chuanzhihui</value>
        </list>
</property>

4.4.3 注入Set类型数据

<property name="set">
        <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>boxuegu</value>
        </set>
</property>

4.4.4 注入Map类型数据

<property name="map">
        <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="kaifeng"/>
        </map>
</property>

4.4.5 注入Properties类型数据

<property name="properties">
        <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
        </props>
</property>

配置完成后,运行下看结果:

说明:

  • property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写 <array> <list> <set> <map> <props> 标签
  • List的底层也是通过数组实现的,所以 <list> <array> 标签是可以混用
  • 集合中要添加引用类型,只需要把 <value> 标签改成 <ref> 标签,这种方式用的比较少
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_59749089/article/details/128842201

spring常见面试题总结(超详细回答)_张维鹏的博客-爱代码爱编程_spring面试题

1、Spring是什么? Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。主要包括以下七个模块: Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);Spring Core:核心类库,所有功能

springcloud与dubbo的比较_程序大视界的博客-爱代码爱编程_dubbo和spring cloud区别

目录 Dubbo 一、dubbo简介 二、dubbo组织架构图 三、dubbo的优势 SpringCloud 一、SpringCloud简介 二、SpringCloud组织架构 三、SpringCloud特点 Dubbo与SpringCloud的比较 二、整体比较 Dubbo 一、dubbo简介 Dubbo是阿里巴巴公司开源

关于Spring中的一级缓存、二级缓存、三级缓存那些事-爱代码爱编程

题记 常常听到别人提起:“一级缓存、二级缓存、三级缓存”。那么它们是什么呢?有什么作用呢? 缓存作用分析 Spring中的一级缓存名为singletonObjects,二级缓存名为earlySingletonObjects,三级缓存名为singletonFactories,除了一级缓存是ConcurrentHashMap之外,二级缓存和三级缓存都是H

Spring框架(二)——SpringTest-爱代码爱编程

SpringTest是Spring框架用来做单元测试的工具。使用SpringTest需要结合Junit一起使用。 目录 一、环境准备1.1 导入jar包1.2 编写测试类二、相关注解三、零配置(无配置文件)四、常见异常4.1 org.springframework.util.Assert.notNull(Ljava/lang/Object;Ljava

Spring框架详解-爱代码爱编程

简介 Spring5框架 内容介绍: 1.Spring概念 2.IOC容器 3.Aop 4.JDBCTEmplate 5.事物管理 6.Spring5新特性 一.Spring框架概述 1.概述 1.Spring框架是轻量级的JavaEE框架 2.Spring可以解决企业应用开发的复杂性 3.Spring有两个核心部分:IOC和Ao

springcloud tencent 全套解决方案_叶秋学长的博客-爱代码爱编程

Spring Cloud Tencent 是什么? Spring Cloud Tencent 是腾讯开源的一站式微服务解决方案。Spring Cloud Tencent 实现了 Spring Cloud 标准微服务 SPI,开发者可以基于 Spring Cloud Tencent 快速开发 Spring Cloud 微服务架构应用。Spring Clou