Spring框架(二)—— IOC

19 篇文章 3 订阅
11 篇文章 0 订阅

一、 IOC & DI 概述

  IOC(Inversion of Control):其思想是反转资源获取的方向。 传统的资源查找方式要求组件向容器发起请求查找资源,作为回应, 容器适时的返回资源.。而应用了 IOC 之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。这种行为也被称为查找的被动形式。
  
  DI(Dependency Injection):IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入。相对于 IOC 而言,这种表述更直接。

二、 一个简单的HelloWorld示例

1) 导入Spring框架中的相关jar包,这里是通过Maven完成对项目的构建,pom文件中的代码如下。

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.1.6.RELEASE</version>
    </dependency>

2) 创建一个简单的JavaBean,命名为HelloWorld,如下:

package com.spring.ioc;

public class HelloWorld {

    private String user;

    public HelloWorld() {
        System.out.println("com.spring.ioc.HelloWorld's constructor...");
    }

    public void setUser(String user) {
        System.out.println("setUser:" + user);
        this.user = user;
    }

    public HelloWorld(String user) {
        this.user = user;
    }

    public void hello() {
        System.out.println("Hello: " + user);
    }

}

3) 创建Spring的配置文件,进行Bean的配置。

   Spring的核心配置文件名称和位置不是固定的。但官方件建议将该核心配置文件放在src目录下,且命名为 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 -->
    <bean id="helloWorld" class="com.spring.ioc.HelloWorld">
        <!-- 为属性赋值 -->
        <property name="user" value="Spring"></property>
    </bean>
</beans>

4) 创建测试类

package com.spring.ioc;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by ChuanChen on 2018/2/11
 */
public class SpringTest {

    public static void main(String[] args) {
        //1. 创建 Spring 的 IOC 容器
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 从 IOC 容器中获取 bean 的实例
        HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");

        //3. 使用 bean
        helloWorld.hello();
    }
}

三、在 Spring 的 IOC 容器里配置 Bean

配置形式:基于 XML 文件的方式;基于注解的方式
Bean 的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、通过FactoryBean

基于 XML 文件的方式配置 Bean

一、通过全类名(反射)的方式配置Bean
在 xml 文件中通过 bean 节点来配置 bean。

 <!--通过全类名的方式来配置bean-->
    <bean id="helloWorld"
          class="com.spring.ioc.HelloWorld">
        <!-- 为属性赋值 -->
        <property name="user" value="Spring"></property>
    </bean>

注1:id为Bean 的名称。在 IOC 容器中必须是唯一的,若 id 没有指定,Spring 自动将权限定性类名作为 Bean 的名字, id 可以指定多个名字,名字之间可用逗号、分号、或空格分隔。
注2:Bean标签的常用属性:
1)id属性:用于指定配置对象的名称,不能包含特殊符号。
2)class属性:创建对象所在类的全路径。
3)name属性:功能同id属性一致。但是在name属性值中可以包含特殊符号。
4)scope属性:设置 Bean 的作用域.

二、通过工厂方法(静态工厂方法 & 实例工厂方法)的方式配置Bean
1)通过调用静态工厂方法创建 Bean
  调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单地调用静态方法,而不同关心创建对象的细节。
  要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类,同时在 factory-method 属性里指定工厂方法的名称。最后,使用 < constrctor-arg > 元素为该方法传递方法参数。

 <bean id="car" class="com.spring.ioc.StaticCarFactory"
          factory-method="getCar">

        <constructor-arg value="ford"/>
    </bean>
package com.spring.ioc;

import java.util.HashMap;
import java.util.Map;

/**
 * 静态工厂方法:直接调用某一个类的静态方法就可以返回bean 实例
 */
public class StaticCarFactory {
    private static Map<String, Car> cars = new HashMap<String, Car>();

    static {
        cars.put("audi", new Car("audi", 300000));
        cars.put("ford", new Car("ford", 400000));
    }

    //静态工厂方法
    public static Car getCar(String name){
        return cars.get(name);
    }
}

2)通过调用实例工厂方法创建 Bean
  实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节。
  要声明通过实例工厂方法创建的 Bean:
  - 在 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean
  - 在 factory-method 属性里指定该工厂方法的名称
  - 使用 construtor-arg 元素为工厂方法传递方法参数

 <!--配置工厂实例-->
 <bean id="carFactory" class="com.spring.ioc.InstanceCarFactory"></bean>
 <!--通过实例工厂方法来配置Bean-->
 <bean id="car" factory-bean="carFactory" factory-method="getCar">
     <constructor-arg value="ford"></constructor-arg>
 </bean>
package com.spring.ioc;

import java.util.HashMap;
import java.util.Map;

/**
 * 实例工厂方法:实例工厂的方法,即先需要创建工厂本身,再调用工厂的实例方法来返回Bean的实例
 */
public class InstanceCarFactory {
    private static Map<String, Car> cars = null;

    public InstanceCarFactory(){
        cars = new HashMap<String, Car>();
        cars.put("audi", new Car("audi", 300000));
        cars.put("ford", new Car("ford", 400000));
    }


    public Car getCar(String name){
        return cars.get(name);
    }
}

三、通过FactoryBean的方式配置Bean
实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
  Spring 中有两种类型的 Bean, 一种是普通Bean,另一种是工厂Bean,即FactoryBean。
  工厂 Bean 跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂 Bean 的 getObject 方法所返回的对象 。
  这里写图片描述

IOC 容器 BeanFactory & ApplicationContext 概述

  在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前,必须对它进行实例化.。只有在容器实例化后,,才可以从 IOC 容器里获取 Bean 实例并使用。
  
  Spring 提供了两种类型的 IOC 容器实现.。
  BeanFactory: IOC 容器的基本实现。
  ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口。
  
  BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory。无论使用何种方式,,配置文件是相同的。
  
  ApplicationContext 的主要实现类:
  ClassPathXmlApplicationContext:从 类路径下加载配置文件
  FileSystemXmlApplicationContext: 从文件系统中加载配置文件
  
  这里写图片描述
  

  ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。

从 IOC 容器中获取 Bean

调用 ApplicationContext 的 getBean() 方法。

这里写图片描述

依赖注入的方式

Spring 支持 3 种依赖注入的方式:

  • 属性注入   
  • 构造器注入   
  • 工厂方法注入(很少使用,不推荐)

属性注入
  属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象。
  属性注入使用 < property > 元素,使用 name 属性指定 Bean 的属性名称,value 属性或 < value > 子节点指定属性值 。
  属性注入是实际应用中最常用的注入方式。

 <!--通过全类名的方式来配置bean-->
    <bean id="helloWorld"
          class="com.spring.ioc.HelloWorld">
        <!-- 属性注入为属性赋值 -->
        <property name="user" value="Spring"></property>
    </bean>

构造方法注入:
  通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。
  构造器注入在 < constructor-arg 元素里声明属性, < constructor-arg > 中没有 name 属性。
按索引匹配入参:

    <bean id="student" class="com.spring.ioc.Student">
        <constructor-arg index="0" value="小明"/>
        <constructor-arg index="1" value="18"/>
        <constructor-arg index="2" value="80"/>
    </bean>

按类型匹配入参:

    <bean id="student" class="com.spring.ioc.Student">
        <!-- 为属性赋值 -->
        <constructor-arg  value="小明" type="java.lang.String"/>
        <constructor-arg  value="18" type="int"/>
        <constructor-arg  value="80.5" type="float"/>
    </bean>

注入属性值细节

字面值
  字面值:可用字符串表示的值,可以通过 < value > 元素标签或 value 属性进行注入。
  基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式。
  若字面值中包含特殊字符,可以使用 < ![CDATA[]]> 把字面值包裹起来。
引用其它 Bean
  组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能。要使 Bean 能够相互访问,就必须在 Bean 配置文件中指定对 Bean 的引用。
  在 Bean 的配置文件中,,可以通过 < ref > 元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 的引用。
  也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean。

这里写图片描述

通过 ref 属性值指定当前属性指向哪一个 bean。
内部 Bean
  当 Bean 实例仅仅给一个特定的属性使用时, 可以将其声明为内部 Bean。 内部 Bean 声明直接包含在 < property > 或 < constructor-arg > 元素里,不需要设置任何 id 或 name 属性。
  内部 Bean 不能使用在任何其他地方。
null 值
  可以使用专用的 < null/ > 元素标签为 Bean 的字符串或其它对象类型的属性注入 null 值。
  

<property name="dataSource"><null/></property>

Spring 支持级联属性的配置。
  为级联属性赋值,属性需要先初始化后,才能为级联属性赋值,否则会有异常。
集合属性
  在 Spring中可以通过一组内置的 xml 标签(例如: < list >, < set > 或 < map >) 来配置集合属性。
  配置 java.util.List 类型的属性,需要指定 < list > 标签, 在标签里包含一些元素。这些标签可以通过
< value > 指定简单的常量值,通过 < ref > 指定对其他 Bean 的引用,通过< bean > 指定内置 Bean 定义. 通过 < null/> 指定空元素,甚至可以内嵌其他集合。数组的定义和 List 一样,都使用 < list >。
  配置 java.util.Set 需要使用 < se t> 标签,定义元素的方法与 List 一样。
  Java.util.Map 通过 < map > 标签定义, < map > 标签里可以使用多个 < entry > 作为子标签. 每个条目包含一个键和一个值。必须在 < key > 标签里定义键。因为键和值的类型没有限制, 所以可以自由地为它们指定 < value >, < ref >, < bean > 或 < null > 元素。可以将 Map 的键和值作为 < entry > 的属性定义, 简单常量使用 key 和 value 来定义, Bean 引用通过 key-ref 和 value-ref 属性定义。
  使用 定义 java.util.Properties。 该标签使用多个 < prop> 作为子标签,每个 < prop> 标签必须定义 key 属性.。

<bean id="propertyDemo" class="com.spring.ioc.PropertyDemo">
        <!-- 注入数组 -->
        <property name="arrs">
            <list>
                <value>value 1 of array</value>
                <value>value 2 of array</value>
                <value>value 3 of array</value>
            </list>
        </property>
        <!-- 注入List集合 -->
        <property name="list">
            <list>
                <value>value 1 of list</value>
                <value>value 2 of list</value>
                <value>value 3 of list</value>
            </list>
        </property>
        <!-- 注入Map集合 -->
        <property name="map">
            <map>
                <entry key="key1" value="value 1 of map"></entry>
                <entry key="key2" value="value 2 of map"></entry>
                <entry key="key3" value="value 3 of map"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="username">root</prop>
                <prop key="password">123</prop>
            </props>
        </property>
    </bean>
public class PropertyDemo {
    private String[] arrs;
    private List<String> list;
    private Map<String, String> map;
    private Properties properties;

    public void setArrs(String[] arrs) {
        this.arrs = arrs;
    }

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

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

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

    public String[] getArrs() {
        return arrs;
    }

    public List<String> getList() {
        return list;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public Properties getProperties() {
        return properties;
    }
}

使用 utility scheme 定义集合
  使用基本的集合标签定义集合时,不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合。所以无法在不同 Bean 之间共享集合。
  可以使用 util schema 里的集合标签定义独立的集合 Bean。需要注意的是, 必须在 < beans > 根元素里添加 util schema 定义。

    <util:list id="list">
        <ref bean="student1"/>
        <ref bean="student2"/>
        <ref bean="student3"/>
    </util:list>

使用 p 命名空间
  为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息。Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 < bean > 元素属性的方式配置 Bean 的属性。使用 p 命名空间后,基于 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" 
       xmlns:util="http://www.springframework.org/schema/util"
       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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 配置一个 bean -->
    <!--通过全类名的方式来配置bean-->
    <bean id="helloWorld" class="com.spring.ioc.HelloWorld" p:user="Spring">
    </bean>
</beans>

XML 配置里的 Bean 自动装配

自动装配: 无须在Spring配置文件中描述javaBean之间的依赖关系(如配置< property >、< constructor-arg >)。IOC容器会自动建立javabean之间的关联关系。

  Spring IOC 容器可以自动装配 Bean, 需要做的仅仅是在 < bean > 的 autowire 属性里指定自动装配的模式
  byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean。 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配。
  byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同。
  constructor(通过构造器自动装配):不推荐使用 当 Bean 中存在多个构造器时。 此种自动装配方式将会很复杂。
  
XML 配置里的 Bean 自动装配的缺点
  在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性。 然而, 若只希望装配个别属性时, autowire 属性就不够灵活了。autowire 属性要么根据类型自动装配, 要么根据名称自动装配。 不能两者兼而有之.。一般情况下,在实际的项目中很少使用自动装配功能。因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

    <bean id="game" class="com.spring.ioc.Game"></bean>

    <bean id="student" class="com.spring.ioc.Student" 
          autowire="byName">
        <constructor-arg index="0" value="小明"/>
        <constructor-arg index="1" value="18"/>
        <constructor-arg index="2" value="80"/>

    </bean>

bean 之间的关系:继承;依赖

继承 Bean 配置
  Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean,继承这个父 Bean 的 Bean 称为子 Bean。子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置。子 Bean 也可以覆盖从父 Bean 继承过来的配置。
  父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean。并不是 < bean > 元素里的所有属性都会被继承。 比如: autowire, abstract 等。也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true。

    <!--抽象bean:bean的abstract属性为true的bean,
    这样的bean只能被IOC容器实例化,不能被继承配置-->
    <bean id="parentStudent" class="com.spring.ioc.Student"
          abstract="true">
        <property name="age" value="18"/>
        <property name="score" value="80.5"/>
    </bean>

    <!--bean 配置的继承:使用bean的parent属性指定继承哪个bean的配置-->
    <bean id="student" class="com.spring.ioc.Student"
          parent="parentStudent">
        <property name="name" value="Jerry"/>
    </bean>

依赖 Bean 配置
  Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好。
  如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称。

Bean 的作用域

  在 Spring 中, 可以在 < bean > 元素的 scope 属性里设置 Bean 的作用域.。
  默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例。该作用域被称为 singleton, 它是所有 Bean 的默认作用域。
  
这里写图片描述
  

使用外部属性文件

  在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等)。 而这些部署细节实际上需要和 Bean 配置相分离。
  Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器,这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中。可以在 Bean 配置文件里使用形式为 ${var}的变量,PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量。
  Spring 还允许在属性文件中使用${propName} ,以实现属性之间的相互引用。
注册 PropertyPlaceholderConfigurer
Spring 2.0:
这里写图片描述

<bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="2"/>
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="locations">
            <list>
                <value>classpath:datasource.properties</value>
            </list>
        </property>
        <property name="fileEncoding" value="utf-8"/>
    </bean>


    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}"/>
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
        <!-- 连接池启动时的初始值 -->
        <property name="initialSize" value="${db.initialSize}"/>
        <!-- 连接池的最大值 -->
        <property name="maxActive" value="${db.maxActive}"/>
        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
        <property name="maxIdle" value="${db.maxIdle}"/>
    </bean>

Spring 2.5 之后: 可通过 <context:property-placeholder> 元素简化:
1)< beans > 中添加 context Schema 定义。
2)在配置文件中加入如下配置:
这里写图片描述

    <!-- 引入数据库的配置文件 -->
    <context:property-placeholder location="classpath:datasource.properties" />

    <!-- 数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

datasource.properties文件如下:

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud
jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.user=root
jdbc.password=1234

整合多个配置文件

  Spring 允许通过 < import > 将多个配置文件引入到一个文件中,进行配置文件的集成。这样在启动 Spring 容器时,仅需要指定这个合并好的配置文件就可以。
  import 元素的 resource 属性支持 Spring 的标准的路径资源:
  这里写图片描述

<import resource="applicationContext-datasource.xml"/>

IOC 容器中 Bean 的生命周期

  Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务。
  Spring IOC 容器对 Bean 的生命周期进行管理的过程:
  1)通过构造器或工厂方法创建 Bean 实例
  2)为 Bean 的属性设置值和对其他 Bean 的引用
  3)调用 Bean 的初始化方法(在 Bean 的声明里设置 init-method 属性)
  4)Bean 可以使用了
  5)当容器关闭时, 调用 Bean 的销毁方法(在 Bean 的声明里设置destroy-method 属性)
创建 Bean 后置处理器
  Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
  Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例。 其典型应用是:检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性。
  对Bean 后置处理器而言, 需要实现BeanPostProcessor接口。 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
这里写图片描述

public class MyBeanPostProcessors implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        return null;
    }

    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        return null;
    }
}

添加 Bean 后置处理器后 Bean 的生命周期
  1)通过构造器或工厂方法创建 Bean 实例
  2)为 Bean 的属性设置值和对其他 Bean 的引用
  3)将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
  4)调用 Bean 的初始化方法
  5)将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
  6)Bean 可以使用了
  7)当容器关闭时, 调用 Bean 的销毁方法

总结:
  1. Spring容器 从XML 文件中读取Bean的定义,并实例化Bean。
  2. Spring根据Bean的定义填充所有的属性。
  3. 如果Bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
  4. 如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
  5. 如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
  6. 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
  7. 如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
  8. 如果bean实现了 DisposableBean,它将调用destroy()方法。
注意:
  有两个重要的bean 生命周期方法,第一个是setup() , 它是在容器加载bean的时候被调用。第二个方法是 teardown() 它是在容器卸载类的时候被调用。
  Bean 标签有两个重要的属性init-method和destroy-method。使用它们你可以自己定制初始化和注销方法。即,在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法。它们也有相应的注解@PostConstruct和@PreDestroy。
  

四、基于注解的方式配置 Bean

在 classpath 中扫描组件

  组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件。
  特定组件包括:
  @Component: 基本注解, 标识了一个受 Spring 管理的组件
  @Repository: 标识持久层组件
  @Service: 标识服务层(业务层)组件
  @Controller: 标识表现层组件
  对于扫描到的组件, Spring 有默认的命名策略; 使用非限定类名, 第一个字母小写。也可以在注解中通过 value 属性值标识组件的名称。
  当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan>
  base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类。当需要扫描多个包时, 可以使用逗号分隔。如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类,示例:
这里写图片描述
  <context:include-filter> 子节点表示要包含的目标类。<context:exclude-filter> 子节点表示要排除在外的目标类。<context:component-scan> 下可以拥有若干个 <context:include-filter><context:exclude-filter> 子节点。

<!-- 配置自动扫描的包 不包括Controller-->
<context:component-scan base-package="com.zcc.mh">
    <context:exclude-filter
            type="annotation"
            expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- 1、配置自动扫描的包 只扫描Controller,
将默认的filter改为false:use-default-filters="false"-->
<context:component-scan base-package="com.zcc.mh" use-default-filters="false">
    <!--只扫描控制器  -->
    <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<context:include-filter><context:exclude-filter> 子节点支持多种类型的过滤表达式:
这里写图片描述

组件装配

  <context:component-scan> 元素还会自动注册 AutowiredAnnotationBeanPostProcessor 实例, 该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性。
  
使用 @Autowired 自动装配 Bean
  @Autowired 注解自动装配具有兼容类型的单个 Bean属性。
  构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解。
  默认情况下,所有使用 @Authwired 注解的属性都需要被设置。 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常。 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false。
  默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称。Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称。
  @Authwired 注解也可以应用在数组类型的属性上。 此时 Spring 将会把所有匹配的 Bean 进行自动装配。
  @Authwired 注解也可以应用在集合属性上,此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean。
  @Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean,此时 Bean 的名称作为键值。

使用 @Resource 或 @Inject 自动装配 Bean
  Spring 还支持 @Resource 和 @Inject 注解,这两个注解和 @Autowired 注解的功用类似。
  @Resource 注解要求提供一个 Bean 名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为 Bean 的名称。
  @Inject 和 @Autowired 注解一样也是按类型匹配注入的 Bean, 但没有 reqired 属性
  建议使用 @Autowired 注解

Spring注解开发

1)创建Spring配置文件,引入约束;并开启注解扫描

<?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:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


    <context:component-scan base-package="com.spring.ioc"/>
</beans>

2)创建UserController类、UserDao类、UserServiceImpl类,如下:

public interface IUserService {
    void login();
}
@Service("iUserService")
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserDao userDao;

    public void login() {
        userDao.seleteUser();
        System.out.println("user login");
    }
}
@Repository
public class UserDao {

    public void seleteUser(){
        System.out.println("selete User");
    }
}
@Controller
public class UserController {

    @Autowired
    private IUserService iUserService;

    public void login(){
        iUserService.login();
        System.out.println("UserController login");
    }
}

3)使用注解完成对象的注入

@Autowired
    private IUserService iUserService;
@Autowired
    private UserDao userDao;

4)编写测试类

public class SpringTest {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserController userController = (UserController) ctx.getBean("userController");
        userController.login();

    }
}

运行结果如下:

selete User
user login
UserController login

Spring注解开发的缺点

1)代码可读性不好,不容易维护,因为我们不得不在代码里找依赖关系。
2)通用性不好,比如哪天我们的代码不用Spring了,那么我们就得一个一个删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值