您的当前位置:首页正文

springboot启动类

来源:汇意旅游网


前言

提示:这里可以添加本文要记录的大概内容:

springboot启动流程有很多文章都介绍得很详细了,今天我们换种方式来讨论下启动类。


提示:以下是本篇文章正文内容,下面案例可供参考

一、简单回顾

1、首先快速创建一个springboot项目,编写一个测试接口。

@RestController
public class UserController {
    @RequestMapping("/test")
    public String getNameById(String id){
        System.out.println("测试接口入参,id="+id);
        return "lili";
    }
}

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2、下面我们来改造下启动类,demo1:将启动类的注解去掉,run方法入参换一个配置类

import com.jy.demo.config.AopConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(AopConfig.class, args);
    }
}

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.*;

/**
 * @Author jy
 * @Date 2022/4/2 15:38
 * @Version 1.0
 */
@Configuration
@ComponentScan(basePackages = "com.jy.demo.controller")
//@EnableAspectJAutoProxy
@EnableAutoConfiguration
//@Import(JyAfterFilter.class)
public class AopConfig {
   
}

启动服务测试接口,发现服务正常启动,接口调用也是正常

import com.jy.demo.config.AopConfig;
import org.springframework.boot.SpringApplication;

/**
 * @Author jy
 * @Date 2022/7/20 15:43
 * @Version 1.0
 */
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopConfig.class, args);
    }
}

服务启动依然正常,接口测试也正常

二、run方法的入参

1、首先我们还是回顾下spring的注解模式

public class Demo9 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
        applicationContext.publishEvent(new ApplicationEvent("监听事件推送") {
        });
        Apple bean = applicationContext.getBean(Apple.class);
        bean.setId(1);
        System.out.println(bean);
    }
}
public void register(Class<?>... componentClasses) {
		Assert.notEmpty(componentClasses, "At least one component class must be specified");
		StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
				.tag("classes", () -> Arrays.toString(componentClasses));
		this.reader.register(componentClasses);//注意这行代码!!!!
		registerComponentClass.end();
	}

传入的参数就是一个配置类,spring先将这个配置类注入容器,然后在BeanFactoryPostProccsor的实现中处理配置类带来的该处理的对象。具体的操作可以看看,而springboot的启动类中的run方法入参是什么呢?其实也是一个配置类,那么springboot是怎么用这个配置类的呢?

// 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);
public Set<Object> getAllSources() {
		Set<Object> allSources = new LinkedHashSet<>();
		if (!CollectionUtils.isEmpty(this.primarySources)) {
			allSources.addAll(this.primarySources);
		}
		if (!CollectionUtils.isEmpty(this.sources)) {
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}

往下一步就是在load()方法中加载


这里因为我们看的配置类,所以进入第一个if中,再往里走就到了我们前面spring处理时的类似代码了

圈上的这行代码和前面提示注意的那行代码就是一个意思了,到目前为止说清楚了,这个配置类被注册到容器的过程,那么和我们启动类的位置有什么关系呢?

三、ComponentScan的扫描范围

细心的朋友可能已经发现,我们几次修改的时候配置类的ComponentScan的value值是有所不同的,@SpringBootApplication的value值是默认空,而自己写的配置类上的ComponentScan注解是加了路径值的。两者的区别在于,默认空的话,扫描路径是按配置类所在的位置扫描同级及下级;有值的话就按填写的值进行扫描同级及下级。这个操作在ConfigurationClassPostProcessor类处理配置类信息时处理的。而配置类的信息在前面已经说了是怎么注册到容器中的,所以spring能处理到我们的启动配置类,也顺其自然的能处理到配置类上的扫描范围。所以虽然我们修改了main方法文件所在的位置,修改了配置类的位置服务依然能正常启用,接口也正常调用。

总结

唉,前面屁话了一堆,第三点就这么点东西说明了原因。最后再多一嘴,
既然启动类的位置可以不在最外层,那springboot为什么要放在最外层呢?因为springboot不知道我们会写些什么包路径,所以放最外层从最外层往下扫描,将对象是否注入容器交给开发者(需要注入就加注解)。以上就是我的一点个人理解,欢迎大家斧正。大家一起加油!!!

因篇幅问题不能全部显示,请点此查看更多更全内容