分布式微服务架构之SpringBoot定制篇


一,springboot的启动原理

@SpringBootApplication
public class Application {
public static void main(String[] args) {
//从主程序的入口进入
SpringApplication.run(Application.class,args);
}
}

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//这里的流程实际上分为了两步:
//第一步:创建SpringApplication
//第二步:执行run()
return new SpringApplication(primarySources).run(args);
}

1.创建SpringApplication
进入new SpringApplication()

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//保存主配置类
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断当前是否是一个web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从类路径下找到META-INF/spring.factory配置的所有ApplicationContextInitializer,然后保存起来 TODO
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从类路径下找到META-INF/spring.factory配置的所有ApplicationListener,然后保存起来
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类找到main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}

再来看getSpringFactoriesInstances()

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
//SpringFactoriesLoader.loadFactoryNames(type, classLoader)
//往工厂里面加载bean
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

接着看loadFactoryNames()

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
//调用了loadSpringFactories
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}

try {
//从FACTORIES_RESOURCE_LOCATION下加载配置文件
//FACTORIES_RESOURCE_LOCATION代表的哪里?
//public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

再回到SpringApplication()看setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
//实际调用的是getSpringFactoriesInstances
return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
//调用了 loadFactoryNames
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

这里就和上一步其实是一样的,从META-INF/spring.factories加载bean。

2.执行run()

	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

点击进入run()

    public ConfigurableApplicationContext run(String... args) {
//监听springboot应用的创建
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
Banner printedBanner = printBanner(environment);
//创建ApplicationContext;决定创建web的ioc还是普通的ioc 利用反射创建
context = createApplicationContext();
//做异常打印报告的,没啥用
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境;将environment保存到ioc中;而且applyInitializers();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//容器刷新,ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)
refreshContext(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context, applicationArguments);
//停止监听
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//所有的SpringApplicationRunListener回调finished方法
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

prepareContext()

	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//给上下文设置环境
context.setEnvironment(environment);
//执行上下文的后置处理器,给容器中加载一些组件
postProcessApplicationContext(context);
//回调之前保存的所有的ApplicationContextInitializer的initialize方法
applyInitializers(context);
//回调所有的SpringApplicationRunListener的contextPrepared();
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}


refresh()

	public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 清空缓存
prepareRefresh();

// cas的方式初始化bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 创建bean工厂,加载xxxAware 注册单实例bean
prepareBeanFactory(beanFactory);

try {
// 加载bean工厂的后置处理器
postProcessBeanFactory(beanFactory);

// 执行bean工厂的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);

// 将bean的后置处理器注册到容器中
registerBeanPostProcessors(beanFactory);

// 初始化容器信息
initMessageSource();

// 初始化事件派发器
initApplicationEventMulticaster();

// 加载其他的单实例bean,并创建web容器
onRefresh();

// 将监听器注册到容器
registerListeners();

// 完成bean工厂的初始化,看看有没有自定义的类加载器和xxxAware接口,都加载到容器中
finishBeanFactoryInitialization(beanFactory);

//清理缓存,为此上下文初始化生命周期处理器,将容器刷新派发到生命周期处理器,事件派发器发布事件,启动web容器,并发布事件
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}


二,自定义starter
1.原理分析

1、这个场景需要使用到的依赖是什么?

2、如何编写自动配置

@Configuration  //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就加载的自动配置类,配置在META‐INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

3、模式:
启动器只用来做依赖导入;
专门来写一个自动配置模块;
启动器依赖自动配置;别人只需要引入启动器(starter)
mybatis-spring-boot-starter;自定义启动器名-spring-boot-starter

2.代码
1.首先创建两个maven工程

yhd-spring-boot-starter
yhd-spring-boot-starter-autoconfigurer

2.引入依赖

在yhd-spring-boot-starter-autoconfigurer里面引入

    <!--  引入springboot核心启动器  -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
</dependencies>

在yhd-spring-boot-starter里面引入

        <!--  引入自动配置模块  -->
<dependencies>
<dependency>
<groupId>com.yhd</groupId>
<artifactId>yhd-spring-boot-starter-autoconfigurer</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>

3.编写yhd-spring-boot-starter-autoconfigurer
1.创建一个service

/**
* @author yhd
* @createtime 2020/10/6 1:28
*/
public class HelloService {

@Autowired
private HelloServiceProperties helloServiceProperties;

public String sayHello(String name){
return helloServiceProperties.getPrefix()+" "+name+" " +helloServiceProperties.getSuffix();
}
}


2.创建一个HelloServiceProperties

/**
* @author yhd
* @createtime 2020/10/6 1:30
* Not registered via @EnableConfigurationProperties, marked as Spring component, or scanned via @ConfigurationPropertiesScan
*/
@Component
@ConfigurationProperties(prefix = "yhd.hello")
public class HelloServiceProperties {

private String prefix;
private String suffix;

public String getPrefix() {
return prefix;
}

public void setPrefix(String prefix) {
this.prefix = prefix;
}

public String getSuffix() {
return suffix;
}

public void setSuffix(String suffix) {
this.suffix = suffix;
}
}


3.创建一个HelloServiceAutoConfiguration

/**
* @author yhd
* @createtime 2020/10/6 1:35
*/
@SpringBootConfiguration
@ConditionalOnWebApplication
@EnableConfigurationProperties(HelloServiceProperties.class)
public class HelloServiceAutoConfiguration {

@Autowired
private HelloServiceProperties helloServiceProperties;

@Bean
public HelloService helloService(){
return new HelloService();
}
}

4.在resources目录下创建META-INF目录
5.在META-INF下创建spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yhd.config.HelloServiceAutoConfiguration

4.将这两个项目安装到仓库
5.别的项目引入yhd-spring-boot-starter依赖

/**
* @author yhd
* @createtime 2020/10/6 1:45
*/
@RestController
public class HelloController {

@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.sayHello("尹会东");
}
}

配置文件:

yhd.hello.prefix=Hello
yhd.hello.suffix=!

访问localhost:8080,输出:Hello 尹会东 !。
至此,starter创建成功。

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

分布式微服务架构之SpringBoot定制篇

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 分布式微服务架构之SpringBoot定制篇
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏