微服务
先看完 微服务和组件化微服务的未来
初探:springBoot的自动装配
在pom.xml中父工程下的
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
spring-boot-dependencies 帮我们管理了对所有jar包的版本依赖(在使用jar包时不需要指定即可使用,可以避免jar包版本冲突)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
例如
<properties>
<activemq.version>5.15.3</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.63</appengine-sdk.version>
<artemis.version>2.4.0</artemis.version>
......................................
<properties>
pom.xml中的启动器
启动器的作用?例如我们导入了web的启动器
spring-boot-starter-web
即可支持全栈式Web开发,包括Tomcat和spring-webmvc。
<!--启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
主类SpringBootApplication
@SpringBootApplication标注这个类是一个springboot的应用,其也是一个组合注解,该注解下的所有注解将会被导入Spring容器中。
其注解包括了4个标准注解、2个扫描注解、一个配置类注解和一个开启自动配置类注解。
//@SpringBootApplication标注这个类是一个springboot的应用
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//通过反射获得SpringbootApplication的对象启动它
SpringApplication.run(SpringbootApplication.class, args);
}
}
关于java注解和自定义注解之后会补上
@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) })
@ConfigurationPropertiesScan
public @interface SpringBootApplication {
}
注解
@SpringBootConfiguration :声明该类是一个SpringBoot的配置类
@Configuration :生命该类是spring的配置类
@Component:该类加入了spring容器 是一个spring组件
@EnableAutoConfiguration:开启自动装填配置
@AutoConfigurationPackage :自动装填配置包
@Import(AutoConfigurationPackages.Registrar.class) :自动配置包注册
@Import(AutoConfigurationImportSelector.class) :自动配置导入选择器
注解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
其实引入了两个类:
AutoConfigurationPackages.Registrar
AutoConfigurationImportSelector
@AutoConfigurationPackage会将我们 注解@ComponentScan()扫描当前启动类及其子类所有的注解并加入我们的Spring容器中
@Import(AutoConfigurationImportSelector.class)自动配置选择器如何自动装配
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
首先会判断 调用isEnable() 方法 判断是否开启自动装配 (判断EnableAutoConfiguration是否开启默认开启true)
@Override
public Class<? extends Group> getImportGroup() {
return AutoConfigurationGroup.class;
}
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
该类是如何自动装配最优设置?
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
getAutoConfigurationEntry() 方法用于获取自动装配实体类
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param autoConfigurationMetadata the auto-configuration metadata
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
在该类中有一步getCandidateConfigurations()方法 用于获取候选配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
首先通过方法
List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());去加载自动装配的配置文件 也就是 spring.factories
以下是加载过程
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
classLoader.getResources(“META-INF/spring.factories”) : 获取项目资源
ClassLoader.getSystemResources(“META-INF/spring.factories”); 获取系统资源
从文件META-INF/spring.factories中获取
spring.factories自动装配文件位置
这些将要被装入IOC的Bean命名有一定的规律,每一个×××AutoConfiguration 都作为容器中的一个组件,以下就是web的组件(部分)
最后判断自动配置的信息是否为空,为空抛出异常。至此@Import(AutoConfigurationImportSelector.class)装配结束
但是我们明明将 spring.factories 中的所有组件都加入了Spring容器中为什么该组件还是报红?
注解:
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
只有满足{ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class }中所有的条件时该组件才会被加载到容器中。
为什么我们WEB的组件可以被加载到容器中,因为我们在pom中加入了,web启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
注解 @ConditionalOnClass 之后再补上
springBoot的自动装配 待续。。。。。。。。。。