Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式!
  • Spring会在上下文自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

  1. 在xml中显式的配置
  2. 在java中显示的配置
  3. 隐式的自动装配

这里我们主要讲第三种:自动化的装配bean。

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;

自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

推荐不使用自动装配xml配置 , 而使用注解 .


自动装配介绍

显式配置的案列

public class Man {
    private String name;
    private Pet pet;
    private Woman woman;
 	...   
}
public class Pet {
    public void show() {
        System.out.println("pet");
    }
}
public class Woman {
    public void show() {
        System.out.println("Oh yes!");
    }
}
<bean id="pet" class="com.magee.pojo.Pet" />
    <bean id="woman" class="com.magee.pojo.Woman"/>

    <bean id="man" class="com.magee.pojo.Man"
          p:pet-ref="pet"
          p:name="magee"
          p:woman-ref="woman"
    />

这种就是显式,即手动明确地去装配每一个bean对象含有的值,在bean对象多或bean含有的属性非常多的时候采用这种方式是十分繁琐的,Spring为我们提供了可以自动装配的方法:

使用autowire

spring 第三方jar自动装配 spring中自动装配_java

可选值:

  • Byname:自动在容器中寻找和该bean对象set方法后面的值对应的beanid
  • ByType:自动在容器中寻找和该bean对象属性类型相同bean

使用注解实现自动装配

通常情况下,使用xml方式实现自动注解过于麻烦,现在大部分的开发都使用注解的方式来开发,

spring2.5以上就已经支持注解的方式来开发应用,

我们要使用注解首先需要在xml文件中添加<context:annotation-config/>和约束 xmlns:context="http://www.springframework.org/schema/context"

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

    <!--开启注解支持-->
    <context:annotation-config/>

</beans>

小要点:xml和注解方式都是通过反射机制来实现的注入,xml方式是通过调用set方法,而注解则是根据直接获取属性或者注解的方法来实现注入,因而注解方式不需要强制使用set方法,同时也支持方法上参数的自动装配


1、使用@Autowired

可以使用JSR 330的@Inject注释代替Spring的@Autowired注释
想进一步了解的,可以点击该链接
Spring下的@Inject、@Autowired、@REsource注解的区别

直接在属性上使用即可!也可以在方法上使用!

自动的从容器中获取属性对应或者方法参数上对应的bean值

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

允许空值的属性/参数

  • 如果是在方法上使用@Autowired,则可以再参数中使用@Nullable注解,则当在容器中没有找到该bean的时候也不会报错
  • 如果是在属性上使用的时候,可以使用@Autowired(false),将required属性(默认为true)设置为false

Autowired自动装配,会先使用ByType的方式来自动装配,如果一个对象中出现多个同一类型的属性则会按照Byname的方式自动装配


2、使用@Primary

简单理解–标志首选的bean

由于按类型自动装配可能会导致多个候选对象,因此通常有必要对选择过程进行更多控制。 一种实现此目标的方法是使用Spring的@Primary注释。 @Primary表示当多个bean可以自动连接到单值依赖项的候选对象时,应优先考虑特定的bean。 如果候选中恰好存在一个主bean,则它将成为自动装配的值

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...
}

xml下则使用 方法

<bean class="example.SimpleMovieCatalog" primary="true"></bean>
<bean class="example.SimpleMovieCatalog"></bean>

3、使用@Qualifier

标示首选bean只能标示一个优先的可选方案,当首选bean的数量超过一个时,没有其他方法进一步缩小可选范围。

这时就要用到限定符了,Spring的限定符能够在所有可选的bean上进行缩小范围操作,最终能够达到只有一个bean满足所规定的限制条件。如果将所有的限定符都用上后依然存在歧义性,可以继续使用更多的限定符来缩小选择范围。

@Qualifier 注解是使用限定符的主要方式。

它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。

@Autowired
@Qualifier("dog")
public void setAnimal(Animal animal){
    this.animal = animal;
}

为@Qualifier 注解所设置的参数就是想要注入的bean的ID。

更准确地说,@Qualifier(“dog”)所引用的bean要具有String类型的“dog”限定符。

在bean中,如果没有其他限定符的话,所有的bean都会给一个默认的限定符,这个限定符与bean的ID相同。

在setAnimal()方法上所指定的限定符与要注入的bean的名称是紧耦合的,对类名称的任意改动都会导致限定符失效。


可以为bean设置自己的限定符,而不是依赖于将bean ID作为限定符。

这里要在bean声明上添加@Qualifier注解

@Component
@Qualifier("faith")
public class dog implements Animal {...}

这时,在注入的地方,只要引用faith限定符就可以了。

@Autowired
@Qualifier("faith")
public void setAnimal(Animal animal){
    this.animal = animal;
}

在通过Java配置显式定义bean定义bean的时候,@Qualifier也可以与@Bean注解一起使用。

小结:
	1、spring默认将注册的bean的beanid设置限定符,可以通过使用@Qualifier来手动改变
	2、在自动装配的bean有多个可选bean时候,如果@Primary有多个,可以通过@Qualifier来进一步筛选要
	使用的bean。
	3、面向特性的限定的限定符要比基于bean ID的限定符更好一些。但是如果多个bean具备相同的特性的话,这样也会产生歧义性

4、创建自定义限定符

或许你认为可以在@Qualifier注解后面再加一个@Qualifier注解来进一步缩小范围,但是Java不允许在同一个条目上重复出现相同类型的多个注解,如果有多个相同的注解,编译器会报错。使用@Qualifier注解并没有办法将自动装配的可选bean缩小范围至仅有一个可选的bean。

这种情况下,要创建自定义注解,借助这样的注解来表达bean所希望限定的特性。创建的这个注解,它本身要使用@Qualifier注解来标注,比如我们定义一个Faith注解,如下所示:

@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@public @interface Faith{ }

同理,可以再定义一个Lovely注解。

使用方式为:

@Component
@Faith
@Lovely
public class Dog implements Animal(Animal animal){
    this.animal = animal;
}

通过声明自定义的限定符注解,我们可以同时使用多个限定符,不会再有Java编译器的限制或者错误。而且相对于使用原始的@Qualifier并借助String类型来指定限定符,自定义的注解也更为类型安全。

小结

@Autowired与@Resource异同:
1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType如果出现多个则进一步ByName,@Resource先byName。