从IoC容器中获取Bean

说明:

(1)在前三篇博客中,介绍三种创建对象的方式;本篇博客就介绍如何从IoC容器中提取对象;

(2)然后,本篇博客也附带介绍了<bean标签的id属性和name属性;


从IoC容器中获取Bean

简介

说明:

(1) 很容易理解,直接根据对象的标识,从IoC容器中去获取对象就可以了;

示例


<bean>中【id属性】和【name属性】

【id属性】和【name属性】相同点和区别简介

(1) 本质上来说,【id属性】和【name属性】是一样的;

(2) 无论如何,在一个配置文件中是不允许重复

(3) 如果当前工程有多个配置文件,在不同的配置文件中允许重复;而且,后创建的对象会覆盖IoC容器中先创建的那个对象;

(1) 见【2.【id属性】和【name属性】演示】中的【演示2】

【id属性】和【name属性】演示

演示1: 如果当前工程有多个配置文件,在不同的配置文件中允许重复;而且,后创建的对象会覆盖IoC容器中先创建的那个对象;

比如这儿有多个配置文件:

…………………………

说明:

(1) (PS:意外收获:【ClassPathXmlApplicationContext()】方法的参数是可变参数;)

演示2:name属性,可以定义多个对象标识


id属性,建议只写一个对象标识


说明:在绝大部分情况下,一个对象有一个标识就够了;所以,一般我们优先选用【id属性】;

Spring的<bean允许,既没有【id属性】也没有【name属性】的; (很少遇到,作一般性了解)

这种情况,在日常开发中很少遇到,仅作一般性了解;

路径表达式用法

说明:

(1) 本篇博客的内容是:路径表达式的内容;包括【加载单个配置文件】、【加载多个配置文件】、【当前类路径是什么意思】、【路径表达式的几种写法】

(2) 本篇文章还有一个问题尚未解决:路径表达式中,如何以相对路径的方式,访问在包中的配置文件。也就是,IDEA如何设置访问相对路径下的文件,这个问题暂时搁置

路径表达式:加载单个配置文件

【当前类路径】是程序编译后的路径

路径表达式:使用数组、加载多个配置文件

类路径表达式的几种写法

(0) 上面的config.xml就是指代applicationContext.xml;

(1)class:config.xml

(2)classpath:com/imooc/config

……………………………………………………

这儿还有疑问? 遇到未解决的问题??????????? 这个问题暂时搁置吧~~

这是因为: idea默认不会把.java下的xml配置文件转移到生成的target中。也就是说上述文件读取需要使用如下绝对路径:注意:前面需要加上file:


(3)classpath*:com/imooc/config.xml

这个的意思是:去扫描【所有jar包】和【自己工程中,com.imooc包】中的名字是conifig.xml的文件

(4)classpath:config-*.xml

意思是:扫描classes根路径下,名字为config开头的xml文件;

由此衍生的一个问题:前面在介绍<bean的id和name属性时,介绍过遇到多个配置文件时,后加载创建的对象会覆盖掉之前创建的对象;那么按照这种通配符的写法,如果遇到多个config开头的xml文件时,先加载哪个嘞?:其是按照文件名ASCII码的顺序加载,比如有configa.xml和configb.xml;那么会先加载configa.xml;

从这个通配符的写法、可以加载多个配置文件的例子可知:我们配置文件的命名最好有一定规则;自然,在一般情况下,也要尽量保持所有配置文件中的<bean的id或name都是唯一的;因为,只要<bean的id或name都是唯一的,无论配置文件加载顺序如何,都不会出现对象覆盖的问题了;

(5)classpath:com//config.xml

意思是:扫描com包下,任何子包中的名为config.xml的文件;

很少使用这种路径表达式,因为扫描范围太大了;在通常情况,会使用一个单独的目录来专门保存所有的配置文件;

(6)file:c:/config.xml

意思是:扫描本地磁盘C盘下,名字为config.xml的文件;

这种路径表达式很少使用;

利用setter实现对象依赖注入

说明:

(1) Spring IoC容器则通过配置的方式,完成了【对象实例化】和【对象与对象之间的依赖关系】;从而,可以解决传统编码方式的不足;

(2) 在前面,介绍的是【对象的实例化】;即,在IoC容器中,实例化单个Bean;然后,在前面几篇中,介绍【对象实例化】的时候,这些类的属性都是基本数值类型,所以,比如前面在实例化如Apple对象的时候,也不把这些基本数值类型的属性看成是对象,即也不认为在实例化Apple对象的时候蕴含了【对象与对象之间的依赖关系】;

(3) 然后,接下来就介绍,如何在Spring IoC容器中设置【对象与对象之间的依赖关系】;这个过程称之为依赖注入;在这儿,比如,我们把类中的基本数值类型也看成是对象了;

(4) 【对象依赖注入】有两种方式:基于setter方法注入对象,和基于构造方法注入对象;本篇博客介绍基于setter方法注入对象;

(5)【基于setter方法注入对象】其过程就是,先通过无参构造获取对象,然后调用对应的setter方法给对象的属性赋值,完成对象的初始化;


一:对象依赖注入:引入

可以看到,要实现“小孩吃苹果”这个操作,Child类对象就要依赖于Apple类对象;但是基于IoC容器的理念,不是在Child对象中new一个Apple对象,而是由IoC容器,将Child对象和Apple对象创建好了之后,再动态的进行依赖注入;依赖注入,说白了就是将两个对象关联起来;

二:对象依赖注入:这儿介绍对象依赖注入的第一种方式【基于setter方法注入对象】

(1)【对象依赖注入】有两种方式:基于setter方法注入对象,和,基于构造方法注入对象;

(2)基于setter方法注入对象:这是日常开发中常用的方式;

(3)基于setter方法注入对象:其有两种使用场景;

1.基于setter方法注入对象:第一种使用场景:静态数值注入:直接给Apple对象的如String、float等属性赋值;

这种场景最重要的是要理解:一些基本数据类型的属性(比如,String,float,int),给这些属性赋值的时候,也算是对象依赖注入,因为这些基本数据类型都有对应的包装类;

(1)一个标准的范例

创建一个maven项目:s03:

创建两个演示用的类:Apple类和Child类:

Apple类:

package com.imooc.spring.ioc.entity;
 
 public class Apple {
     private String title; //标签、品种
     private String color; //颜色
     private String origin; //产地
 
     public Apple() {
     }
 
     public Apple(String title, String color, String origin) {
         this.title = title;
         this.color = color;
         this.origin = origin;
     }
 
     public String getTitle() {
         return title;
     }
 
     public void setTitle(String title) {
         this.title = title;
     }
 
     public String getColor() {
         return color;
     }
 
     public void setColor(String color) {
         this.color = color;
     }
 
     public String getOrigin() {
         return origin;
     }
 
     public void setOrigin(String origin) {
         this.origin = origin;
     }
 }

说明:

(1) Apple类没什么好说的,只是一个简单的javaBean;

(2) 强调一下,Apple类的属性都是private的,然后可以通过setter方法来给这些属性赋值;

Child类:

package com.imooc.spring.ioc.entity;
 
 public class Child {
     private String name; //小孩名字
     private Apple apple; //小孩吃到的苹果
 
     public Child() {
     }
 
     public Child(String name, Apple apple) {
         this.name = name;
         this.apple = apple;
     }
 
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this.name = name;
     }
 
     public Apple getApple() {
         return apple;
     }
 
     public void setApple(Apple apple) {
         this.apple = apple;
     }
 
     public void eat() {
         System.out.println(name + "吃到了" + apple.getOrigin() + "种植的" +apple.getTitle());
}
}

说明:

(1) Child类没什么好说的,只是一个简单的javaBean;

(2) 强调一下,Child类的属性都是private的,然后可以通过setter方法来给这些属性赋值;

然后,在pom文件中,引入Spring Framework的依赖;

然后,在resources目录下创建Spring配置文件:applicationContext.xml:

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 id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
<property name="title" value="红富士"/>
<property name="color" value="红色"/>
<property name="origin" value="欧洲"/
 </bean>
</beans>

说明:

(1) 使用诸如【<property name=“title” value=“红富士”/】的方式时,是通过调用对应的setter方法来完成对象的实例化的;

创建程序入口类,去IoC容器中获取对象,测试:

SpringApplication类:

package com.imooc.spring.ioc;
 
 import com.imooc.spring.ioc.entity.Apple;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringApplication {
     public static void main(String[] args) {
         ApplicationContext context = new
         ClassPathXmlApplicationContext("classpath:applicationContext.xml");
          Apple sweetApple = context.getBean("sweetApple", Apple.class);
        System.out.println(sweetApple.getTitle());
}
}

说明:

(1) 为了验证,其确实是通过调用setter方法来给属性赋值的,在Apple类的setter方法中,输出点东西:

(2) 在Apple类的无参构造中,输出一点内容:用以说明,【利用setter实现对象依赖注入】来创建对象的时候,其是【先使用无参构造创建对象,然后再使用setter方法给对象属性赋值】的;

(3) 运行结果:说明IoC容器在实例化Apple对象的时候,发现诸如【<property name=“title” value=“红富士”/】后,是通过对应的setter方法,来给当前对象的属性赋值的;

(2)一种错误的情况:比如,此时在Apple类中增加一个price属性,但是不添加该属性的setter方法:

如果,此时在applicationContext.xml中,也通过【<property name=“price” value=“20.7”/】去给Apple对象的price属性赋值的时候:

但是,不管这个报错,如果强制执行嘞?

报错信息部分摘录:

Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'price' of bean class [com.imooc.spring.ioc.entity.Apple]: Bean property 'price' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

解决办法,就是在Apple类中加上price属性的setter方法;

(3)然后,说明一点:IoC容器也会自动把【可以强转为数字的字符串】转为【对应的数字类型】


但是,在日常开发中,一个类中,并不是所有的属性都是静态数值。(自然,不能否认,在这儿静态数值有对应的包装类,其也可以看成是对象啦)


接上

2.基于setter方法注入对象:第二种使用场景:一般意义上的对象的注入:给Child对象的Apple属性赋值;

(1)一个标准范例

在applicationContext.xml中配置一个Child对象:

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 id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
         <property name="title" value="红富士"/>
         <property name="color" value="红色"/>
         <property name="origin" value="欧洲"/>
         <property name="price" value="20.4"/>
     </bean>
     <bean id="lily" class="com.imooc.spring.ioc.entity.Child"
         <property name="name" value="莉莉"/>
         <property name="apple" ref="sweetApple"/>
     </bean>
 </beans>

说明:

(1) 啰嗦一下,两个对应的说明

在程序入口类SpringApplication类中,去IoC容器中获取对象,测试:

package com.imooc.spring.ioc;
 
 import com.imooc.spring.ioc.entity.Apple;
 import com.imooc.spring.ioc.entity.Child;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringApplication {
     public static void main(String[] args) {
         ApplicationContext context = new
ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Child lilyChild = context.getBean("lily", Child.class);
}
}

说明:

(1) 为了更好的看到对象的创建过程,这儿在Child的无参构造中打印一点东西;在Child的setName()方法和setApple()方法中打印一点东西;

(2) 运行结果


3.Summary

IoC在项目中的重要用途

说明:

(1) 一个案例:说明如何使用IoC容器,来使软件过程中的对象解耦,进而让软件团队成员协作之间也出现解耦;

(2) 通过这个案例,能够体验,通过使用spring框架,能够实现【对象之间的解耦】,从而可以实现【人与人之间的解耦】,最终目的是【大幅度提升项目的开发效率】;

(3) 这篇博客中的内容比较简单,就是【在开发一个大型软件时,开发不同模块的人可以维护不同的applicationContext.xml,实现对象之间的解耦,从而实现人与人之间的解耦】,但这种思想十分重要!

(4)这篇博客长期意义不是太大,仅仅看下就行,因为后面会在实际项目中更加规范、细致、完整地演示spring的应用。


一:案例演示

1.准备一个演示用项目:s04

为了演示,创建一个新的工程s04:

然后,引入spring Framework的依赖:

然后,创建spring配置文件:

说明:

(1) 为什么要创建两个配置文件?

这是出于项目管理的目的;在一个团队中,往往有技术好的人,有技术差点的人;Dao,实现数据库的增删改查,这是比较简单的,这部分工作可以交给初级程序员去开发;Service,是系统中最核心的实现代码,这部分需要交给中高级程序员去开发;开发Dao的初级程序员和开发Service的中高程序员,各维护一个配置文件好点,这样以后,每个人只负责自己的模块就行,可以减少工作上的交叉;

2.创建对应的类

dao包中的BookDao接口:

package com.imooc.spring.ioc.bookshop.dao;
 
 public interface BookDao {
     /**
      * 向book表中,插入一条数据;
      */
     public void insert();
 }

dao包中的BookDaoImpl(Impl表示,这是BookDao接口的实现类):

package com.imooc.spring.ioc.bookshop.dao;
 
 public class BookDaoImpl implements BookDao{
 
     /**
      * 向book表中,插入一条数据;
      */
     public void insert() {
         System.out.println("向book表插入一条数据;");
     }
 }

说明:

(1) 这个类只是演示用的,只打印了一句话;

service包中的BookService类:

package com.imooc.spring.ioc.bookshop.service;
 
 import com.imooc.spring.ioc.bookshop.dao.BookDao;
 
 public class BookService {
     private BookDao bookDao;
     /**
      * 采购一个本新的图书(当一般图书被采购后,自然就需要向book表中新增一条数据)
      */
     public void purchase(){
         System.out.println("正在执行图书采购业务方法;");
         bookDao.insert();
     }
 
     public BookDao getBookDao() {
         return bookDao;
     }
 
     public void setBookDao(BookDao bookDao) {
         this.bookDao = bookDao;
     }
 }

说明:

(1) service中需要调用dao中的方法;所以,在service类中需要有dao的对象,自然后面,我们使用的spring IoC的方式去注入【BookDao类型的对象的,这个属性】;

3.在application配置文件中去设置IoC容器中的对象

在application中去配置对象:

applicationContext-dao.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 id="bookDao"
class="com.imooc.spring.ioc.bookshop.dao.BookDaoImpl">
 
     </bean>
 </beans>

说明:

(1) 啰嗦一点

applicationContext-service.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 id="bookService"
class="com.imooc.spring.ioc.bookshop.service.BookService">
      <property name="bookDao" ref="bookDao"/>
     </bean>
 </beans>

说明:

(1) 因为在service对象中,需要用到BookDao类型的对象,自然去设置BookService类中的bookDao属性就可以啦;

(2) 在applicationContext-service.xml中直接去ref引用applicationContext-dao.xml中的bean其会报错(可能是IDEA版本比较老的问题);设置一下就OK了;( _ _ PS:这个问题,比较好的、一劳永逸式的设置方式尚不清楚???__ )

4.创建程序入口类,测试

创建程序入口类BookShopApplication类,去测试:

package com.imooc.spring.ioc.bookshop;
 
import com.imooc.spring.ioc.bookshop.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 
/**
 
* 应用程序入口类
  */
  public class BookShopApplication {
  public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-*.xml");
BookService bookService = context.getBean("bookService",
BookService.class);
bookService.purchase();
}
}

说明:

(1) 运行结果


二:Summary

1.一个案例

需求: 比如,这个系统要更换数据库,把MySQL数据库换成Oracle数据库;

策略:

(1) 编写Oracle的Dao

由于Mysql和Oracle在底层语法上存在不同,所以为此,Dao部分需要重新编写,由于前面编写了BookDao接口,为了应对Oracle的需求,只需要写一个实现了BookDao接口的面向Oracle的实现类就好了;

(2) 在applicationContext-dao.xml中将bookDao那个<bean的class更换为新编写的Oracle的dao类

这样就OK了。

(3) 再次运行的结果:

(4) 之所以dao部分修改了,service部分不会报错的原因是:我们已经定义了BookDao接口,无论是MySQL数据库的实现Dao类,还是Oracle数据库的实现Dao都实现了相同的接口,所以,在IoC容器注入的时候,并不会因为实现类发生了变化,而产生无法注入的情况;

2.Conclusion

可以看到,这儿很明确的实现了对象与对象之间的解耦,进而可以实现人和人的工作实现了解耦;即,正是由于对象之间解耦了,所以工作的方式也产生了变化,由【原先的多人协商才能决定一个事情】变成了【两个人之间约定一个<bean就可以了】;这种变化,对于大型软件更加重要,可以节约大量的时间等成本。也可以看到,spring框架之所以在实际中会被大规模商用的原因;也能了解到,为什么spring框架比其他框架都显得更为重要的原因;

利用构造方法实现对象依赖注入

说明:

(1) 上面介绍了使用setter方法注入对象;本篇博客就介绍使用构造方法注入对象;

(2) 基于【带参构造方法】实例化对象;]中的使用构造方法来实例化对象】非常相似,只是传入的信息由静态的数值变成了动态引入的对象;


一:利用构造方法实现对象依赖注入

继续基于【[利用setter实现对象依赖注入]】中的s03工程:

基于【构造方法实现对象依赖注入】的方式,在applicationContext.xml中增加对应的 <bean>:

为了方便观察效果,在Child类的有参构造中输出一点内容:

运行结果:

可以看到,此时是通过带参构造的方式去实现对象依赖注入的:

分析:传值过程


二:Phased summary

(1) 这么多创建对象的方式,还好,很简单;

(2) 要想实现某种功能,按照Spring的SOP去做就行;

(3) 自然,底层都是Spring框架在支撑;为了能够更好的理解其背后的原理,就能感到适当、适时阅读Spring源码的必要性;

注入集合对象

本篇博客内容: 如果类的一个属性是集合时,如何注入这个集合对象?本篇博客就是介绍这些内容;

说明:

(1) 注入集合对象还是比较常用的;

(2) 在可以使用【value-ref】或者【ref】的地方,都可以支持内置<bean>;


为了方便后面演示,创建一个基于maven的项目s05;

readme.md:项目说明文档

通过“公司资产配置清单”案例学习集合类型的注入

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
 
<groupId>com.imooc.spring</groupId>
<artifactId>s05</artifactId>
<version>1.0-SNAPSHOT</version>
 
<repositories>
  <repository>
      <id>aliyun</id>
      <name>aliyun</name>
      <url>https://maven.aliyun.com/repository/public</url>
  </repository>
</repositories>
 
<dependencies>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.9</version>
  </dependency>
</dependencies>
 
 
</project>

说明:

(1) 没什么好说的,就是设置国内maven仓库;引入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">
 </beans>

说明:

(1) 就是xml的文档说明;spring配置文件的schema约束;

Computer类:一个简单的bean

package com.imooc.spring.ioc.entity;
 
 public class Computer {
     private String brand; //计算机品牌
     private String type; //计算机类型,台式机或是笔记本
     private String sn; // 计算机的序列号
     private Float price; //计算机价格
 
     public Computer() {
     }
 
     public Computer(String brand, String type, String sn, Float price) {
         this.brand = brand;
         this.type = type;
         this.sn = sn;
         this.price = price;
     }
 
     public String getBrand() {
         return brand;
     }
 
     public void setBrand(String brand) {
         this.brand = brand;
     }
 
     public String getType() {
         return type;
     }
 
     public void setType(String type) {
         this.type = type;
     }
 
     public String getSn() {
         return sn;
     }
 
     public void setSn(String sn) {
         this.sn = sn;
     }
 
     public Float getPrice() {
         return price;
     }
 
     public void setPrice(Float price) {
         this.price = price;
     }
 
     @Override
     public String toString() {
         return "Computer{" +
                 "brand='" + brand + '\'' +
                 ", type='" + type + '\'' +
                 ", sn='" + sn + '\'' +
                 ", price=" + price +
                 '}';
     }
 }

说明:

(1) 一个简单点bean没什么好说的;注意使用IDEA工具自动生成getter与setter方法,还有重写toString方法便于演示

Company类:一个简单的bean

package com.imooc.spring.ioc.entity;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 public class Company {
     private List<String rooms; //公司有哪些房间
     private Set<String rooms1;
     private Map<String, Computer computers;//公司有哪些电脑
     private Properties info;//公司基础的信息
 
 
     public List<String getRooms() {
         return rooms;
     }
 
     public void setRooms(List<String rooms) {
         this.rooms = rooms;
     }
 
     public Set<String getRooms1() {
         return rooms1;
     }
 
     public void setRooms1(Set<String rooms1) {
         this.rooms1 = rooms1;
     }
 
     public Map<String, Computer getComputers() {
         return computers;
     }
 
     public void setComputers(Map<String, Computer computers) {
         this.computers = computers;
     }
 
     public Properties getInfo() {
         return info;
     }
 
     public void setInfo(Properties info) {
         this.info = info;
     }
 
     @Override
     public String toString() {
         return "Company{" +
                 "rooms=" + rooms +
                 ", rooms1=" + rooms1 +
                 ", computers=" + computers +
                 ", info=" + info +
                 '}';
     }
 }

说明:

(1) Company类的属性是集合类型,以便后面演示如何注入集合类型对象;

SpringApplication类:程序入口类

package com.imooc.spring.ioc;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringApplication {
     public static void main(String[] args) {
         ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
}
}

一:List

案例:

在applicationContext.xml中定义 <bean>:

说明:

(1) 这儿是通过<property来设置的属性,即也就是使用setter方法实现的依赖注入;


运行结果:


List在传递过程中,类型的变化:


List的特点是允许出现重复的:


二:Set

案例:

在applicationContext.xml中定义 <bean>:


运行结果:


Set在传递过程中,类型的变化:

这是因为:


三:Map:

案例:

在applicationContext.xml中定义 <bean>:


运行结果:


问题与不足:

解决办法:在可以使用【value-ref】或者【ref】的地方,都可以支持内置<bean,如下:


Map在传递过程中,类型的变化:


四:Properties

与Map类似,Properties也是键值对,只是Properties的键值均要求是String;所以,在日常开发中,常用Properties保存一些静态的文本数据,如登陆时密码用户名这些;

关于Properties的详细内容,去参考jdk文档中有关properties的介绍就可以啦。

案例:

在applicationContext.xml中定义 <bean>:


运行结果:


Properties在传递过程中,类型的变化:

查看容器内对象

说明:

(1) 如何查看容器内有多少个对象?

前面介绍了如何在容器内创建对象和设置对象之间的关系;但是,所有这些信息,都是我们自动脑补去想象的;如果一个项目足够大,对象很多,单靠去想就很吃力,那么我们如何知道当前容器中到底有哪些对象,这些对象又是什么类型的呐?

(2)主要内容包括: 【context.getBeanDefinitionNames()】:获取容器中所有id的数组;【context.getBean(beanName).getClass().getName()】获取bean的类型;【context.getBean(beanName).toString()】:获取bean的具体内容;


1.为了演示:在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 id="c1" class="com.imooc.spring.ioc.entity.Computer">
<constructor-arg name="brand" value="联想"/>
<constructor-arg name="type" value="台式机"/>
<constructor-arg name="sn" value="8389283012"/>
<constructor-arg name="price" value="3085"/>
</bean>
 
<bean class="com.imooc.spring.ioc.entity.Computer">
    <constructor-arg name="brand" value="戴尔"/>
    <constructor-arg name="type" value="台式机"/>
    <constructor-arg name="sn" value="8389283012"/>
    <constructor-arg name="price" value="3085"/>
</bean>
 
<bean class="com.imooc.spring.ioc.entity.Computer">
    <constructor-arg name="brand" value="宏碁"/>
    <constructor-arg name="type" value="台式机"/>
    <constructor-arg name="sn" value="8389283012"/>
    <constructor-arg name="price" value="3085"/>
</bean>
 
<bean id="c2" class="com.imooc.spring.ioc.entity.Company">
    <property name="computers">
        <map>
            <entry key="dev-88172" value-ref="c1"/>
            <entry key="dev-88173">
                <bean class="com.imooc.spring.ioc.entity.Computer">
                    <constructor-arg name="brand" value="联想"/>
                    <constructor-arg name="type" value="笔记本"/>
                    <constructor-arg name="sn" value="1280258012"/>
                    <constructor-arg name="price" value="5060"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>
 
<bean id="c3" class="com.imooc.spring.ioc.entity.Company">
    <property name="info">
        <props>
            <prop key="phone">12345678</prop>
            <prop key="address">XX街XX号</prop>
            <prop key="website">http://baidu.com</prop>
        </props>
    </property>
</bean>
 
</beans>

说明:

(0) 在applicationContext.xml中写了很多种<bean,其目的就是尽可能的为【后面的演示】提供不同情况的<bean;

(1) 在【【id属性】和【name属性】的区别;】就已经介绍过,一个<bean>可以没有id或name;所以,这儿也在applicationContext.xml中添加了没有id或name的匿名<bean>;

(2) 因为【在可以使用【value-ref】或者【ref】的地方,都可以支持内置<bean】,所以这儿也添加了一个内置的<bean;


2.编写入口类:查看容器中的对象

SpringApplication类:

package com.imooc.spring.ioc;
 
import com.imooc.spring.ioc.entity.Company;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
 
        //获取当前容器中,所有beanId的数组;
        String[] beanNames = context.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            System.out.println(beanName);
            System.out.println("对象类型是:" + context.getBean(beanName).getClass().getName());
            System.out.println("对象内容是:" + context.getBean(beanName).toString());
            System.out.println("=======================");
        }
    }
}

说明:

(1) 【context.getBeanDefinitionNames()】:获取容器中所有<bean id>的数组;


可以发现,那些没有写id或name的匿名<bean>也是有的,而且都保留了,(经过实测,即使是这两个对象<bean>完全一样)不存在覆盖的情况;


然后,可以发现,在IoC容器中,那个内置<bean>并没有对应的beanId;


(2) 对于那些没有写id或name的匿名<bean,如何获取?

在【<bean>标签【id属性】和【name属性】的区别】已知,要获取一个匿名<bean>,需要使用类的全路径,那么对于一个类有多个匿名<bean>的情况,又如何获取我们想要的<bean>嘞?

要想获取指定的bean就需要带上后面的【#+数字了】

其实,由于这种具体的对象和其在applicationContext.xml中书写<bean的顺序有关,而这是非常容易搞错的,比较难维护,所以在实际中匿名<bean使用的并不多;


(3)【context.getBean(beanName).getClass().getName()】获取bean的类型


(4)【context.getBean(beanName).toString()】:获取bean的具体内容