Spring注解详解之自动注入(@Autowired,@Qualifier,@Primary)

概述

Spring的自动注入,也叫自动装配,就是对spring中的bean进行属性赋值,Spring默认情况下是不开启自动装配的,要开启自动装配,需要显式的进行配置,spring提供的自动装配功能有四种,分别是no,byName,byType,constructor,( autodetect 这种模式已过时)

在spring的AutowireCapableBeanFactory接口中定义了这四种模式

public interface AutowireCapableBeanFactory{

    //无需自动装配
    int AUTOWIRE_NO = 0;

    //按名称自动装配bean属性
    int AUTOWIRE_BY_NAME = 1;

    //按类型自动装配bean属性
    int AUTOWIRE_BY_TYPE = 2;

    //按构造器自动装配
    int AUTOWIRE_CONSTRUCTOR = 3;

    //过时方法,Spring3.0之后不再支持
    @Deprecated
    int AUTOWIRE_AUTODETECT = 4;
}

四种装配模式

  • no :该默认是spring的默认设置,表示自动装配是关闭的,可以在bean标签里通过propertity标签进行显式的设置
<bean id="cat_c" class="com.spring.auto.autowire.Cat">bean>
<bean id="dog_d" class="com.spring.auto.autowire.Dog">bean>
<bean id="test" class="com.spring.auto.autowire.Person">
    <property name="cat" ref="cat_c"/>
    <property name="dog" ref="dog_d"/>
    <property name="say" value="测试"/>
bean>
  • byName:通过bean的名称进行注入,在进行属性自动注入时,通过属性名称在容器中匹配id为该属性名称的bean进行注入,有则注入,没有则不进行注入
  • byType:通过bean的类型进行注入,如果属性的类型在IOC容器中存在且唯一,则进行注入,如果该类型存在多个bean,则NoUniqueBeanDefinitionException异常
public class Cat {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class User {

    private String name;
    private Cat cat;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", cat=" + cat +
                '}';
    }
}
<bean id="myCat" class="com.ming.bean.Cat">
    <property name="name" value="kitty">property>
bean>

<bean id="user" class="com.ming.bean.User" autowire="byName">
    <property name="name" value="James">property>
bean>

测试方法

@Test
    public void testAutoWired() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = applicationContext.getBean(User.class);
        System.out.println(user.toString());
    }

1:当没有autowire="byName"属性时,输出结果为:User{name=‘James’, cat=null},默认不进行注入

2:当指定autowire="byName"属性时,cat的ID为myCat,输出结果为同1,没有匹配到,不注入

3:当指定autowire="byType"属性时,结果为User{name=‘James’, cat=Cat{name=‘kitty’}},注入成功

4:当执行autowire="byType"属性时,并且放开注释部分,则抛异常NoUniqueBeanDefinitionException

  • constructor:通过构造函数进行自动注入,和byType类似, 在启用了自动装配的bean中 ,通过构造方法的参数类型进行匹配,
<bean id="cat" class="com.ming.bean.Cat">
    <property name="name" value="kitty1">property>
bean>

<bean id="user" class="com.ming.bean.User" autowire="constructor">
    <constructor-arg index="0" value="James">constructor-arg>
bean>

@Autowired,@Qualifier,@Primary

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
	/**
	 * Declares whether the annotated dependency is required.
	 * 

Defaults to {@code true}. */ boolean required() default true; }

查看该源码,该注解可以使用在构造方法上,方法上,属性,参数上,注解上,只有一个required属性,可以指定自动注入是否是必须的

示例

定义service和repository

@Repository
public class UserRepositoryImpl {
    private int id ;
   
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "UserRepositoryImpl{" +
                "id=" + id +
                '}';
    }
}
@Service
public class UserServiceImpl {

    @Qualifier("userRepository1")//指定ID进行注入
    @Autowired//先按byType匹配,如果存在多个,则按byName匹配
    //@Resource(name="userRepository1")java规范的注解进行注入
    private UserRepositoryImpl userRepositoryImpl;

    @Override
    public String toString() {
        return "UserServiceImpl{" +
                "userRepositoryImpl=" + userRepositoryImpl +
                '}';
    }
	//@Autowired//先按byType匹配,如果存在多个,则按byName匹配
    public UserRepositoryImpl getUserRepositoryImpl() {
        return userRepositoryImpl;
    }
   //@Autowired//先按byType匹配,如果存在多个,则按byName匹配,
    public UserServiceImpl(@Autowired UserRepositoryImpl userRepositoryImpl) {
        //也可以使用在参数上
        this.userRepositoryImpl = userRepositoryImpl;
    }
}

定义配置类

@Configuration
@ComponentScan(value = {"com.ming.dao","com.ming.service"})
public class AutoWiredConfig {
    @Primary
    @Bean("userRepository1")
    public UserRepositoryImpl userRepository(){
        UserRepositoryImpl userRepository = new UserRepositoryImpl();
        userRepository.setId(2);
        return userRepository;
    }
}

测试方法

@Test
public void testAutoWired() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AutoWiredConfig.class);
    UserServiceImpl userService = applicationContext.getBean(UserServiceImpl.class);
    //判断注入的bean是哪个
    System.out.println(userService.getUserRepositoryImpl() == applicationContext.getBean("userRepositoryImpl"));
    applicationContext.close();
}

@Autowired:无论是使用在属性上,set方法上,还是构造方法上,其原则都是一样的:先byType进行注入,如果该类型在IOC容器中,有且只有一个,则进行注入,如果该属性类型在容器中存在多个时,则会根据属性名称进行byName进行匹配

**@Qualifier:**指定ID进行注入,当容器中存在属性类型的bean有多个时,可以通过该注解指定ID进行注入

**@Primary:**主要的,当容器中同一个类型的bean存在多个时候,有该注解的会首先注入,如果即通过该注解指定了首要注入bean,有通过 @Qualifier指定了ID进行注入,则会以 @Qualifier为准

@Resource,@Inject

@Resource(JSR250),@Inject(JSR330),这两个注解是java规范的注解,在spring中也是支持对bean的注入的

**@Resource:**默认是按照属性名称进行装配的,可以通过name属性来指定bean的ID进行注入,但是不支持spring的注解 @Primary,也没有required=false属性

**@Inject:**需要导入javax.inject的包,和@Resource一样,也不支持spring的注解 @Primary,也没有required=false属性

Spring底层组件

如果自定义的一些组件,想要使用spring的一些组件,比如ApplicationContext,BeanFactory等,可以实现spring给提供的xxxAware接口,在对象创建时,可以使用接口方法进行注入,spring的每个xxxAware接口都有xxxAwareProcessor后置处理器实现类,

public class Color implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
    private ApplicationContext applicationContext;
    @Override
    public void setBeanName(String name) {
        System.out.println("当前bean的名字:"+name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("spring传入的IOC:"+applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override//该方法可以通过$来获取环境变量的值,通过#计算SPel表达式的值
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String s = resolver.resolveStringValue("当前系统${os.name},计算#{10+20}");
        System.out.println(s);
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

配置类

@Configuration
@Import(Color.class)
public class AutoWiredConfig {

}

测试方法

@Test
public void testAutoWired() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AutoWiredConfig.class);
    Color color = applicationContext.getBean(Color.class);
    System.out.println("判断获取的applicationContext是否一样"+(applicationContext == color.getApplicationContext()));
    applicationContext.close();
}
//输出结果
当前bean的名字:com.ming.bean.Color
当前系统Windows 10,计算30
spring传入的IOC:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ccd43c2, started on Mon Mar 16 23:55:14 CST 2020
判断获取的applicationContext是否一样true

你可能感兴趣的:(Spring注解详解之自动注入(@Autowired,@Qualifier,@Primary))