创建一个SpringApplication实例
public static ConfigurableApplicationContext run(Class>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
SpringApplication构造方法:属性赋值
// 收集所有的容器初始化组件对象:解析 spring.factories 文件获取容器自定义组件 private List总结> initializers; // 收集所有的监听器:扩展方式和上面的初始化组件方式差不多 private List > listeners;
SpringApplication的构建都是为了run()方法启动做铺垫,构造方法中总共就有几行代码,最重要的部分就是设置应用类型、设置初始化器、设置监听器。 spring-boot自定义容器初始化组件 Demo 定义组件
实现ApplicationContextInitializer
public class CustomInitializer implements ApplicationContextInitializer {
private static final Logger logger = LoggerFactory.getLogger(CustomInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
logger.info("====================CustomInitializer start======================");
logger.info("CustomInitializer initialize方法被执行...");
logger.info("ApplicationName: {}", applicationContext.getApplicationName());
logger.info("isActive: {}", applicationContext.isActive());
logger.info("====================CustomInitializer end======================");
}
}
配置容器组件
SpringBoot的SPI扩展 meta-INF下面 spring.factories配置自定义组件的位置
org.springframework.context.ApplicationContextInitializer=com.li.springbootproject.spring.initializer.CustomInitializer
add方式添加
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MySpringBootApplication.class);
application.addInitializers(new MyApplicationContextInitializer());
application.run(args);
}
}
总结
ApplicationContextInitializer 是 Spring 对外提供的扩展点之一,用于在 ApplicationContext 容器加载 Bean 之前对当前的上下文进行配置。重要的还是如何将这一组件和我们的具体业务相结合,实现我们具体的业务,这应该是需要思考的。 调用对象的 Run() Run() 方法流程
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 获取运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动运行监听器
listeners.starting();
try
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 环境构建这一步加载了系统环境配置、用户自定义配置并且广播了ApplicationEnvironmentPreparedEvent事件,触发监听器。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印 Banner
Banner printedBanner = printBanner(environment);
// 依据是否为 web 环境创建 web 容器或者普通的 IOC 容器(只是创建) 见下面截图
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// IOC 容器的前置处理,为刷新容器之前做准备,关键操作(将启动类注入容器)
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新容器,完成组件的扫描,创建,加载等
refreshContext(context);
// IOC容器的后置处理
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;
}
创建 BeanFactory
初始化完成之后就进到了run方法,run方法完成了所有Spring的整个启动过程:准备Environment——发布事件——创建上下文、bean——刷新上下文——结束
对比 ApplicationContext,ConfigurableApplicationContext提供了配置上下文的接口,如设置Environment、监听器、切面类、关闭上下文的钩子等。
容器启动过程中的 refreshContext() 源码refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
// 告诉子类去刷新bean工厂,这步完成后配置文件就解析成一个个bean定义,注册到BeanFactory(但是未被初始化,仅将信息写到了beanDefination的map中)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
// 处理自定义的BeanFactoryPostProcess:允许BeanFactoryPostProcessor在容器实例化任何bean之前读取bean的定义(配置元数据)
postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessor各个实现类的方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类
// 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。
registerBeanPostProcessors(beanFactory);
// 国际化
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
// 实例化所有剩余的非懒加载单例 bean
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}catch(Exception e){
// ...
}
}
}
SpringBoot 容器 启动流程
常用技巧
初始化类的属性
@PostConstruct
初始化类变量
首先这个注解是由Java提供的,它用来修饰一个非静态的void方法。它会在服务器加载Servlet的时候运行,并且只运行一次。
它的作用在于声明一个Bean对象初始化完成后执行的方法。
Bean初始化中的执行顺序:
Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
@Component
public class InitStaticVariableThree {
private static final Logger logger = LoggerFactory.getLogger(InitStaticVariableThree.class);
public static RedissonClient redissonClientOne;
@Autowired
private RedissonClient redissonClient;
@PostConstruct
public void init() {
redissonClientOne = redissonClient;
logger.info(String.valueOf(redissonClient));
logger.info(String.valueOf(redissonClientOne));
}
}
注册 Bean
除了注解、Java配置和XML配置的方式来创建Bean,还有另外一种方式来创建我们的BeanDefinition。通过 BeanDefinitionRegistryPostProcessor可以创建一个特别的后置处理器,来将BeanDefinition添加到BeanDefinitionRegistry中。BeanDefinition 是对 Bean 的定义,其保存了 Bean 的各种信息,如属性、构造方法参数、是否单例、是否延迟加载等。这里的注册 Bean 是指将 Bean 定义成 BeanDefinition,之后放入 容器中 BeanDefinitionRegistryPostProcessor
和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。这就跟类与类实例之间的区别类似。 执行时机
在Bean定义没有被加载,bean实例还没有被初始化时候。 使用
注册PersonBean:MyBeanDefinitionRegistryPostProcessor.java
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
private static final Logger logger = LoggerFactory.getLogger(MyBeanDefinitionRegistryPostProcessor.class);
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
logger.info(LogConst.LOG_SUCCESS_PREFIX + "MyBeanDefinitionRegistryPostProcessor 中的 postProcessBeanDefinitionRegistry 方法");
logger.info(LogConst.LOG_SUCCESS_PREFIX + "bean 定义的数据量:" + registry.getBeanDefinitionCount());
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(PersonBean.class);
registry.registerBeanDefinition("personbean", rootBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
logger.info(LogConst.LOG_SUCCESS_PREFIX + "MyBeanDefinitionRegisterPostProcessor中的postProcessBeanFactory方法");
logger.info(LogConst.LOG_SUCCESS_PREFIX + "bean 定义的数据量:" + beanFactory.getBeanDefinitionCount());
}
}
使用PersonBean:直接注入使用
实现 Bean 的初始化 实现InitializingBean
定义 Bean 实现 InitializingBean
public class InitializingBeanExample implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(InitializingBeanExample.class);
private int id;
private String name;
@Override
public void afterPropertiesSet() {
logger.info(LogConst.LOG_SUCCESS_PREFIX + " 初始化前的值为:{}", this);
logger.info(LogConst.LOG_SUCCESS_PREFIX + " 我要对 PeopleBean 进行初始化!");
this.id = 100;
this.name = "李四";
logger.info(LogConst.LOG_SUCCESS_PREFIX + " 初始化后的值为:{}", this);
}
}
注册 Bean
@Configuration
public class InitializingBeanExampleTest {
private static final Logger logger = LoggerFactory.getLogger(InitializingBeanExampleTest.class);
@Bean
public InitializingBeanExample initializingBeanExample() {
InitializingBeanExample initializingBeanExample = new InitializingBeanExample();
initializingBeanExample.setId(1);
initializingBeanExample.setName("test1");
logger.info(LogConst.LOG_SUCCESS_PREFIX + initializingBeanExample);
return initializingBeanExample;
}
}
使用initMethod方法
定义 Bean
@Bean(initMethod = "initBean")
@Lazy
public InitMethodBean initMethodBean() {
InitMethodBean initMethodBean = new InitMethodBean();
logger.info(LogConst.LOG_SUCCESS_PREFIX + "实例化 InitMethodBean 信息为:" + initMethodBean);
return initMethodBean;
}
定义 Bean的 inti-method 方法
public class InitMethodBean {
private static final Logger logger = LoggerFactory.getLogger(InitMethodBean.class);
private UUID id;
private String name;
private void initBean() {
this.id = UUID.randomUUID();
this.name = "InitMethodBean";
logger.info(LogConst.LOG_SUCCESS_PREFIX + "执行 InitMethodBean 的 initBean():" + this);
}
// ...
}
@PostConstruct
看前面的讲解 总结
初始化 Bean 的顺序
Constructor > @PostConstruct > InitializingBean > init-method
获取 Bean 修改 Bean 信息 实现 BeanPostProcessor 接口
实现BeanPostProcessor 接口,重写postProcessBeforeInitialization()、postProcessAfterInitialization(),在重写的方法中,可以获得Bean的属性,对Bean进行相关的操作。
@Component
public class UserBeanPostProcessor implements BeanPostProcessor {
private static final Logger logger = Logger.getLogger(String.valueOf(UserBeanPostProcessor.class));
// 在这里可以拿到bean的相关信息,进行相关操作
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
final String name = "myUser";
if(name.equals(beanName)){
User user = (User) bean;
user.setName("李四");
user.setDate(new Date());
logger.info("=====> postProcessBeforeInitialization():"+ JSONObject.toJSONString(user));
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
执行时机
postProcessBeforeInitialization() 方法:在 Bean 实例化、属性注入后,初始化前调用。postProcessAfterInitialization() 方法:在 Bean 实例化、属性注入、初始化都完成后调用。
SpringBoot 启动后执行操作
springboot给我们提供了两种方式:ApplicationRunner和CommandLineRunner。
这两种方法提供的目的是为了满足,在项目启动的时候立刻执行某些方法。我们可以通过实现ApplicationRunner和CommandLineRunner,来实现,他们都是在SpringApplication 执行之后开始执行的。
Order 注解使用在Spring容器启动后可以加载一些资源或者做一些业务操作实现 CommandLineRunner
@Component
@Order(1)
public class OrderTestOne implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(OrderTestOne.class);
@Override
public void run(String... args) throws Exception {
logger.info("OrderTestOne...");
}
}
order的值越小,优先级越高order如果不标注数字,默认最低优先级,因为其默认值是int最大值 实现 ApplicationRunner、Ordered 接口
@Component
public class OrderTestTwo implements ApplicationRunner, Ordered {
private static final Logger logger = LoggerFactory.getLogger(OrderTestTwo.class);
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("OrderTestTwo...");
}
@Override
public int getOrder() {
return 2;
}
}
获取 ApplicationContext 容器 直接注入
直接在使用的地方注入使用
@Autowired private ApplicationContext applicationContextBean;实现ApplicationContextAware接口
实例代码SpringContextUtils,定义全局的获取上下文的工具类
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(SpringContextUtils.class);
private static ApplicationContext applicationContext = null;
private SpringContextUtils() {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (Objects.isNull(SpringContextUtils.applicationContext)) {
logger.info(LogConst.LOG_SUCCESS_PREFIX + "ApplicationUtils初始化...");
SpringContextUtils.applicationContext = applicationContext;
}
logger.info(LogConst.LOG_SUCCESS_PREFIX + "ApplicationUtils初始化成功!");
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@SuppressWarnings("all")
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static T getBean(Class tClass) {
return getApplicationContext().getBean(tClass);
}
}
作为参数获取 ApplicationContext Bean
Spring在初始化AutoConfiguration时会自动传入ApplicationContext,这时我们就可以使用下面的方式来获取ApplicationContext:
@Configuration
public class TestConfig {
private static final Logger logger = LoggerFactory.getLogger(TestConfig.class);
public TestConfig(ApplicationContext applicationContext) {
logger.info(String.valueOf(applicationContext));
}
}
通过WebApplicationContextUtils获取
Spring提供了一个工具类用于获取ApplicationContext对象:
@Autowired
private ServletContext servletContext;
@Override
public String testSix() {
WebApplicationContext context1 = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
WebApplicationContext context2 = WebApplicationContextUtils.getWebApplicationContext(servletContext);
return "测试成功!";
}
获取BeanFactory Spring中的Aware
Aware这个类主要是辅助Spring进行访问容器中的数据,在实现这个类重写的方法中,可以拿到相关组件的信息,从而可以进行相应的扩展。
常用的Aware实现类BeanFactoryAware:获取BeanFactory容器BeanNameAware:获取Bean的名称ApplicationContextAware:获取ApplicationContext 得到 BeanFactory
实现BeanFactoryAware,在setXXX()中获得相关的Spring组件。
@Component
public class GetBeanFactory implements BeanFactoryAware {
private static final Logger logger = LoggerFactory.getLogger(GetBeanFactory.class);
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
MyBeans bean = beanFactory.getBean(MyBeans.class);
logger.info("-----> 获得当前的BeanFactory "+ beanFactory);
}
}
FactoryBean、BeanFactoryPostProcessor 扩展
Mybatis 中 Mapper
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHUfeeFt-1647340618646)(images/image-20220313111913059.png)]
BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。
FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
实现汽车装配引擎的过程BeanProduct
@Configuration
public class BeanProduct {
@Bean
public SpecialBeanForEngine specialBeanForEngine() {
return new SpecialBeanForEngine();
}
@Bean(initMethod = "start")
public Car car(CarEngine carEngine) {
Car car = new Car();
car.setEngine(carEngine);
return car;
}
}
注册 EngineFactory 的 BeanDefine
public class SpecialBeanForEngine implements BeanFactoryPostProcessor, BeanNameAware {
public String name;
@Override
public void setBeanName(String name) {
this.name = name;
}
public class SpecialBeanForEngine implements BeanFactoryPostProcessor, BeanNameAware {
public String name;
@Override
public void setBeanName(String name) {
this.name = name;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(EngineFactory.class);
genericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
genericBeanDefinition.setAutowireCandidate(true);
beanDefinitionRegistry.registerBeanDefinition("engine007", genericBeanDefinition);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(EngineFactory.class);
genericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
genericBeanDefinition.setAutowireCandidate(true);
beanDefinitionRegistry.registerBeanDefinition("engine007",genericBeanDefinition);
}
}
汽车 Bean 的配置
public class Car implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(Car.class);
private String code = String.valueOf(UUID.randomUUID());
private CarEngine engine;
public Car() {
logger.info(LogConst.LOG_SUCCESS_PREFIX + "Car Constructor...");
logger.info(LogConst.LOG_SUCCESS_PREFIX + "Car engine not setting");
}
private void start() {
logger.info(LogConst.LOG_SUCCESS_PREFIX + "Car start...");
engine.fire();
}
@Override
public void afterPropertiesSet() throws Exception {
logger.info("Car initializingBean after propertieSet");
if (engine == null) {
logger.info("Car's engine not setting, in initializingBean ");
} else {
logger.info("Car's engine installed, in initializingBean");
// 使用接口方法
engine.fire();
}
}
@PostConstruct
public void postConstruct() {
logger.info("Car postConstruct");
if (engine == null) {
logger.info("Car engine not setting, in postConstruct");
} else {
logger.info("Car engine installed, in postConstruct");
}
}
}
需要代理的接口
public interface CarEngine {
void fire();
void close();
}
工厂Bean EngineFactory
public class EngineFactory implements FactoryBean, BeanNameAware, InvocationHandler { private static final Logger logger = LoggerFactory.getLogger(EngineFactory.class); private String name; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("fire".equalsIgnoreCase(method.getName())) { logger.info(LogConst.LOG_SUCCESS_PREFIX + "here is invoke engine:" + method.getName()); } if ("close".equalsIgnoreCase(method.getName())) { logger.info(LogConst.LOG_SUCCESS_PREFIX + "here is invoke engine:" + method.getName()); } return null; } @Override public void setBeanName(String name) { this.name = name; } @Override public CarEngine getObject() { logger.info(LogConst.LOG_SUCCESS_PREFIX + "EngineFactory to build Engine01 , EngineFactory :" + name); CarEngine carEngine = (CarEngine) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{CarEngine.class}, this); return carEngine; } @Override public Class> getObjectType() { return CarEngine.class; } @Override public boolean isSingleton() { return true; } }
测试代码
@Autowired private CarEngine carEngine; carEngine.fire(); carEngine.close();
执行结果
2022-03-12 20:04:25.508 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car Constructor... 2022-03-12 20:04:25.508 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car engine not setting 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car postConstruct 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car engine installed, in postConstruct 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car initializingBean after propertieSet 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car engine installed, in initializingBean 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.b.EngineFactory : ==========> here is invoke engine:fire 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.beanfactorypostprocessor.Car : ==========> Car start... 2022-03-12 20:04:25.509 INFO 12836 --- [ main] c.l.s.s.b.EngineFactory : ==========> here is invoke engine:fire
SpringBoot Event事件同步、异步处理
场景:按照一定的顺序做一些事情,例如向A表插入数据事物提交之后,向B表中插入历史记录,最后向C表插入。 Spring 事件
在 Spring 中,初始化容器时会调用 org.springframework.context.ConfigurableApplicationContext 接口中的 reFresh() 方法进行 Bean的加载,该方法会进行事件的监听注册。
示例代码定义事件
public class UserEventextends ApplicationEvent { private T data; public UserEvent(T source) { super(source); this.data =source; } public T getData() { return this.data; } public void setData(final T data) { this.data = data; } }
发布事件
@Autowired
private ApplicationEventPublisher publisher;
private void sendInsertUser() {
User user = new User();
user.setId(20210317);
user.setUsername("测试张三");
UserEvent userEvent = new UserEvent<>(user);
// 发布事件
publisher.publishEvent(userEvent);
}
监听用户插入的事件
@Async @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,fallbackExecution = true) public void insertUserLinster(UserEventuserEvent) { User data = userEvent.getData(); String message = String.format("get user message: %s", JSON.toJSONString(data)); log.info(message); // 后续操作;继续处理 }
SpringBoot 关机函数
实现 ExitCodeGenerator 接口,生成自己的退出代码
@Component
public class ExitCodeApplication implements ExitCodeGenerator {
private static final Logger logger = LoggerFactory.getLogger(ExitCodeApplication.class);
@Override
public int getExitCode() {
logger.info(LogConst.LOG_SUCCESS_PREFIX + "容器已经关机...");
return 999;
}
}
调用
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/close")
public void testFive(HttpServletRequest request, HttpServletResponse response) {
SpringApplication.exit(applicationContext);
}
SpringBoot starter机制
SpringBoot 在启动时会去依赖的 starter 包中寻找 /meta-INF/spring.factories 文件,然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包,这类似于 Java 的 SPI 机制。
SpringBoot中的starter是一种非常重要的机制(自动化配置),能够抛弃以前繁杂的配置,将其统一集成进starter
生成配置文件
@Configuration
@ConditionalOnClass(StarterService.class)
@EnableConfigurationProperties(StarterServiceProperties.class)
public class StarterAutoConfigure {
@Autowired
private StarterServiceProperties properties;
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "example.service", value = "enabled", havingValue = "true")
public StarterService starterService() {
return new StarterService(properties.getConfig());
}
}
resources下meta-INF的spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.li.StarterAutoConfigure
引入依赖
com.li springboot-starter-demo 1.0-SNAPSHOT



