Beginning Spring学习笔记——第2章(二)依赖注入

Setter注入


之前的用XML配置Bean的实例中已经有通过setter注入的方式,通过在XML文件中使用 < property name=“”, ref=“”>标签,name特性表示依赖属性的名称,ref表示注入其中的Bean的名称

    <bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>

除此之外,还可以用<property>标签的value特性直接为Bean内属性赋值

<bean id="account1" class="com.wiley.beginningspring.ch2.Account">
        <property name="id" value="1" />
        <property name="ownerName" value="John" />
        <property name="balance" value="10.0"/>
        <property name="locked" value="false" />
    </bean>

    <bean id="account2" class="com.wiley.beginningspring.ch2.Account">
        <property name="id" value="2" />
        <property name="ownerName" value="Mary" />
        <property name="balance" value="20.0"/>
        <property name="locked" value="false" />
</bean>

如果需要注入的是Collection或者Map属性,也可以用<map>、<set>等标签为之赋值

<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl">
        <property name="accountsMap">
            <map>
                <entry key="1" value-ref="account1"/>
                <entry key="2" value-ref="account2"/>
            </map>              
        </property>
    </bean>

构造函数注入


此时在Bean的定义中加入<constructor>标签采用其含参构造函数即可
首先给AccountServiceImpl定义一个含参构造函数

public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}

然后在XML配置文件中采用<constructor>标签

<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
        <constructor-arg ref="accountDao"/>
</bean>

此处ref属性同样是指向需要注入的Bean
当然,和<property>标签一样,<constructor>标签也可以用value属性来接收值,此外,当以一个类有多个构造函数时,还可通过index属性来指定参数在构造函数的位置从而指定构造函数
考察如下Foo类以及与之相关的Bar类和Baz类

public class Foo {

    private Bar bar;
    private Baz baz;

    public Foo(Bar bar, Baz baz) {
        this.bar = bar;
        this.baz = baz;
    }

    public Foo(Baz baz, Bar bar) {
        this.bar = bar;
        this.baz = baz;
    }
}


public class Bar {

}


public class Baz {

}

此时的Bean配置需要指定两个参数序号确定使用的构造函数

    <bean id="foo" class="com.wiley.beginningspring.ch2.Foo">
        <constructor-arg ref="bar" index="0"/>
        <constructor-arg ref="baz" index="1"/>
    </bean>

    <bean id="bar" class="com.wiley.beginningspring.ch2.Bar"/>

    <bean id="baz" class="com.wiley.beginningspring.ch2.Baz"/>

bar序号为0,baz序号为1,采用构造函数

    public Foo(Bar bar, Baz baz) {
        this.bar = bar;
        this.baz = baz;
    }

注意序号从0开始

构造函数+Setter注入


给类定义一个构造函数和Setter

public class Foo {

    private Bar bar;
    private Baz baz;

    public Foo(Bar bar) {
        this.bar = bar;
    }

    public void setBaz(Baz baz) {
        this.baz = baz;
    }
}

此时可以在同一个Bean标签下完成构造函数和setter的注入

    <bean id="foo2" class="com.wiley.beginningspring.ch2.Foo">
        <constructor-arg ref="bar"/>
        <property name="baz" ref="baz"/>
    </bean>

Bean定义重写


当不同的配置源中存在两个同名的Bean定义的时候,根据给定顺序的第二个Bean定义将会重写第一个Bean定义。相同的配置源中不允许出现两个同名Bean定义。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
Configuration1.class, Configuration2.class);

在容器创建中如此组合了这样两个配置类时,重复的Bean会按照Configuration2.class中的配置

depends-on特性


该特性存在于<bean>标签内,用于指定bean之间的依赖关系,这样的依赖关系决定他们的创建和销毁顺序

<bean id="a" class="com.wiley.beginningspring.ch2.A" depends-on="b,c"/>

这样创建的Bean a依赖于Bean b和c,a会在b, c创建之后被创建,且如果a不是无状态Bean会在b, c销毁前销毁

无状态Bean和有状态Bean

无状态Bean没有状态变量。
例如

public class A { 
       public A() {} 
       public String hello() { 
          return "Hello 谁?"; 
       } 
    } 

相比之下有状态Bean存在状态变量,例如

public class B { 
       private String name; 
       public B(String arg) { 
       this.name = arg; 
       } 
       public String hello() { 
          return "Hello" + this.name; 
       } 
    } 

其中的name就是状态变量
详情参见 有状态Bean和无状态Bean

自动装配


可以不在Bean定义中显式定义依赖项而是让Spring容器自动往Bean中注入依赖项,有byType、byName和constructor三种模式

byType模式

byType模式中Spring通过反射查看Bean中定义的类,然后注入容器中类型匹配的属性,通过调用这些属性的setter方法完成

  • XML配置
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl" autowire="byType"/>

<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl"/>
  • Java配置
@Bean(autowire=Autowire.BY_TYPE)
    public AccountService accountService() {
        AccountServiceImpl bean = new AccountServiceImpl();
        return bean;
    }

容易发现,有多个类型Bean可以装配的时候会装配失败

byName模式
  • XML配置
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl" autowire="byName"/>

<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl"/>
  • Java配置
@Bean(autowire=Autowire.BY_TYPE)
    public AccountService accountService() {
        AccountServiceImpl bean = new AccountServiceImpl();
        return bean;
    }
@Autowired

使用该注解时不必向@Bean注解添加autowire特性也可实现自动装配,加了@Autowired注解的setter方法会自动注入合适依赖

public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;

    @Autowired
    @Qualifier
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    //Implementation
}

@Configuration
public class Ch2BeanConfiguration {

    @Bean
    @Qualifier
    public AccountDao accountDao() {
        AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
        //depedencies of accountDao bean will be injected here...
        return bean;
    }
}

该种方法在有多个符合条件依赖项时应该添加@Qualifier注解指定注入的Bean,此时装配模式变为byName

Bean查找


在Spring容器控制之外的地方获取Bean可用ApplicationContext.getBean()方法执行显式Bean查找

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值