Spring注解驱动 自动装配(三)

一、@Autowired自动装配基操

新建Person组件,并给name属性赋值为"张三",age属性赋值为30。

package com.example.demo.annotation;

import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component
public class Person {
    public  String name="张三";
    
    public  Integer age=30;
    
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
}

测试单元,用@Autowired自动装配Person组件。

package com.example.demo;

import com.example.demo.annotation.MainConfig;
import com.example.demo.annotation.Person;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
class annotationTest {

    @Autowired
    Person person;

    @Test
    void test(){
        System.err.println(person);
    }
}

打印运行结果到控制台,发现这个自动装配可以生效。
在这里插入图片描述
我们接下来在配置类中也注册一个Person组件,赋值name属性为"李四",age属性为40以示区别。

package com.example.demo.annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value = "com.example.demo.annotation")
public class MainConfig {

    @Bean
    public Person person111(){
        return new Person("李四",40);
    }

}

这样容器中就有两个同类型的组件了,一个id为类名首字母小写person,另一个为bean方法名person111。
下面在单元测试中看看是也不是?

@Test
void contextLoads() {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfig.class);
    //按Person类型获取组件
    String[] typeNames=applicationContext.getBeanNamesForType(Person.class);
    for (String typeName:typeNames) {
        System.err.println(typeName);
    }
}

打印运行结果出来看看:
在这里插入图片描述
可以看到IOC容器中现在有两个Person类型的组件。

再来运行单元测试,看看结果:
在这里插入图片描述
可以看到虽然现在容器中有两个Person类型的组件,但是默认装配的是 id 为 person 的组件。
那么要想装配 id 为 person111 的组件怎么办呢?

二、多个同类型组件的自动装配

1、使用@Primary注解

直接在bean组件的注册位置加上@Primary注解

@Bean
@Primary
public Person person111(){
    return new Person("李四",40);
}

运行单元测试,打印结果如下:
在这里插入图片描述
由结果发现,标注了@Primary的bean组件会被优先装配。

2、修改装配名字

注释掉刚才加的@Primary注解,修改自动装配属性的名字:

@Autowired
Person person111;

然后修改单元测试并运行

@Test
void test(){
    System.err.println(person111);
}

运行结果发现现在生效的也是 id 为 person111 的组件:
在这里插入图片描述

3、使用@Qualifier注解

用@Qualifier注解的value属性直接指定要装配的组件id。现在指定装配的组件id为person。

@Autowired
@Qualifier(value = "person")
Person person111;

再次运行单元测试,发现确实又装配了id为person的组件:
在这里插入图片描述
除了@Autowired注解以外,@Resource、@Inject注解也可以用来进行自动装配。
但是@Resource功能不够强大,@Inject需要导入额外的包,在Spring框架下,我们的首选仍然是@Autowired。
另外@Resource和@Inject在离开了Spring框架后仍然能够正常使用,而@Autowired目前只在Spring框架中生效。

三、@Profile根据环境自动装配

有时候我们需要根据不同的环境注册不同的组件,假定现在有dev开发、test测试和prod生产三个环境。
要怎么实现不同的环境装配不同的组件呢?@Profile注解可以帮您办到。
配置类,给配置类中多注册几个bean:

package com.example.demo.annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {

    @Bean
    public Person person111(){
        return new Person("李四",40);
    }

    @Bean
    public Person person222(){
        return new Person("张三",30);
    }

    @Bean
    public Person person333(){
        return new Person("王五",50);
    }
}

测试单元:

package com.example.demo;

import com.example.demo.annotation.MainConfig;
import com.example.demo.annotation.Person;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
class annotationTest {
    
    @Test
    void contextLoads() {
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfig.class);
        String[] typeNames=applicationContext.getBeanNamesForType(Person.class);
        for (String typeName:typeNames) {
            System.err.println(typeName);
        }
    }

}

运行测试单元看看IOC容器中这些组件
在这里插入图片描述
果然都是刚才注册的bean组件。现在来给它们都标上@Profile注解,并分别设置为prod、test、dev环境。

@Profile("prod")
@Bean
public Person person111(){
    return new Person("李四",40);
}

@Profile("test")
@Bean
public Person person222(){
    return new Person("张三",30);
}

@Profile("dev")
@Bean
public Person person333(){
    return new Person("王五",50);
}

运行单元测试,发现IOC容器中一个Person组件都没了
修改一下单元测试将环境设置为prod和test(可同时制定多种环境)。

@Test
void contextLoads() {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
    applicationContext.getEnvironment().setActiveProfiles("prod","test");
    applicationContext.register(MainConfig.class);
    applicationContext.refresh();

    String[] typeNames=applicationContext.getBeanNamesForType(Person.class);
    for (String typeName:typeNames) {
        System.err.println(typeName);
    }
}

再次运行单元测试,发现设为prod和test的组件都被导入进了IOC容器。
在这里插入图片描述
下面删掉设为dev的组件的@Profile注解,再次运行单元测试:
在这里插入图片描述
发现没有标注@Profile注解的bean默认是都要导入到容器中的。
另外这个注解也可以标注在类上,下面在配置类上标注@Profile注解并设为test环境。

package com.example.demo.annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Profile("test")
@Configuration
public class MainConfig {

    @Bean
    public Person person111(){
        return new Person("李四",40);
    }

    @Bean
    public Person person222(){
        return new Person("张三",30);
    }

    @Bean
    public Person person333(){
        return new Person("王五",50);
    }
}

这就表示只有在test环境下这些bean才会被导入到IOC容器中。
单元测试,设置激活环境为test:

@Test
void contextLoads() {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
    applicationContext.getEnvironment().setActiveProfiles("test");
    applicationContext.register(MainConfig.class);
    applicationContext.refresh();
    String[] typeNames=applicationContext.getBeanNamesForType(Person.class);
    for (String typeName:typeNames) {
        System.err.println(typeName);
    }
}

结果不出所料:
在这里插入图片描述
由于当前环境正是test,所以配置类中所有的bean组件都被导入到了IOC容器中。

发布了17 篇原创文章 · 获赞 1 · 访问量 301

猜你喜欢

转载自blog.csdn.net/weixin_43424932/article/details/104081211