【Spring】如何获取Bean对象(对象装配)

前言 

本期讲解,属性注入、Setter注入、构造方法注入

目录

1. 属性注入

1.1 繁琐的获取Bean对象

1.2 依赖注入(使用@Autowired)

1.3 属性注入优缺点

2. Setter注入

3. 构造方法注入


1. 属性注入

创建一个项目如下,有 DogControllerDogRepositoryDogService 类和一个 App 启动类,此外也配置好两个 .xml 文件。


1.1 繁琐的获取Bean对象

DogRepository 中编写代码如下:

@Repository
public class DogRepository {
    public int hello() {
        System.out.println("Hello Dog!");
        return 1;
    }
}

在之前的学习中,我们获取 Bean 对象通过获取 Spring 容器,得到 Bean 对象,再使用 Bean 对象。

当我们在 DogService 中想要使用 hello 方法,如下所示:

@Service
public class DogService {
    public int hello() {
        // 1.获取 Spring 容器
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 2.获取 Bean 对象
        DogRepository dogRepository =
                context.getBean("DogRepository", DogRepository.class);
        // 3.使用 Bean 对象
        dogRepository.hello();
        return 1;
    }
}

1.2 依赖注入(使用@Autowired)

更加简单的获取方式为使用 @Autowired 注解,即在类中直接使用声明 DogRepository 类并使用。使用场景如下:

  1. 按类型装配‌:@Autowired默认按照类型进行装配,如果容器中有多个相同类型的Bean,则会抛出异常。
  2. 按名称装配‌:如果需要按名称进行装配,可以配合@Qualifier注解使用,指定具体的Bean名称。

(1)按类型装配:直接在 DogService 中注入 DogRepository 类,并获取 DogRepository 类里面的 hello 方法:

@Service
public class DogService {

    @Autowired DogRepository dogRepository;

    public int hello() {
        dogRepository.hello();
        return 1;
    }
}

 创建一个测试类测试上述代码是否正确:

class DogServiceTest {
    @Test
    void hello() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        DogService dogService =
                context.getBean("dogService",DogService.class);
        dogService.hello();
    }
}

执行结果:


(2)按照名称装配

@Autowired 依赖注入会根据 getType 来获取对象,如果只读取到一个就直接使用对象。如果读取到多个则使用 getName 来进行匹配,此时我们就可以用到 @Qualifier 注解。

Cat 类主要内容有 idnamecontent,在该类中设置 getter setter 方法并重写 toString 方法:

public class Cat {

    private int id;
    private String name;
    private String content;

    @Override
    public String toString() {
        return "Cat{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Cats 类用来设置两个小猫,通过 set 方法设置小喵1和小喵2。

@Component
public class Cats {


    @Bean("cat1")
    public Cat cat1(){
        Cat cat = new Cat();
        cat.setId(1);
        cat.setName("小喵1");
        cat.setContent("喵喵喵1");
        return cat;
    }


    @Bean("cat2")
    public Cat cat2() {
        Cat cat = new Cat();
        cat.setId(2);
        cat.setName("小喵2");
        cat.setContent("喵喵喵2");
        return cat;
    }
}

CatService 类为获取刚刚创建的对象中某一个,当我们想得到小喵2时,则在 @Qualifier 注解中设置 cat2 名称即可。

@Service
public class CatService {

    @Autowired
    @Qualifier("cat2")
    private Cat cat;

    public void hello() {
        System.out.println(cat.toString());
    }
}

测试类:

class CatServiceTest {

    @Test
    void hello() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("Spring-config.xml");
        CatService catService = context.getBean("catService", CatService.class);
        catService.hello();
    }
}

 运行结果:


1.3 属性注入优缺点

  • 功能性:无法注入一个不可变的属性(被final修饰的属性)
  • 通用性:只适用于IoC容器
  • 设计原则:更容易违背单一设计原则


2. Setter注入

  • 优点,更加符合单一设计原则
  • 缺点,无法注入一个被final修饰的对象,setter注入的对象可以被修改

代码展示

@Service
public class DogService {
    private DogRepository dogRepository;

    @Autowired
    public void setDogRepository(DogRepository dogRepository) {
        this.dogRepository = dogRepository;
    }
    public void hello() {
        System.out.println("执行了DogRepository中的hello方法");
        dogRepository.hello();
    }
}
class DogServiceTest {
    @Test
    void hello() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        DogService dogService =
                context.getBean("dogService",DogService.class);
        dogService.hello();
    }
}


无法注入被 final 修饰的对象:

 setter 注入的对象被修改

此外,使用 setter 注入 @Autowired 不可省略。


3. 构造方法注入

构造方法注入是官方推荐的注入方式,使用方法是在构造方法上方加 @Autowired,如果当前类里面只有一个构造方法也可不加。

代码展示

@Service
public class DogService {
    private  DogRepository dogRepository;

    @Autowired
    public DogService(DogRepository dogRepository) {
        this.dogRepository = dogRepository;
    }

    public void hello() {
        System.out.println("执行了DogRepository中的hello方法");
        dogRepository.hello();
    }
}

优点:

  • 可注入被final修饰的属性
  • 注入的对象不会被修改,构造方法只会加载一次
  • 构造方法注入可以保证注入对象完全初始化
  • 通用性更好

缺点:

  • 写法比属性注入复杂
  • 无法解决循环依赖问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只爱打拳的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值