欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring学习之04自动装配

程序员文章站 2022-05-24 14:37:54
...

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学习之04自动装配

可选值:

  • 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。