Spring实战读书笔记(一):隐式的bean发现机制和自动装配

读书笔记中涉及到的书可以从这个repo下载

1 背景

我们可以通过3种方式装配bean,分别是:

  1. 在XML中进行显式配置
  2. 在Java中进行显示配置
  3. 隐式的bean发现机制和自动装配

这篇博文讲第3种方式

2 隐式的bean发现机制和自动装配

Spring从两个角度来实现自动化装配

  1. 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
  2. 自动装配(autowiring): Spring自动满足bean之间的依赖

我以一个项目为例,来描述自动化装配的过程。
项目的github地址如下:https://github.com/AChaoZJU/Vue-Spring-Boot-Get-Started

2.1 组件扫描

首先看项目的启动文件BusinessApplication.java

package com.wepay.business;

import com.wepay.business.resource.storage.StorageProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class BusinessApplication {

	public static void main(String[] args) {
		SpringApplication.run(BusinessApplication.class, args);
	}
}

重点在于@SpringBootApplication 这个annotation
注意:这个annotation是Spring Boot的annnotation
在IDEA中点开

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

我们看到有@ComponentScan这个annotation
@ComponentScan能够在Spring中启动组件扫描(compoent sacn, 默认是不开启的)。如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包(扫描这个包以及这个包下的所有子包,查找带有@Component注解的类,并且自动为其创建一个bean

@Component会发现FileSystemStorageService 这个类

package com.wepay.business.resource.storage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Objects;
import java.util.stream.Stream;

@Service
public class FileSystemStorageService implements StorageService {
...
  }

然后为其创建一个bean。
等等!!这个类只有@Service注解,没有@Component注解。这样也可以被创建成一个bean。
答案是:可以。
因为@Service注解被@Component注解修饰

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
}

OK, 我们已经FileSystemStorageService 这个类创建了一个bean

2.2 自动装配

接下来: 我们看这个bean如何被自动装配,代码见GoodResource

package com.wepay.business.resource;

import com.wepay.business.model.Good;
import com.wepay.business.repo.GoodRepository;
import com.wepay.business.resource.storage.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.List;
import java.util.Optional;

@CrossOrigin
@RestController
@RequestMapping("/api")
public class GoodResource {
  @Autowired
  private GoodRepository repository;

  private final StorageService storageService;

  @Autowired
  public GoodResource(StorageService storageService) {
    this.storageService = storageService;
  }

  ...
  }
  • 自动装配就是让Spring自动满足bean依赖的一种方法。上面GoodResource类依赖StorageService的bean。在我们的代码中,只有FileSystemStorageService 这个类实现了StorageService 这个接口。所以你也可以认为,我们依赖FileSystemStorageServicel 类的bean。
  • 在满足依赖的过程中,自动装配会在Spring应用上下文寻找匹配某个bean(指GoodResource类的bean,因为@RestController被@Component注解)需求的其他bean(指FileSystemStorageServicel 类的bean)
  • 而@Autowired帮助我们实现了自动装配。
    这表明,当Spring创建GoodResource bean的时候,会通过这个构造器( public GoodResource(StorageService storageService) )实例化并且传入一个可设置(is assignable)给StorageService的bean

在GoodResource构造函数中,我们没有进行任何实例化操作。这就是bean的作用。

以上,我们就实现了组件扫描Component Scan(发现@Component注解的类并为其创建一个bean)和自动装配(寻找bean,并在满足其他bean对这个bean的依赖需求)两个过程。

2.3 更新

在class GoodResource中,构造器的注解@Autowired注解可以不加
因为:

Starting with Spring 4.3, if a class, which is configured as a Spring bean, has only one constructor, the @Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.

详见:spring-injects-dependencies-in-constructor-without-autowired-annotation

package com.wepay.business.resource;

import com.wepay.business.model.Good;
import com.wepay.business.repo.GoodRepository;
import com.wepay.business.resource.storage.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.List;
import java.util.Optional;

@CrossOrigin
@RestController
@RequestMapping("/api")
public class GoodResource {
  @Autowired
  private GoodRepository repository;

  private final StorageService storageService;

  // @Autowired 
  public GoodResource(StorageService storageService) {
    this.storageService = storageService;
  }

  ...
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章