Spring二(依赖注入)

一. 装配Bean介绍

创建应用对象之间协作关系的行为通常称为装配(wiring)

三种装配机制:

  •   在XML中进行显式配置
  •   在Java中进行显式配置
  •   隐式的bean发现机制和自动装配

二. 自动化装配bean

Spring从两个角度来实现自动化装配:

  •   组件扫描: Spring会自动发现应用上下文中所创建的bean
  •   自动装配: Spring自动满足bean之间的依赖

自动化装配步骤: ①启用组件扫描, ②为bean添加注解实现自动化装配

①启用组件扫描:

  • Java显式配置启动组件扫描
  • XML显示配置启动组件扫描

    Java显式配置      

package soundsystem;

import org.springframework.context.annotation.compoentScan;

import org.springframework.context.annotation.Configuration;


@Configuration

@ComponentScan

public class CDPlayerConfig {

}

      使用@ComponentScan注解, 启动组件扫描. @ComponentScan默认扫描与配置类相同的包, 查找带有@Component注解的类, 发现后会自动为该类创建一个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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">


    <context: component-scan base-package="soundsystem" />


</beans>

②声明bean, 设置扫描的基本包

声明bean:

    声明bean组件用@Component

    @Component 注解在上, 表明该类会作为组件类, 并告知Spring要为这个类创建bean

    Spring支持将@Named作为@Component注解的替代方案.在大多数场景,两者是可以互相替换的.一般用@Component

为组件扫描的bean命名:

     默认ID是类名第一个字母变小写.  自己命名则用: @Component("yourName")

设置组件扫描的基本包:

    默认以配置类所在的包作为基础包(base package)来扫描组件

    明确设置基础包,用basePackages属性:

                设置一个基础包

  @Configuration

  @ComponentScan(basePackages="soundsystem")

      public class CDPlayerConfig { }

              设置多个基础包:

@Configuration

@ComponentScan(basePackages={"soundsystem", "video"})

    public class CDPlayerConfig { }

   上面属性都是用的String类型表示, 这是类型不安全(not type-safe), 如果重构代码可能出错

    除了将包设置为String类型外,还可以将其指定为包中所包含的类或接口

@Configuration

@ComponentScan(basePackageClasses={CDPlayer.class, DVDPlayer.class})

    public class CDPlayerConfig { }

③为bean添加注解实现自动装配:

    自动装配就是让Spring自动满足bean依赖的一种方法, 在满足依赖的过程中, 会在Spring应用上下文中寻找匹配某个bean需求的其他bean.用@Autowired来注解要自动装配的bean,

    @Autowired使用:

             @Autowired注解在有参构造器上, 表明当Spring创建该类 bean时, 会通过这个构造器来进行实例化,并且会传入一个可设置给该构造器参数类型的bean

             @Autowired注解在Setter方法上

         @Autowired注解在类的任何方法上, 不管是构造器, Setter方法还是其他的方法, Spring都会尝试满足方法参数上所声明的依赖.Ⅰ如果有且只有一个bean匹配依赖需求的话, 那么这个bean将会被装配进来. Ⅱ如果没有匹配的bean, 那么在应用上下文创建的时候, Spring会抛出一个异常. Ⅲ如果有多个bean都能满足依赖关系的话, Spring将抛出异常, 表明没有明确指定要选择哪个bean进行装配.

    在大多数场景下,@Inject和@Autowired可以相互替换, 一般两个都可以用

三. Java代码装配bean (JavaConfig)

①创建JavaConfig类

创建JavaConfig类的关键在于为其添加@Configuration注解. @Configuration注解表明这个类是一个配置类, 该类应该包含在Spring上下文中如何创建bean的细节.

     例:    

package soundsystem;

import org.springframework.context.annotation.Configuration;


@Configuration

public class CDPlayerConfig { }

  这个CDPlayerConfig就是一个JavaConfig类, 使用了@Configuration. 因为这里要用JavaConfig所以不用@ComponentScan注解

②声明简单的bean

  在JavaConfig中声明bean, 需要编写一个方法, 这个方法会创建所需类型的实例, 然后给这个方法添加@Bean注解.

例: 声明一个bean

@Bean
public CompactDisc sgtPeppers() {
    return new SgtPeppers();
}

@Bean注解会告诉Spring这个方法将会返回一个对象, 该对象要注册为Spring应用上下文中的bean.方法体中包含了最终产生bean实例的逻辑.

默认情况下, bean的ID与带有@Bean注解的方法名是一样的.如果想用不同的名字,可以用name属性重命名该方法.

方法只要能返回一个实例即可,无论是用构造器, Setter方法还是其他Java代码, 只要能产生bean实例都可以.

③JavaConfig配置实现注入

上面声明的简单bean中, 没有其他依赖. 下面声明一个CDplayer bean, 它依赖于CompactDisc(方法sgtPeppers()返回CompactDisc类型实例).

@Bean
public CDPlayer cdPlayer() {
    return new CDPlayer(sgtPeppers());
}

方法cdPlayer()和sgtPeppers()都是使用@Bean注解, 表明这个方法会创建一个bean实例并将其注册到Spring应用上下文中. 所创建的bean ID默认与方法的名字相同.

但是cdPlayer()和sgtPeppers()实例化方式不同, sgtPappers()使用默认的构造器构建实例. 而cdPlayer()是调用了需要传入CompactDisc对象的构造器来创建CDPlayer实例.

看起来, CompactDisc是通过调用sgtPeppers()得到的, 但情况并非完全如此.因为sgtPeppers()方法上添加了@Bean注解, Spring将会拦截所有对它的调用. 并确保直接返回该方法所创建的bean, 而不是每次都对其进行实际的调用.

例如要创建两个bean

@Bean
public CDPlayer cdPlayer() {
    return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer anotherCDPlayer() {
    return new CDPlayer(sgtPeppers());
}

上面创建两个同一个依赖(sgtPeppers())的bean, 如果对sgtPeppers()调用像其他Java方法调用一样的话, 那么每个CDPlayer实例都会有一个自己特有的CompactDisc实例.但实际上, 一个CompactDisc实例就够了. 我们可以将同一个CompactDisc实例注入到任意数量的其他bean之中. 默认情况下, Spring中bean都是单例的.所以, Spring会拦截对sgtPeppers()的调用并确保返回的是Spring所创建的bean.因此上面两个bean会得到相同的CompactDisc实例.

除了通过调用方法来引用bean, 还可以将依赖作为参数来引用bean

@Bean
public CDplayer cdPlayer(CompactDisc compactDisc) {
    return new CDPlayer(compactDisc);
}

带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例

四. XML装配bean

1. 创建XML配置规范

在使用XML为Spring装配bean之前, 需要创建一个新的配置规范.

Spring XML 基本配置:

<?xml version="1.0" encoding="UTF-8"?>

<!-- Application context definition. -->
<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" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/jdbc
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"
	default-autowire="byName">
	

  <!-- configuration details go here -->
	
</beans>

2. 声明一个简单的<bean>

例如声明一个CompactDisc bean:

<bean class="soundsystem.SgtPeppers" />

创建这个bean的类是通过class属性来指定的, 并且要使用全限定的类名.

因为没有明确给定ID, 所以这个bean将会根据全限定类名来进行命名. 在本例中, bean的ID将会是"soundsystem.SgtPeppers#0".如果声明了另一个SgtPeppers, 并且没有明确进行标识, 那么它自动得到的ID将会是"soundsystem.SgtPeppers#1".

使用id属性, 为每一个bean设置名字

<bean id="compactDisc" class="soundsystem.SgtPeppers" />

当Spring发现这个<bean>元素时, 它将会调用SgtPeppers的默认构造器来创建bean.

3. 借助构造器注入初始化bean

在Spring XML配置中, 声明bean只有一种方式,但是声明DI有多种可选的配置方案和风格.

构造器注入配置方案:

  • <constructor-arg> 元素
  • 使用Spring3.0 所引入的c-命名空间

①构造器注入bean引用

下面将SgtPeppers bean注入到CDPlayer bean中.

<bean id="cdPlayer" class="soundsystem.CDPlayer">
    <constructor-arg ref="compactDisc">
</bean>

<constructor-arg>元素告知Spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中.

在使用c-命名空间时,先在XML顶部文件声明添加一个模式:

xmlns:c="http://www.springframework.org/schema/c"

使用c-命名空间完成相同功能:

<bean id="cdPlayer" class="soundsystem.CDPlayer"
    c:cd-ref="compactDisc" />

上面这种方式调试无法执行

替代方案:

<bean id="cdPlayer" class="soundsystem.CDPlayer"
    c:_0-ref="compactDisc" />

②将字面量注入到构造器中

使用value属性

<constructor-arg value="The Beatles" />

使用c-命名空间有两种方法, 一是引用构造器参数的名字

<bean id="teacher"
    class="school.person"
    c:_id="001"
    c:_name="Tom" />

另一种是通过参数索引装配相同的字面量值

<bean id="teacher"
    class="school.person"
    c:_0="001"
    c:_1="Tom" />

③装配集合

使用<constructor-arg>的 <list>或<set>子元素. c-命名空间无法装配集合

使用<list>元素

<constructor-arg>
    <value>Tom</value>
    <value>Jack</value>
    <value>Mikes</value>
</constructor-arg>

类似的可以使用<ref>元素代替<value>

使用<set>元素与上相似, 但使用<set>时, 所有的重复的值都会被忽略掉,存放顺序也不保证.

4. 设置属性

上面的类都是通过构造器注入的, 没有使用属性的Setter方法. 接下来为如何受用Spring XML实现属性注入.

使用规则: 强依赖使用构造器注入, 可选依赖使用属性注入

<bean id="cdPlayer"
    class="soundsystem.CDPlayer">
 <property name="compactDisc" ref="compactDisc" />
</bean>

下面使用p-命名空间

添加模式

xmlns:p="http://www.springframework.org/schema/p"

使用p-命名空间完成上面功能

<bean id="cdPlayer"
    class="soundsystem.CDPlayer"
    p:compactDisc-ref="compactDisc" />

装配字面值
 

<bean id="customer"   class="shop.customerbook">
<property name="id" value="001" />
<property name="books" >
  <list>
    <value>the name</value>
    <value>bule sky</value>
    <value>come on</value>
  </list>
</property>
</bean>

使用p-命名空间完成上面功能

<bean id="customer"   class="shop.customerbook"
     p:id="001">
<property name="books" >
  <list>
    <value>the name</value>
    <value>bule sky</value>
    <value>come on</value>
  </list>
</property>
</bean>

p-命名空间虽然不能装配集合,但是util-命名空间可以装配集合

添加模式

xmlns:util="http://www.springframework.org/schema/util"

<util:list id="book">
    <value>the name</value>
    <value>bule sky</value>
    <value>come on</value>
</util:list>
<bean id="customer"   class="shop.customerbook"
     p:id="001"
     p:book-ref="book" />

util-命名空间还有set, map, properties等其他元素.

五. 导入和混合配置

1. 在JavaConfig中引入XML配置

2. 在XML配置中引用JavaConfig

猜你喜欢

转载自blog.csdn.net/wanderc/article/details/86371899