读书笔记中涉及到的书可以从这个repo下载
我们可以通过3种方式装配bean,分别是:
这篇博文讲第3种方式
Spring从两个角度来实现自动化装配
我以一个项目为例,来描述自动化装配的过程。
项目的github地址如下:https://github.com/AChaoZJU/Vue-Spring-Boot-Get-Started
首先看项目的启动文件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
接下来: 我们看这个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;
}
...
}
在GoodResource构造函数中,我们没有进行任何实例化操作。这就是bean的作用。
以上,我们就实现了组件扫描Component Scan(发现@Component注解的类并为其创建一个bean)和自动装配(寻找bean,并在满足其他bean对这个bean的依赖需求)两个过程。
在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;
}
...
}