简介
hello,今天分享鄙人关于springboot的理解,springboot是现在很多企业web开发所使用的一站式框架,整体来说springboot是对spring的整体再封装!
spring官方给出了很多springboot的优点
1.创建独立的spring的应用,很对时候用springboot创建微服务让人感到十分的省心
2.内嵌tomcat,jetty等web容器
3.自动配置spring或者第三方jar包等一系列优点
springboot的自动装配原理
springboot最核心的点就在于它的主启动类上 他一启动就会加载很多spring的配置,而最重要的就是主启动类上的@SpringBootApplication注解。
这是一个组合注解,面试这么多次springboot的自动装配原理势必问的,其实我也观察到很多人再面试的时候一遇到这个问题就会扯上一大堆,其实都很难说到核心上面去。
@SpringBootConfiguration 这个注解的底层其实就是spring里面的@Configuration 作用就是标志一个类作为配置类,自然也没什么好说的,当然了现在spring5以后就引入了 这个 boolean proxyBeanMethods() default true; 它的作用就是 如果设置微true或者默认不设置 当前的配置类就为一个代理对象,其作用是为了解决组件依赖的问题(组件依赖 大家应该都懂)!
至于@ComponentScan这个注解就跟没什么说的了,他无非就是相当于spring配置文件里面的让spring去将类加载到ioc容器中。
真正的核心就是@EnableAutoConfiguration 同样,这个注解也是一个组合注解
(1) @AutoConfigurationPackage:
翻译过来就是自动配置包,它的底层就是一个@Import({Registrar.class})
这里面导入的一个Registrar.class组件
这里就是将注解信息的元数据拿到,这里的元数据信息也其实就是我们的主启动类。也就是说将我们主启动类所在的包以及其子包里面的组件全部扫描到并且加载到ioc容器中去 所以一定要注意写文件的位置,当然了如果没按照规定写的话也可以使用@ComponentScan注解将它扫描进来!
@Import({AutoConfigurationImportSelector.class})
这里是使用import来导入相应的组件,而配置的规则都在AutoConfigurationImportSelector这个类里面
这里就是加载springboot需要加载的组件而具体的方法就是getAutoConfigurationEntry();
先是获取到候选的配置
接着走断点就说明 有164项需要加载到ioc容器中
下面就是是说排除掉一些重复的再排除掉一些其他的 就把需要导入的组件进行封装然后返回
值得一说的就是这个getCandidateConfigurations()方法,那么我们现在就是说springboot从哪里去找到它要加载的哪些类
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
这个方法就是说先采用spring的加载器去找到我们所需要组件的名称
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);
}
}
}
可以看到他是到META-INF/spring.factories里面去找到需要加载的组件名称的,也就是在我们的spring-boot-autoconfigure-2.2.4.RELEASE.jar包里面的META-INF下里面的spring.factories
这里面就包含了我们要加载的组件
自定义starter
要想定义一个starter必须要熟悉springboot的配置原理才能理清其中的逻辑
参照springboot官方
就像这样什么什么starter 只是用来引入我们的自动配置组件
1.首先建立一个空项目
2.紧接着建立一个maven项目
这个就是跟springboot里面的starter一样用来做一个场景导入
3.建立一个springboot的项目,这里使用idea的初始化向导
就这样直接直接创建就行
那么我们再starter里面引入我们的自动配置就行
这里就简单写一个方法作为来进行演示
先建立一个Hello类建立一个普通的方法作为我们需要使用的
public class Hello {
@Autowired
HelloBean helloBean;
public String sayHello(String name){
return helloBean.getPre()+name+helloBean.getSuf();
}
}
接着创建有个bean
@ConfigurationProperties("zengbo.hello")
public class HelloBean {
private String pre;
private String suf;
public String getPre() {
return pre;
}
public void setPre(String pre) {
this.pre = pre;
}
public String getSuf() {
return suf;
}
public void setSuf(String suf) {
this.suf = suf;
}
}
这里使用@ConfigurationProperties(“zengbo.hello”)来与配置文件进行动态绑定以zengbo.hello为前缀进行绑定。
再接下来创建一个配置类
@Configuration
@EnableConfigurationProperties(HelloBean.class)
@ConditionalOnMissingBean(Hello.class)
public class HelloAutoConfigure {
@Bean
public Hello hello(){
return new Hello();
}
}
这里首先使用@Configuration来标注此类是一个配置类,
@EnableConfigurationProperties(HelloBean.class)
这个注解是将开启配置绑定并且默认将HelloBean.class加载到ioc容器中
@ConditionalOnMissingBean(Hello.class)
这个条件注解就是说当我们容器中没有Hello.class组件的时候才将相面的@Bean生效
所以我们才没有将Hello加到容器中
这里需要注意的是在springboot官方就是到自动配置/META-INF/spring.factories里面去找的所以我们也需要创建
在配置里面我们只需要写上需要自动导入的组件即可
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zengbo.auto.HelloAutoConfigure
在完成这一系列工作之后就需要将starter加载到我们的仓库里面去
分别点击clean和install就行 这样就导入到我们的仓库了
接下来测试就行
随便新建一个springboot的项目将我们自定义的starter进行导入
这样就代表导入了
然后注入我们的要测试的组件就行
在去配置文件里面把我们需要动态获取的值写上就行
zengbo.hello.pre="welcome"
zengbo.hello.suf="to home"
至此我们自定的starter就完成了