Spring入门 --- IOC

配置环境

我们在开发中,会写很多的类,而有些类之间不可避免的产生依赖关系,这种依赖关系称之为耦合。有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的。请看下面的示例代码:

1 创建maven工程;

2 导入必要的依赖

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

2.1 引入log4j的配置文件

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout

3 创建UserDao接口

public interface UserDao {
   void save();
}

4 创建UserDao接口的实现类UserDaoImpl

public class UserDaoImpl implements UserDao {

   @Override
   public void save() {
      System.out.println("持久层:用户保存...");
   }

}

5 创建 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="userDao" class="cn.cosco.impl.UserDaoImpl"></bean>

</beans>

6 创建测试类

 	@Test
    public void test1(){
        //创建Spring工厂(创建IOC容器)
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");//1
        UserDao userDao  = (UserDao) ac.getBean("userDao");//2
        userDao.save();
    }

测试结果:

控制台输出如下结果:

持久层:用户保存...

测试发现:我们可以从spring容器中获取对象,但是,这个对象是如何创建出来的呢?

这其实是利用了 Spring IOC 方法。

Spring IOC

1 什么是 Spring IOC

IOC,它是Inverse of Control的缩写,中文含义是控制反转,表示将对象的创建权力反转给Spring框架!!

IOC解决的问题:使用IOC可以解决的程序耦合性高的问题!!

2 Spring中的工厂

在spring中提供了两个工厂接口:

1、ApplicationContext

2、BeanFactory

2.1 ApplicationContext接口

使用该接口可以获取到具体的Bean对象

该接口下有两个具体的实现类

ClassPathXmlApplicationContext – 加载类路径下的Spring配置文件
FileSystemXmlApplicationContext – 加载本地磁盘下的Spring配置文件

下面演示FileSystemXmlApplicationContext的用法:把src下的applicationContext.xml拷贝到你电脑的某个目录,例如:c:/spring,可以通过FileSystemXmlApplicationContext加载本地磁盘下的spring配置文件

public class TestIOC {
    @Test
    public void test1(){
        //创建Spring工厂(创建IOC容器)
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao  = (UserDao) ac.getBean("userDao");
        userDao.save();
    }

    @Test
    public void test2(){
        //创建Spring工厂(创建IOC容器)
        ApplicationContext ac = new FileSystemXmlApplicationContext("C:/spring/applicationContext.xml");
        UserDao userDao  = (UserDao) ac.getBean("userDao");
        userDao.save();
    }

}

2.2 BeanFactory工厂 ---- 已过时

BeanFactory是Spring框架早期的创建Bean对象的工厂接口。在TestIOC中创建test3测试方法:

/**
 * 早期版本的spring工厂:BeanFactory
 */
@Test
public void test3() {
    //此方法已经过时
    BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    UserDao userDao = (UserDao) factory.getBean("userDao");
    userDao.save();

} 

2.3 BeanFactory和ApplicationContext的区别 :

BeanFactory                – BeanFactory采取延迟加载,第一次getBean时才会初始化Bean

ApplicationContext        – 在加载applicationContext.xml时候就会创建具体的Bean对象的实例

修改UserDaoImpl,增加一个无参构造方法,运行test1和test3两个单元测试方法,验证ApplicationContext和BeanFactory这两个工厂到底什么时候创建bean对象??

public class UserDaoImpl implements UserDao {

   public UserDaoImpl() {
      System.out.println("调用了无参构造方法...");
   }


   @Override
   public void save() {
      System.out.println("持久层:用户保存...");
   }

}

修改test1单元测试方法:

/**
 * 创建ioc容器时就已经把对象创建好了
 */
@Test
public void test1(){
    //创建Spring工厂(创建IOC容器)
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    System.out.println("===============");
    UserDao userDao  = (UserDao) ac.getBean("userDao");
    userDao.save();
}

运行结果:

调用了无参构造方法...
===============

运行test1方法,发现:ApplicationContext是在创建ioc容器时就已经把对象创建好了

修改test3单元测试方法:

/**
 * 早期版本的spring工厂:BeanFactory
 * 创建ioc容器时并没有创建对象,而是在第一次getBean时再创建对象
 */
@Test
public void test3() {
    BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    System.out.println("===============");
    UserDao userDao = (UserDao) factory.getBean("userDao");
    userDao.save();

}

运行结果:

===============
调用了无参构造方法...

运行test3方法,发现:BeanFactory是创建ioc容器时并没有创建对象,而是在第一次getBean时再创建对象

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

    <bean id="userDao" class="cn.cosco.impl.UserDaoImpl"></bean>

</beans>

2.4.1 id属性

id属性是bean的唯一标识

2.4.2 class属 性

javaBean 的全路径名

其实,除了 id 属性和 class 属性外,还可以配置如下属性:

2.4.3 scope属性

scope属性代表Bean的作用范围

singleton: 单例(默认值)

prototype: 多例,在Spring框架整合Struts2框架的时候,Action 类也需要交给 Spring 做管理,配置把 Action 类配置成多例!!

request: 应用在 web 工程中,将创建的对象存入到 request 域中。

session: 应用在 web 工程中,将创建的对象存入到 session 域中。

globalsession: 应用在 porlet 环境下使用。将创建的对象存入到全局的 session 中。

后三种比较少见。

在TestIOC中创建单元测试方法test4:

@Test
public void test4() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDao userDao1 = (UserDao) ac.getBean("userDao");
    UserDao userDao2 = (UserDao) ac.getBean("userDao");
    System.out.println(userDao1==userDao2);

}

运行结果:

调用了无参构造方法...
true

测试发现:当scope为 singleton 时,无论实例化几次 javaBean 对象,都只会创建一次。

修改 applicationContext.xml,把 UserDaoImpl 的作用域改为 prototype:

<?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="userDao" class="cn.cosco.dao.impl.UserDaoImpl" scope="prototype"></bean>
</beans>

运行结果:

调用了无参构造方法...
调用了无参构造方法...
false

测试发现:当scope为prototype时,每次获取bean,都会重新实例化

2.4.4 init-method属性

当bean被载入到容器的时候调用init-method属性指定的方法

修改 UserDaoImpl ,在其中提供 init 方法

public class UserDaoImpl implements UserDao {

   public UserDaoImpl() {
      System.out.println("调用了无参构造方法...");
   }

   public void init(){
      System.out.println("调用了init方法...");
   }

   @Override
   public void save() {
      System.out.println("持久层:用户保存...");
   }

}

修改 applicationContext.xml,为 UserDaoImpl 指定初始化方法

<?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="userDao" class="cn.cosco.dao.impl.UserDaoImpl" init-method="init"></bean>
</beans>

运行 test1 单元测试方法,测试结果:

调用了无参构造方法...
调用了init方法...
===============
持久层:用户保存...

2.4.5 destroy-method属性

当bean从容器中删除的时候调用destroy-method属性指定的方法

想查看destroy-method的效果,有如下条件:

scope= singleton 有效 

web容器中会自动调用,但是 main 函数或测试用例需要手动调用(需要使用 ClassPathXmlApplicationContext 的close() 方法) 

在applicationContext.xml中为UserDaoImpl指定销毁方法

<?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="userDao" class="cn.cosco.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
</beans>

修改UserDaoImpl,在其中提供destroy方法

public class UserDaoImpl implements UserDao {

   public UserDaoImpl() {
      System.out.println("调用了无参构造方法...");
   }

   public void init(){
      System.out.println("调用了init方法...");
   }


   @Override
   public void save() {
      System.out.println("持久层:用户保存...");
   }

   public void destroy(){
      System.out.println("调用了销毁方法...");
   }


}

修改test1单元测试方法,显示关闭ioc容器。测试结果如下:

调用了无参构造方法...
调用了init方法...
===============
持久层:用户保存...
调用了销毁方法...

3 Spring 生成bean的三种方式

3.1 无参构造方法

默认调用无参构造方法实例化bean。在此之前,都是调用无参构造来实例化的。

3.2 静态工厂实例化方式

通过调用工厂类的静态方法来生成bean

编写DeptDao接口:

public Interface DeptDaoImpl {
    public void save();
}

编写DeptDaoImpl实现类:

public class DeptDaoImpl implements DeptDao{
    @Override
    public void save() {
        System.out.println("持久层:部门保存...");
    }
}

编写工厂类,在其中创建静态工厂方法

public class Factory {
    /**
     * 静态工厂方法
     */
    public static DeptDao create(){
        System.out.println("调用了静态工厂方法");
        return new DeptDaoImpl();
    }

}

编写applicationContext.xml配置文件,采用静态工厂方式配置DeptDaoImpl类

<?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="userDao" class="cn.cosco.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
    <bean id="deptDao" class="cn.cosco.factory.Factory" factory-method="create"></bean>
</beans>

在配置DeptDaoImpl这个bean时,class属性写的不是DeptDaoImpl的全路径名,而是工厂类的全路径名;

factory-method:指定工厂类中静态方法的名字

在TestIOC类中编写测试方法test5:

@Test
public void test5(){
    //创建Spring工厂(创建IOC容器)
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    DeptDao deptDao = (DeptDao) ac.getBean("deptDao");
    deptDao.save();

}

测试结果如下:

调用了静态工厂方法
持久层:部门保存...

3.3 实例工厂实例化方式

修改Factory工厂类,创建实例工厂方法:

public class Factory {
    /**
     * 静态工厂方法
     */
//    public static DeptDao create(){
//        System.out.println("调用了静态工厂方法");
//        return new DeptDaoImpl();
//    }

    /**
     * 实例工厂方法
     * @return
     */
    public  DeptDao create(){
        System.out.println("调用了实例工厂方法");
        return new DeptDaoImpl();
    }


}

编写applicationContext.xml,采用实例工厂方式重写配置DeptDaoImpl

<?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="userDao" class="cn.cosco.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
    <!-- 实例工厂方法来实例化 -->
    <bean id="factory" class="cn.cosco.factory.Factory"></bean>
    <bean id="deptDao" factory-bean="factory" factory-method="create"></bean>
</beans>

factory-bean:指定工厂bean的id;

Factory-method:指定工厂bean的实例工厂方法的名字

运行test5测试方法,测试结果如下:

调用了实例工厂方法
持久层:部门保存...

4 注入依赖

4.1 什么是注入依赖

IOC和DI的概念:
​ * IOC – Inverse of Control,控制反转,将对象的创建权反转给Spring!!
​ * DI – Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!

如果UserServiceImpl的实现类中有一个属性,那么使用Spring框架的IOC功能时,可以通过依赖注入把该属性的值传入进来!!

4.2 构造方法注入

什么是构造方法注入?构造方法注入就是利用bean的构造方法完成对bean中属性的赋值。

创建Car实体类,提供有参构造方法

public class Car implements Serializable{
    private String name;
    private Double price;

    public Car(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {

        return name;
    }

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

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

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

创建applicationContext2.xml,在applicationContext2.xml配置Car这个bean

<?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="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="兰博基尼"></constructor-arg>
       <constructor-arg name="price" value="3000000.0"></constructor-arg>
   </bean>
</beans>

创建单元测试类TestDI,在其中创建单元测试方法test1测试,注意此处创建IOC容器时,应该加载applicationContext2.xml

public class TestDI {
    
    @Test
    public void test1(){
        //创建Spring工厂(创建IOC容器)
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext2.xml");
        Car car = (Car) ac.getBean("car");
        System.out.println(car);
    }

}

运行结果:

Car{name='兰博基尼', price='3000000.0'}

4.3 set方法注入

什么是set方法注入?set方法注入就是利用bean中属性的set方法对属性赋值。

创建People实体类,提供属性的set方法,不需要提供有参构造方法。

public class People implements Serializable{
    private String name;//要提供属性所对应的set方法
    private String address;
    private Car car;//对象属性

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

    public void setAddress(String address) {
        this.address = address;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", car=" + car +
                '}';
    }
}

在applicationContext.xml2中配置People实体类,普通属性用value指定值,对象属性用ref指定需要注入的bean的id.

<?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="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="兰博基尼"></constructor-arg>
       <constructor-arg name="price" value="3000000.0"></constructor-arg>
   </bean>
    <!-- 第二种注入形式:set方法注入 -->
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="汪峰"></property>
        <property name="address" value="北京"></property>
        <property name="car" ref="car"></property>
    </bean>

</beans>

在TestIOC中创建test2方法

@Test
public void test2(){
    //创建Spring工厂(创建IOC容器)
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext2.xml");
    People people = (People) ac.getBean("people");
    System.out.println(people);
}

运行结果:

People{name='汪峰', address='北京', Car{name='兰博基尼', price='3000000.0'}}

注意:采用set方法注入时,类中一定要有无参构造方法,因为spring会先调用无参构造方法实例化对象。

4.4 set方法其它注入写法

通过set方法注入还有其它两种写法,这两种写法都是spring在新的版本中提供的写法:

1、p命名空间的写法

2、SpEL的写法

4.4.1 p命名空间的写法

在applicationContext2.xml中引入p命名空间

修改applicationContext2.xml,采用p命名空间的写法为People注入值。语法是:

p:简单属性名=”值”

p:对象属性名-ref=”bean的id”

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="兰博基尼"></constructor-arg>
       <constructor-arg name="price" value="3000000.0"></constructor-arg>
   </bean>
    <!-- 第二种注入形式:set方法注入 p命名空间-->
    <bean id="people" class="cn.cosco.domain.People" p:name="汪峰" p:address="北京" p:car-ref="car"></bean>

</beans>

4.4.2 SpEL的写法(spring3.0提供)

什么是SpEl:Spring Expression Language

修改applicationContext2.xml,采用SpEL的写法为People注入值

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="兰博基尼"></constructor-arg>
       <constructor-arg name="price" value="3000000.0"></constructor-arg>
   </bean>
    <!-- 第二种注入形式:set方法注入 SpEL的写法 -->
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="#{'汪峰'}"></property>
        <property name="address" value="#{'北京'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>
</beans>

SpEL注入的语法是:

注入字符串:#{‘字符串’}

注入数字:#{数字}

注入其它对象:#{对象id}

SpEL还可以注入其它对象的属性或方法的返回值,创建 CarInfo 类,存储 Car 的信息:

public class CarInfo implements Serializable {
    public String getName(){
        return "奇瑞QQ";
    }

    public double calculatePrice(){
        return Math.random() * 10000;
    }

}

创建Car2实体类

public class Car2 implements Serializable{
    private String name;
    private Double price;

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

    public void setPrice(Double price) {
        this.price = price;
    }

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

在applicationContext2.xml配置Car2

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="兰博基尼"></constructor-arg>
       <constructor-arg name="price" value="3000000.0"></constructor-arg>
   </bean>
   <!-- 第二种注入形式:set方法注入 SpEL的写法 -->
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="#{'汪峰'}"></property>
        <property name="address" value="#{'北京'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>

    <!-- SpEL的写法 -->
    <bean id="carInfo" class="cn.cosco.domain.CarInfo"></bean>
    <bean id="car2" class="cn.cosco.domain.Car2">
        <property name="name" value="#{carInfo.name}"></property>
        <property name="price" value="#{carInfo.calculatePrice()}"></property>
    </bean>

</beans>

注意:#{carInfo.ame}会调用getName方法获取汽车的名称;而#{carInfo.calculatePrice()}会直接调用calculatePrice方法获取汽车价格。

4.5 数组或list注入

有的时候,bean中的属性是List或数组类型。那么该怎么给List或数组注入值呢?数组和list注入的写法是一样的。

新建bean类:CollectionBean

public class CollectionBean implements Serializable{
    private List<String> list;//也可以是数组

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

    @Override
    public String toString() {
        return "CollectionBean{" +
                "list=" + list +
                '}';
    }
}

在applicationContext2.xml中配置CollectionBean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="五菱宏光"></constructor-arg>
       <constructor-arg name="price" value="30000.0"></constructor-arg>
   </bean>
   	<!-- 第二种注入形式:set方法注入 SpEL的写法 -->
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="#{'汪峰'}"></property>
        <property name="address" value="#{'北京'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>

    <!-- SpEL的写法 -->
    <bean id="carInfo" class="cn.cosco.domain.CarInfo"></bean>
    <bean id="car2" class="cn.cosco.domain.Car2">
        <property name="name" value="#{carInfo.name}"></property>
        <property name="price" value="#{carInfo.calculatePrice()}"></property>
    </bean>

    <!-- 特殊类型的注入 -->
    <bean id="cb" class="cn.cosco.domain.CollectionBean">
        <property name="list">
            <list>
                <value>乔峰</value>
                <value>段誉</value>
                <value>虚竹</value>
            </list>
        </property>
    </bean>


</beans>

在TestDI中创建单元测试方法test3:

@Test
public void test3(){
    //创建Spring工厂(创建IOC容器)
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    CollectionBean cb = (CollectionBean) ac.getBean("cb");
    System.out.println(cb);
}

测试结果如下:

CollectionBean{list=[乔峰,段誉,虚竹]}

4.6 Set集合的注入

有的时候,bean中的属性是Set类型。那么该怎么给Set类型的属性注入值呢?

修改CollectionBean,在其中添加一个Set类型的属性并提供set方法:

public class CollectionBean implements Serializable{
    private List<String> list;//也可以是数组
    private Set<String> set;

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

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

    @Override
    public String toString() {
        return "CollectionBean{" +
                "list=" + list +
                ", set=" + set +
                '}';
    }
}

在applicaitonContext2.xml中为Set类型的属性注入值:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="五菱宏光"></constructor-arg>
       <constructor-arg name="price" value="30000.0"></constructor-arg>
   </bean>
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="#{'汪峰'}"></property>
        <property name="address" value="#{'北京'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>

    <!-- SpEL的写法 -->
    <bean id="carInfo" class="cn.cosco.domain.CarInfo"></bean>
    <bean id="car2" class="cn.cosco.domain.Car2">
        <property name="name" value="#{carInfo.name}"></property>
        <property name="price" value="#{carInfo.calculatePrice()}"></property>
    </bean>

    <!-- 特殊类型的注入 -->
    <bean id="cb" class="cn.cosco.domain.CollectionBean">
        <property name="list">
            <list>
                <value>乔峰</value>
                <value>段誉</value>
                <value>虚竹</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>鸠摩智</value>
                <value>天山童姥</value>
                <value>无崖子</value>
            </set>
        </property>
    </bean>
</beans>

提示:spring在注入set的时,给我们注入的是一个LinkedHashSet,所以在输入set集合中的元素时,是按照我们注入的顺序来的,并不是无序的。

4.7 Map集合的注入

有的时候,bean中的属性是Map类型。那么该怎么给Map类型的属性注入值呢?

修改CollectionBean,在其中添加一个Map类型的属性并提供set方法:

public class CollectionBean implements Serializable{
    private List<String> list;//也可以是数组
    private Set<String> set;
    private Map<String,String> map;

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

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

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

    @Override
    public String toString() {
        return "CollectionBean{" +
                "list=" + list +
                ", set=" + set +
                ", map=" + map +
                '}';
    }
}

在applicationContext2.xml中为Map输入注入值:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="五菱宏光"></constructor-arg>
       <constructor-arg name="price" value="30000.0"></constructor-arg>
   </bean>
    <!-- 第二种注入形式:set方法注入 -->

    <!--<bean id="people" class="cn.cosco.domain.People">-->
        <!--<property name="name" value="小明"></property>-->
        <!--<property name="address" value="上海"></property>-->
        <!--<property name="car" ref="car"></property>-->
    <!--</bean>-->
    <!--<bean id="people" class="cn.cosco.domain.People" p:name="汪峰" p:address="北京" p:car-ref="car"></bean>-->
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="#{'汪峰'}"></property>
        <property name="address" value="#{'北京'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>

    <!-- SpEL的写法 -->
    <bean id="carInfo" class="cn.cosco.domain.CarInfo"></bean>
    <bean id="car2" class="cn.cosco.domain.Car2">
        <property name="name" value="#{carInfo.name}"></property>
        <property name="price" value="#{carInfo.calculatePrice()}"></property>
    </bean>

    <!-- 特殊类型的注入 -->
    <bean id="cb" class="cn.cosco.domain.CollectionBean">
        <property name="list">
            <list>
                <value>乔峰</value>
                <value>段誉</value>
                <value>虚竹</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>鸠摩智</value>
                <value>天山童姥</value>
                <value>无崖子</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="id" value="1"></entry>
                <entry key="username" value="张三"></entry>
            </map>
        </property>


    </bean>


</beans>

说明:

表示map中的一个键值对;

的key表示键,value表示值;

4.8 Properties的注入(重点)

有的时候,bean中的属性是Properties类型。那么该怎么给Properties类型的属性注入值呢?

修改CollectionBean,在其中添加一个Properties类型的属性并提供set方法:

public class CollectionBean implements Serializable{
    private List<String> list;//也可以是数组
    private Set<String> set;
    private Map<String,String> map;
    private Properties properties;

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

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

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

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

    @Override
    public String toString() {
        return "CollectionBean{" +
                "list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
} 

在applicationContext2.xml中给Properties类型的属性注入值:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 构造方法注入 -->
   <bean id="car" class="cn.cosco.domain.Car">
       <constructor-arg name="name" value="五菱宏光"></constructor-arg>
       <constructor-arg name="price" value="30000.0"></constructor-arg>
   </bean>
    <!-- 第二种注入形式:set方法注入 -->

    <!--<bean id="people" class="cn.cosco.domain.People">-->
        <!--<property name="name" value="小明"></property>-->
        <!--<property name="address" value="上海"></property>-->
        <!--<property name="car" ref="car"></property>-->
    <!--</bean>-->
    <!--<bean id="people" class="cn.cosco.domain.People" p:name="汪峰" p:address="北京" p:car-ref="car"></bean>-->
    <bean id="people" class="cn.cosco.domain.People">
        <property name="name" value="#{'汪峰'}"></property>
        <property name="address" value="#{'北京'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>

    <!-- SpEL的写法 -->
    <bean id="carInfo" class="cn.cosco.domain.CarInfo"></bean>
    <bean id="car2" class="cn.cosco.domain.Car2">
        <property name="name" value="#{carInfo.name}"></property>
        <property name="price" value="#{carInfo.calculatePrice()}"></property>
    </bean>

    <!-- 特殊类型的注入 -->
    <bean id="cb" class="cn.cosco.domain.CollectionBean">
        <property name="list">
            <list>
                <value>乔峰</value>
                <value>段誉</value>
                <value>虚竹</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>鸠摩智</value>
                <value>天山童姥</value>
                <value>无崖子</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="id" value="1"></entry>
                <entry key="username" value="张三"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="id">2</prop>
                <prop key="name">小明</prop>
            </props>
        </property>
    </bean>
</beans>

猜你喜欢

转载自blog.csdn.net/zyrdfly/article/details/83956247