A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 哈哈大圣 中级黑马   /  2019-1-24 13:47  /  888 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

# Spring基于XML的IOC细节

## 一、Spring中的工厂的类结构图

---
@@@@@@@@@@@@@@@@@@@@@@@@@@2 spring中工厂的类结构图.png

---
@@@@@@@@@@@@@@@@@@@@@@@@@@2 spring中工厂的类结构图关系.png

### 1. BeanFactory和ApplicationContext的区别

1. **`BeanFactory`** 是Spring容器的顶层接口。
    - 需要使用时创建对象
2. **`ApplicationContext`** 是`BeanFactory`的子接口
    - 只要一读取配置文件,默认情况下就会创建对象。

### 2. ApplicationContext接口的实现类

1. **`ClassPathXmlApplicationContext`**
    - 【推荐!】从根路径下加载配置文件

2. **`FileSystemXmlApplicationContext`**
    - 【忘记吧!】从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

3. **`AnnotationConfigApplicationContext`**
    - 当使用注解配置容器对象时,需要使用此类来创建spring容器。它用来读取注解。


## 二、IOC中bean标签和管理对象细节
> bean.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 标签:用于配置让spring 创建对象,并且存入ioc容器中
     id 属性:对象的唯一标识
     class 属性:指定要闯将对象的全限定类名
     -->
    <!-- 配置service -->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl" ></bean>
</beans>
```

### 1. bean标签的作用
1. 用于配置对象让spring来创建。
2. 【默认情况下】调用的是类中的无参构造函数【反射】。如果没有无参构造函数则不能创建成功。

### 2. bean标签的属性介绍

```
<bean
    id="accountDao"
    -- 给对象在容器中提供一个唯一标识。用于获取对象。

    class="com.itheima.dao.impl.AccountDaoImpl"
    -- 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数

    scope="prototype"
    -- 指定对象的作用范围:取值及其含义如下
        -- singleton: 默认值,单例的
        -- prototype: 多例的
        -- request: web项目中,Spring创建一个Bean对象,将对象存入request域中
        -- session: web项目中,Spring创建一个Bean对象,将对象存入session域中
        -- golbal session: web项目中,【应用在Protlet环境】,如果没有Protlet
                 环境,那么golbalSession相当于session

    init-method="init"
    -- 指定类中的初始化方法的名称

    destroy-method="destory"
    -- 指定类中销毁方法的名称

></bean>
```

### 3. bean的作用范围和生命周期

#### 1. 单例对象:属性scope="singleton"
> 一个应用只有一个对象的实例。作用范围就是整个引用

- **生命周期**:
    - 对象出生:当应用加载,创建容器市,对象就被创建了。
    - 对象活着:容器在,对象在
    - 对象拜拜:应用卸载、容器销毁时。

#### 2. 多例对象:属性scope="prototype"
> 每次访问对象时,都会重新创建对象实例

- **生命周期**:
    - 对象出生:当使用对象时
    - 对象活着:对象在被使用中
    - 对象拜拜:长时间不使用,被java的垃圾回收机制GC回收了

#### 3. 实例化Bean的三种方式

##### 1. 使用默认无参构造函数
> 在默认情况下:会根据默认无参构造函数来创建类对象,如果没有默认无参构造函数,将会创建失败。
```
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
```

##### 2. spring管理【静态】工厂-使用静态工厂的方式创建对象
> 比如,如下:使用StaticFactory类中静态方法createAccountService创建对象,并存入spring容器

1. 模拟一个**静态**工厂类,创建业务层实现类
```
public class StaticFactory {
    public static AccountService createAccountService() {
        return new AccountServiceImpl();
    }
}
```

2. 配置文件bean.xml
```
<bean
    id="accountService"
    -- 指定bean的id,用于从容器中获取

    class="com.itheima.factory.StaticFactory"
    -- 指定【静态工厂】的全限定类名

    factory-method="createAccountService"
    -- 指定生产对象的静态方法

></bean>
```

##### 3. spring管理【实例】工厂-使用实力工厂的方法创建对象
> 先把工厂的创建交给spring来管理,然后再使用工厂的bean来调用里面的方法;
*演示:模拟一个实例工厂,创建业务层实现类,此工厂创建对象,必须现让spring创建该工厂的实例对象,再调用方法*

1. **实例**工厂类
```
public class InstanceFactory {
    public AccountService createAccountService() {
        return new AccountServiceImpl();
    }
}
```

2. bean.xml配置
```
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
-- 实例工厂的bean配置

<bean id="accountService"
    factory-bean="instancFactory"
    -- 指定实例工厂bean的id

    factory-method="createAccountService"
    -- 指定实例工厂中创建对象的方法

></bean>
```


## 三、Spring的依赖注入
> 依赖注入:Dependency Injection,spring框架核心ioc的具体实现。程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

### 1. 构造函数注入
> 顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做,而是通过配置的方式,让spring框架来为我们注入。

1. 被注入的类案例:【类中需要提供一个对应参数列表的构造函数】
```
public class AccountServiceImpl implements AccountService {

    private String name;
    private Integer age;
    private Date birthday;

    public AccountServiceImpl(String name, Integer age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }
    ...
```

2. bean.xml对应的配置的标签`constructor-arg`介绍
```
<constructor-arg
    index="1"
    -- 指定参数在构造函数参数列表的索引位置

    type="Integer"
    -- 指定参数在构造函数中的数据类型

    name="name"
    -- 指定参数在构造函数中的名称

    -\-\ 上面三个是找给谁赋值,下面两个是赋什么值 /-/-

    value="张三"
    -- 它能赋的值是基本的数据类型和String类型

    ref="now"
    -- 能赋的值为其他的bean类型,在配置文件中得配置该bean标签,如下
></constructor-arg>
<bean id="now" class="java.util.Date"></bean>
```

3. bean.xml配置案例
```
<bean id="now" class="java.util.Date"></bean>

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <constructor-arg name="name" value=" 张三 "></constructor-arg>
    <constructor-arg name="age" value="18"></constructor-arg>
    <constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>

```


### 2. set方法注入【开发中的常客】
> 需要在类中提供set方法

1. bean类文件案例
```
public class AccountServiceImpl implements IAccountService {
    private String name;
    private Integer age;
    private Date birthday;

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

    public void setAge(Integer age) { this.age = age; }

    public void setBirthday(Date birthday) { this.birthday = birthday; }

    ...
```

2. 涉及的标签`property`
```
<property
    name="name"
    -- 被注入类的对应set方法“set”之后的部分首字母小写!

    value="test"
    -- 给属性赋值为基本数据类型和string类型的

    ref="now"
    -- 给属性赋值是其他bean类型的

></property>
<bean id="now" class="java.util.Date"></bean>
```


3. bean.xml配置案例
```
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <property name="name" value="test"></property>
    <property name="age" value="21"></property>
    <property name="birthday" ref="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>
```

### 3. 使用p名称空间注入数据(本质还是调用set方法)【了解】
> 此种方式通过xml中导入p名称空间,使用`p:propertyName`来注入数据,本质还是调用set方法实现注入功能

1. java代码【->2. set方法注入【开发中的常客】->1. bean类文件案例】

2. 配置文件案例
```
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    -- 引入此命名空间约束

    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="accountService"
    class="com.itheima.service.impl.AccountServiceImpl4"
    p:name="test" p:age="21" p:birthday-ref="now"/>
    -- p:propertyName的形式

</beans>
```

### 4. 注入集合属性
> 给类中的集合成员传值,用的也是注入的方式,只不过变量的数据类型都是集合。一般注入的集合类型为List、Set、Map、Properties

1. 被注入的JavaBean
```
public class AccountServiceImpl implements AccountService {

    private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String, String> myMap;
    private Properties myProps;

    public String[] getMyStrs() { return myStrs; }

    public void setMyStrs(String[] myStrs) { this.myStrs = myStrs; }

    public List<String> getMyList() { return myList; }

    public void setMyList(List<String> myList) { this.myList = myList; }

    public Set<String> getMySet() { return mySet; }

    public void setMySet(Set<String> mySet) { this.mySet = mySet; }

    public Map<String, String> getMyMap() { return myMap; }

    public void setMyMap(Map<String, String> myMap) { this.myMap = myMap; }

    public Properties getMyProps() { return myProps; }

    public void setMyProps(Properties myProps) { this.myProps = myProps; }

    ...
```

2. bean.xml中对应的配置
    - 注入集合数据时,只要结构相同,标签可以互换
    - 注入集合时,根据类型选择标签,同种集合类型通用
        - List结构:
            - `<array></array>`
            - `<list></list>`
            - `<set></set>`
        - Map结构的
            - `<map></map>`
            - `<entry></entry>`
            - `<prop></prop>`
            - `<props></props>`
```
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <!-- 给数组注入数据 -->
    <property name="myStrs">
        <set>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </set>
    </property>

    <!-- 注入list集合数据 -->
    <property name="myList">
        <list>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </list>
    </property>

    <!-- 注入set集合数据 -->
    <property name="mySet">
        <set>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </set>
    </property>

    <!-- 注入Map数据 -->
    <property name="myMap">
        <props>
            <prop key="A">AAA</prop>
            <prop key="B">BBB</prop>
        </props>
    </property>

    <!-- 注入properties数据 -->
    <property name="myProps">
        <map>
            <entry key="A" value="AAA"></entry>
            <entry key="B">
                <value>BBB</value>
            </entry>
        </map>
    </property>
</bean>
```


## 四、Spring配置文件中提示的配置【Eclipse】
---
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ spring配置文件提示配置【Eclipse】.png



0 个回复

您需要登录后才可以回帖 登录 | 加入黑马