SpringBoot源码阅读--自定义Starter

SpringBoot源码阅读--自定义Starter_第1张图片

新建一个maven项目,引入相关依赖。然后在META-INF文件夹下新建文件 spring.factories。配置我们的自动配置类



	
		org.springframework.boot
		spring-boot-starter-parent
		2.1.5.RELEASE
	
	4.0.0
	com.itw.boot
	my-boot-study-starter
	
		
			 org.springframework.boot 
			 spring-boot-starter-web 
		
		
			 org.springframework.boot 
			 spring-boot-starter-test 
		
		
			org.projectlombok
			lombok
		

		
			com.alibaba
			fastjson
			1.2.45
		

	
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itw.autoConfig.AutoConfigWeatherProperties
package com.itw.autoConfig;

import com.itw.configProperties.WeatherProperties;
import com.itw.service.WeatherService;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

//我们的注解@Configuration,表明这是个配置类
//EnableConfigurationProperties注解配合注解@ConfigurationProperties使用,自动注入
@Configuration
@EnableConfigurationProperties(WeatherProperties.class)
public class AutoConfigWeatherProperties {

	@Bean
	public RestTemplate getRestTemplate (){
		return new RestTemplate();
	}

	@Bean
	public WeatherService getWeatherService(WeatherProperties weatherProperties){
		return new WeatherService(weatherProperties);
	}

}
package com.itw.configProperties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotNull;

@Data
@ConfigurationProperties(prefix = "myapp.weather")
@Validated
public class WeatherProperties {
	@NotNull
	String urlStr;
	@NotNull
    String appKey;
}
package com.itw.service;

import com.itw.configProperties.WeatherProperties;
import net.minidev.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

public class WeatherService {
	@Autowired
	private RestTemplate restTemplate;

	public WeatherService(WeatherProperties weatherProperties) {
		this.appKey = weatherProperties.getAppKey();
		this.urlStr = weatherProperties.getUrlStr();
	}

	private String urlStr;

	private String appKey;
	
	public String getWeatherInfo(String  city){
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("appkey", appKey);
		jsonObject.put("city", city);
		String json = JSONObject.toJSONString(jsonObject);
		//使用restTemplate进行访问远程Http服务
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
		HttpEntity httpEntity = new HttpEntity(json, headers);
		//这个接口的appkey不能放到请求体中,所以需要修改逻辑
		String result = restTemplate.postForObject(urlStr, httpEntity, String.class);
		return result;
	}

}

 然后,打包之后就可以,供其他模块或项目引用了。

package com.itwzhangzx.boot.controller;

import com.itw.service.WeatherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;

@RestController
public class WeatherController {
       //别的项目中直接使用我们之前的starter中的对象
	@Autowired
	private WeatherService weatherService;

	@RequestMapping("/getWeatherByCity")
	public  String getWeatherByCity(HttpServletRequest request){
		return weatherService.getWeatherInfo(request.getParameter("city"));
	}


}

为啥我们的项目中能直接用jar包中的对象,关键就在于注解:

@EnableAutoConfiguration
package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

//省略。。。
}

我们先看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服务 	SERVLET
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
//加载ApplicationContextInitializer 容器初始化器()
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//就是找到我们的启动类,比我 MyAppDemo
		this.mainApplicationClass = deduceMainApplicationClass();
	}

然后看我们的run方法:

public ConfigurableApplicationContext run(String... args) {
    //一个计时器。用于统计初始化容器时间
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection exceptionReporters = new ArrayList<>();
//配置模式 java.awt.headless 系统配置,自行百度
		configureHeadlessProperty();
//配置我们的监听器 SpringApplicationRunListener
//从类路径下找到META-INF/spring.factories配置的所有SpringApplicationRunListener
		SpringApplicationRunListeners listeners = getRunListeners(args);
//回调监听器的starting方法,监听器是排好序的,这儿按序执行starting方法
		listeners.starting();
		try {    //main方法的参数,封装
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
//环境中存储我们的所有的配置信息,比如我们的yml文件中的配置参数
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
//spring.beaninfo.ignore属性的配置
			configureIgnoreBeanInfo(environment);
//打印banner
			Banner printedBanner = printBanner(environment);
//创建IOC容器
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
//容器中放入我们的bean,configuration,组件,bean的装配
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			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;
	}

SpringBoot源码阅读--自定义Starter_第2张图片

我们的配置类,也就是注解@Configuration标识了的类会在刷新容器的时候,初始化,然后放入容器中。

 

你可能感兴趣的:(JAVA)