文章目录
自动注入原理
参考Spring Cloud Alibaba 微服务原理与实战 3.3
@SpringBootApplication
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AutoConfigurationImportSelector.class
@SpringBootApplication的
@EnableAutoConfiguration中@Import(AutoConfigurationImportSelector.class)
改类实现了ImportSelector接口
public interface ImportSelector {
//这个方法返回的都会被注入容器中
String[] selectImports(AnnotationMetadata importingClassMetadata);
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
AutoConfigurationImportSelector#selectImports
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//从
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
- getAutoConfigurationEntry 主要根据这个方法找到需要注入的bean
- getConfigurations() 单纯get数组返回
AutoConfigurationImportSelector#getAutoConfigurationEntry
作用:获取到要配置的类,根据一些规则排除掉一些类
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获取@EnableAutoConfiguration中的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获得所有自动装配的配置类,后面分析
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//去除重复配置项目
configurations = removeDuplicates(configurations);
//根据@EnableAutoConfiguration中的属性去除一些配置类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
//广播事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
AutoConfigurationImportSelector#getCandidateConfigurations
作用:这个方法是真正从文件中获取配置类的方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这个load就是从配置文件中读取一堆Configurations的配置类
List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
.getCandidates();
Assert.notEmpty(configurations,
"No auto configuration classes found in "
+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
这个方法老版本的boot和新版本的boot有所不用(此处是新版本)
-
老版本
会先从.propertiest的这个文件中得到自动装配条件然后再从spring.factories中获得对应的configuration配置类 -
新版本
直接读取这个文件,里面就是一批的configuration配置类
在这些configuration类中根据条件再来判断是否加载,就可以实现按需加载
例如
@Conditional 按需加载
这个注解是spring中的,可以实现Condition接口来实现是否注入,springboot进行了优化
可以作用于类或者方法上
自己实现@Enable…类似注解
自己也能实现类似的@Enable…注解
//想要注入的类
public class User {}
public class Person {}
实现了ImportSelector 接口
public class myConfig implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{Person.class.getName(),User.class.getName()};
}
}
自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(myConfig.class)
public @interface EnableMyBean {
}
在启动类上加上注解即可注入自己的bean
@SpringBootApplication
@EnableMyBean
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
自定义starter
Starter是Spring Boot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境( 条件)进行自动配置。使用者只需要依赖相应功能的Starter,无需做过多的配置和依赖,Spring Boot就能自动扫描并加载相应的模块。
总结:
- 它整合了这个模块需要的依赖库;
- 提供对模块的配置项给使用者、并可以对配置项提供默认值,使得使用者可以不指定配置时提供默认配置项值,也可以根据需要指定配置项值;
- 提供自动配置类对模块内的Bean进行自动装配
例如,在Maven的依赖中加入spring-boot-starter-web就能使项目支持Spring MVC,并且Spring Boot还为我们做了很多默认配置,无需再依赖spring-web、spring-webmvc等相关包及做相关配置就能够立即使用起来。
例如:一个模块只有一个User类,但是通过这个starter可以根据配置文件来配置默认的User类属性,并自动加入容器
首先创建一个新项目,并使用maven install 加入到仓库
如果没有自动注入使用的时候new出对象,现在改写成starter实现自动注入并且初始化值
1.新建一个spingboot项目(3.0要支持jdk17,所以创建2.7.8的版本),修改配置文件,否则其他项目无法读取依赖
2.编写配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "chen.user")
@Data
public class myUserProperties {
private String name = "ck";
private Integer age = 66;
}
@ConfigurationProperties(prefix = “chen.user”) 代表是配置文件的前缀为chen.user。
等于默认配置chen.user.name = ck 和 chen.user.age = 66,要配合@EnableConfigurationProperties或者@Configuration才有效果,如果配置文件中相同的属性则替换
@Configuration
//引入配置类
@EnableConfigurationProperties(myUserProperties.class)
//加载条件
@ConditionalOnClass(MyUser.class)
public class myUserConfig {
@Bean
//配置文件中chen.user.enalbe = true才会注入这个bean
@ConditionalOnProperty(value = "chen.user.enable",havingValue = "true")
public MyUser myUser(myUserProperties myUserProperties)
{
MyUser myUser = new MyUser();
myUser.setName(myUserProperties.getName());
myUser.setAge(myUserProperties.getAge());
return myUser;
}
}
3.编写配置文件(根据自动注入原理)
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.chenke.myusertestspringbootstarter.config.myUserConfig
org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.chenke.myusertestspringbootstarter.config.myUserConfig
测试下这两个文件只要有其中一个就可以写入
4.install这个springboot项目
5.在其他的springboot引入这个依赖
<dependency>
<groupId>com.chenke</groupId>
<artifactId>myusertest-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
application.properties
//根据自己设定 为true才会注入
chen.user.enable = true
//如果不写这两个将用默认值
chen.user.name = zssm
chen.user.age = 250
项目启动后容器中就会自动存在一个 MyUser(name=zssm, age=250)