草庐IT

springboot启动类

jy0912 2023-09-15 原文

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

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

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 {
   
}

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

从目前来看这样操作是没有问题。那么我们再来试试demo2的方式修改,先新建两个类具体位置如图


从图片中可以看出,main所在的类在app包下,配置类在最外层,这时我用TestApplication启动,服务也是正常运行,测试接口也是正常调用成功

3、我们再修改下代码,demo3:配置类也改一下

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的实现中处理配置类带来的该处理的对象。具体的操作可以看看Configuration注解解析,而springboot的启动类中的run方法入参是什么呢?其实也是一个配置类,那么springboot是怎么用这个配置类的呢?

首先是将这个配置类放在SpringApplication的成员变量里,然后在run方法中的上下文应用准备的时候对配置类进行了处理。

// 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不知道我们会写些什么包路径,所以放最外层从最外层往下扫描,将对象是否注入容器交给开发者(需要注入就加注解)。以上就是我的一点个人理解,欢迎大家斧正。大家一起加油!!!

有关springboot启动类的更多相关文章

  1. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  2. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  3. ruby - 使用 Capistrano 启动 sidekiq - 2

    我想用Capistrano启动sidekiq。下面是代码namespace:sidekiqdotask:startdorun"cd#{current_path}&&bundleexecsidekiq-c10-eproduction-Llog/sidekiq.log&"pcapture("psaux|grepsidekiq|awk'{print$2}'|sed-n1p").strip!endend它执行成功但sidekiq仍然没有在服务器上启动。输出:$capsidekiq:starttriggeringloadcallbacks*2014-06-0315:03:01executing`

  4. ruby-on-rails - fastercsv 的 Rails 3 服务器启动问题 - 2

    我有一个正在升级到Rails3的Rails2.3.5应用程序。我做了所有我需要做的升级以及当我使用启动Rails服务器时要做的事情railsserver它给了我这个PleaseswitchtoRuby1.9'sstandardCSVlibrary.It'sFasterCSVplussupportforRuby1.9'sm17nencodingengine.我正在使用ruby-1.9.2-p0并安装了fastercsv(1.5.3)gem。在puts语句的帮助下,我能够追踪到错误发生的位置。我发现执行在这一行停止了Bundler.require(:default,Rails.env)if

  5. 电脑启动后显示器黑屏怎么办?排查下面4个问题,快速解决 - 2

    电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑

  6. 如何判断oracle是否启动及启动oracle数据库 - 2

    plsql连接Oracle超时,完犊子了肯定是服务器断电了。得马上检查Oracle服务器状态1、检查数据库是否启动su-oracle切换到Oracle用户,输入sqlplus/assysdba显示连接状态。如果末尾显示的状态是Connectedtoanidleinstance.证明未启动2、启动数据库startup启动数据库,末尾出现Databaseopened说明数据库启动成功3、查看数据库监听是否正常先quit;断开Oracle连接,使用lsnrctlstatus查看监听状态,如果出现TNS-开头的Nolistener、Connectionrefused等错误,说明监听未启动4、启动数据库

  7. ruby-on-rails - 为什么 Rails 在启动时预加载它的所有依赖项(gems)? - 2

    当Rails启动时,它会预加载所有依赖项(gems),这会导致启动时间非常缓慢。在我正在处理的一个中型项目中,Rails的启动时间为10-15秒,具体取决于机器。虽然这在生产中不是问题,但在开发中却是一个巨大的痛苦。特别是在工作TDD/BDD时。有加速测试的解决方案(如spork),但它们会引入自己的问题。我的问题是:为什么不在每个代码文件中要求所需的依赖项,而不是在启动时预加载所有内容?手动要求的缺点是什么?额外的代码行? 最佳答案 Rails不是PHP。一些资源是自动加载的,但是您可能需要的所有资源都在启动/初始化时加载,因为最

  8. ruby - 无法启动 sinatra 进程 - eventmachine "no acceptor" - 2

    我有一个作为守护程序运行的Sinatra应用程序,使用Apache端口转发在端口80和端口7655之间进行调解。这在过去一直运行良好。今天,不太好。我不明白为什么。问题:sudoruby​​my_process.rb返回:/var/lib/gems/1.9.1/gems/eventmachine-1.0.0/lib/eventmachine.rb:526:in`start_tcp_server':noacceptor(portisinuseorrequiresrootprivileges)(RuntimeError)尝试过:更新所有系统包,更新所有gem。没有帮助(除了来自eventm

  9. ruby - 无法让测试单元启动在 ruby​​ 1.9.2 中工作 - 2

    我正在使用Ruby1.9.2(ruby-vyields:ruby1.9.2p290(2011-07-09revision32553)[x86_64-linux]),我正在尝试让它工作:require'test/unit'classTestStartup当我运行它时,我得到了Loadedsuitetest_startupStartedintest1.Finishedin0.000395seconds.1tests,0assertions,0failures,0errors,0skips我很难找到有关此功能的文档,除了SO等上的零散帖子。是的,我想使用这个功能而不是设置。TIA

  10. ruby - 使用 Foreman 启动位于不同目录的 Rack App - 2

    我有一个成功运行多个进程的Procfile设置:#/Procfileredis:bundleexecredis-serversidekiq:bundleexecsidekiq-v-C./config.ymlforward:forward4567mock-api我需要再添加一个进程-一个位于我机器上不同目录中的Sinatra应用程序。如果我cd到该目录,我可以从终端启动它:$rackup-p4567我可以使用终端从不同的目录启动它:$sh-c'cd/Path/to/project/&&execrackup-p4567'但是我应该如何使用工头来做到这一点。我尝试添加以下内容,但它无声地失败

随机推荐