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;
  }

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