1.【SpringBoot 一】SpringApplication启动类的Args详解
2.头秃了,二十三张图带你从源码了解SpringBoot启动流程!
3.Spring中ApplicationListener和ApplicationContext的使用
4.如何阅读spring源码?
5.Spring源码- 02 Spring IoC容器启动之refresh方法
6.SpringBoot源码学习——SpringBoot自动装配源码解析+Spring如何处理配置类的
【SpringBoot 一】SpringApplication启动类的Args详解
传递参数的一种方式,如在启动时使用java -jar --spring.profiles.active=prod或更改自定义配置信息。使用方式是--key=value,其配置优先于项目内部的php问答系统源码配置。
在大部分使用SpringBoot进行开发的项目中,启动类的格式通常是SpringApplication.run(SpringBootDemoPropertiesApplication.class, args);然而,在日常使用中,我们似乎很少使用args参数。那么,args参数究竟有什么作用呢?让我们通过源码来一探究竟。
启动一个带有web项目的示例,并在application.yml配置文件中定义一个自定义属性developer.name=test。以下是启动类,其中设置了args参数。
1. Args使用场景一:在run方法中,args第一次出现在SpringApplication类中。getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)方法用于实例化SpringApplicationRunListener的实现类(配置在spring.factories中的实现类)。关于spring.factories的用法,可以参考SpringBoot 二spring.factories加载时机分析。此项目中只在spring.factories中找到了一个实现类org.springframework.boot.context.event.EventPublishingRunListener。在实例化的过程中,将两个参数{ SpringApplication和String[] args}传递过去。对应到的构造函数如下,并且在EventPublishingRunListener的方法中都有把Args传递下去。
2. Args使用场景二:上述SpringApplicationRunListeners完成后,接下来就到了SimpleCommandLinePropertySource。主要看上面的new Source(args)方法。SimpleCommandLinePropertySource也是一个数据源PropertySource,但它主要是存放命令行属性,例如启动参数Args中的属性就会保存在这个对象中。并且SimpleCommandLinePropertySource会被放入到Environment中,所以也可以通过@link Environment.getProperty(String)来获取命令行的值。看构造函数,可以知道实例化之后的SimpleCommandLinePropertySource是name为commandLineArgs的数据源。属性值的解析规则如下。往下走到了,这个方法的作用就是把我们的Args放到到Spring的environment中;sources.addFirst(new SimpleCommandLinePropertySource(args))。看到方法是等值线源码addFirst(),这说明什么?说明命令行的数据源被放到了最前面;那么命令行数据源的属性就会被最优先采用。那么我们就可以通过Environment.getProperty(String)获取args中的值了。那么我们可以利用这个args做什么用呢?可以用它来写入配置,并且是覆盖项目中的配置(因为它的优先级更高);例如java -jar --spring.profiles.active=dev。这里就算yml配置的是prod,最终使用的是dev。
头秃了,二十三张图带你从源码了解SpringBoot启动流程!
源码版本
作者使用的是Spring Boot的2.4.0版本。不同版本的Spring Boot可能存在差异,建议读者与作者保持一致,以确保源码的一致性。
从哪入手
Spring Boot源码的研究起点是主启动类,即标注着`@SpringBootApplication`注解并且包含`main()`方法的类。这是Spring Boot启动的核心。
源码如何切分
SpringApplication中的静态`run()`方法是一个复杂的流程,它分为两步:创建`SpringApplication`对象和执行`run()`方法。接下来将分别介绍这两部分。
如何创建`SpringApplication`
创建`SpringApplication`的过程本质上是一个对象的生成,通过调试追踪,最终调用的构造方法如图所示。创建过程主要涉及三个阶段,我们将逐一进行深入。
设置应用类型
创建过程中的重要步骤是确定应用类型,这将直接影响项目的性质,如Web应用或非Web应用。应用类型由WebApplicationType枚举类决定,加载特定类(如DispatcherServlet)来判断。
设置初始化器
初始化器(ApplicationContextInitializer)用于在IOC容器刷新之前进行初始化操作,例如ServletContextApplicationContextInitializer。获取初始化器的方式是从SpringApplication中的方法调用开始的,最终通过`#SpringFactoriesLoader.loadSpringFactories()`方法从类路径加载。
设置监听器
监听器(ApplicationListener)负责监听特定的事件(如IOC容器刷新或关闭)。在Spring Boot中,使用SpringApplicationEvent事件来扩展监听器概念,主要在启动过程中触发。获取监听器的方式与初始化器相同,从spring.factories文件中加载。
总结
SpringApplication的美菜商城源码构建为`run()`方法的执行铺平了道路,关键步骤包括设置应用类型、初始化器和监听器。注意,初始化器和监听器需要在spring.factories文件中声明,才能在构建过程中加载,此时IOC容器尚未创建,即使注入到容器中也不会生效。
执行`run()`方法
在构建结束后,到了启动的阶段,`run()`方法将执行一系列操作,分为八个步骤进行详细解析。
步骤1:获取并启动运行过程监听器
SpringApplicationRunListener监听器用于监听应用程序的启动过程,通过调用方法从spring.factories文件中获取运行监听器实例,并执行特定事件的广播。
步骤2:环境构建
构建过程包括加载系统和自定义配置(如application.properties),并广播事件通知监听器。
步骤3:创建IOC容器
执行容器创建过程,根据应用类型选择容器类型,此步骤仅创建容器,未进行其他操作。
步骤4:IOC容器的前置处理
这一步是容器刷新前的准备工作,关键操作是将主启动类注入容器,为后续自动化配置奠定基础。
步骤5:调用初始化器
执行构建过程中设置的初始化器,加载自定义的初始化器实现。
步骤6:加载启动类,注入容器
将主启动类加载到IOC容器中,作为自动配置的入口。
步骤7:两次事件广播
这一步涉及两次事件广播,包括ApplicationContextInitializedEvent和ApplicationPreparedEvent。
步骤8:刷新容器
容器刷新由Spring框架完成,包括资源初始化、上下文广播器等。
步骤9:IOC容器的后置处理
这一步是容器刷新后的扩展操作,通常用于打印结束日志等。
步骤:发出结束执行的事件
使用EventPublishingRunListener广播ApplicationStartedEvent事件,允许在IOC容器中注入的监听器响应。
步骤:执行Runners
Spring Boot提供了两种Runner,即CommandLineRunner和ApplicationRunner,图文直播间源码用于定制额外操作。
总结
Spring Boot启动流程相对简洁,通过八个步骤详细描述了从创建到执行的整个过程。理解run()方法的执行流程、事件、初始化器和监听器的执行时间点是关键。
Spring中ApplicationListener和ApplicationContext的使用
关于Spring的源码相关功能1引入ApplicationContextApplicationContext是Spring的一个核心接口,允许容器通过应用程序上下文环境创建,获取,管理bean.
publicinterfaceApplicationContextextendsEnvironmentCapable,ListableBeanFactory,HierarchicalBeanFactory,MessageSource,ApplicationEventPublisher,ResourcePatternResolver{ /***Returntheuniqueidofthisapplicationcontext.*@returntheuniqueidofthecontext,or{ @codenull}ifnone*/@NullableStringgetId();/***Returnanameforthedeployedapplicationthatthiscontextbelongsto.*@returnanameforthedeployedapplication,ortheemptyStringbydefault*/StringgetApplicationName();/***Returnafriendlynameforthiscontext.*@returnadisplaynameforthiscontext(never{ @codenull})*/StringgetDisplayName();/***Returnthetimestampwhenthiscontextwasfirstloaded.*@returnthetimestamp(ms)whenthiscontextwasfirstloaded*/longgetStartupDate();/***Returntheparentcontext,or{ @codenull}ifthereisnoparent*andthisistherootofthecontexthierarchy.*@returntheparentcontext,or{ @codenull}ifthereisnoparent*/@NullableApplicationContextgetParent();AutowireCapableBeanFactorygetAutowireCapableBeanFactory()throwsIllegalStateException;}ApplicationContext提供的功能:
访问应用程序组件的Bean工厂方法.从org.springframework.beans.factory.ListableBeanFactory继承而来.
publicinterfaceListableBeanFactoryextendsBeanFactory{ ......}通用方式加载文件资源的能力.从org.springframework.core.io.support.ResourcePatternResolver继承而来.
packageorg.springframework.core.io.support;importjava.io.IOException;importorg.springframework.core.io.Resource;importorg.springframework.core.io.ResourceLoader;publicinterfaceResourcePatternResolverextendsResourceLoader{ StringCLASSPATH_ALL_URL_PREFIX="classpath*:";Resource[]getResources(Stringvar1)throwsIOException;}向注册监听器发布事件的能力.从org.springframework.context.ApplicationEventPublisher继承而来.
@FunctionalInterfacepublicinterfaceApplicationEventPublisher{ defaultvoidpublishEvent(ApplicationEventevent){ publishEvent((Object)event);}voidpublishEvent(Objectevent);}解析消息的能力,支持国际化.从org.springframework.context.MessageSource继承而来.
publicinterfaceMessageSource{ @NullableStringgetMessage(Stringcode,@NullableObject[]args,@NullableStringdefaultMessage,Localelocale);StringgetMessage(Stringcode,@NullableObject[]args,Localelocale)throwsNoSuchMessageException;StringgetMessage(MessageSourceResolvableresolvable,Localelocale)throwsNoSuchMessageException;}从父上下文继承,后代上下文中的定义总是优先级.单个父上下文可以被整个web应用程序使用,而每个servlet都有自己独立于任何其他servlet的子上下文.
2关于ApplicationListener的说明2.1ApplicationListener简介ApplicationContext事件机制是属于设计模式中的观察者设计模式,通过ApplicationEvent类和ApplicationListener接口实现事件处理.
当容器中有一个ApplicationListener对象,当ApplicationContext发布ApplicationEvent事件时,ApplicationListener对象会被自动触发,需要由程序来控制.此外Spring中也内置了一下事件.
内置事件说明ContextRefreshedEventApplicationContext被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用refresh()方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有SingletonBean被预实例化,ApplicationContext容器已就绪可用ContextStartedEventConfigurableApplicationContext(ApplicationContext子接口)接口中的start()方法启动ApplicationContext时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序ContextStoppedEventConfigurableApplicationContext接口中的stop()停止ApplicationContext时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作ContextClosedEventConfigurableApplicationContext接口中的close()方法关闭ApplicationContext时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启RequestHandledEvent是web-specific事件,告诉所有beanHTTP请求已经被服务处理。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件2.2ApplicationListener案列1准备一个SpringBoot环境2创建一个自定义的监听器@ComponentpublicclassDemoApplicationListenerimplementsApplicationListener<ContextRefreshedEvent>{ @OverridepublicvoidonApplicationEvent(ContextRefreshedEventevent){ System.out.println(event);System.out.println("TestApplicationListener............................");}}根据上述可知,ContextRefreshedEvent内置事件,是ApplicationContext被初始化或刷新时会发布,即监听器可以收到回调信息.
3启动项目,查看日志3关于ApplicationContext的说明3.1ApplicationContext的简介从上述可知ApplicationContext具有发布事件的能力,是从ApplicationEventPublisher接口继承来的.而Spring中的事件使用,需要继承ApplicationEvent类或ApplicationContextEvent抽象类,抽象类中只有一个构造函数,且带有一个Object类型的参数作为事件源,且该事件源不能为null,因此我们需要在自己的构造函数中执行super(Object)。
publicclassEventObjectimplementsjava.io.Serializable{ privatestaticfinallongserialVersionUID=L;/***TheobjectonwhichtheEventinitiallyoccurred.*/protectedtransientObjectsource;/***ConstructsaprototypicalEvent.**@paramsourceTheobjectonwhichtheEventinitiallyoccurred.*@exceptionIllegalArgumentExceptionifsourceisnull.*/publicEventObject(Objectsource){ if(source==null)thrownewIllegalArgumentException("nullsource");this.source=source;}....}3.2ApplicationContext的案列3.2.1准备一个SpringBoot环境@SpringBootApplicationpublicclassApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(Application.class,args);testEvent();}//@Bean//publicFeignInterceptorfeignInterceptor(){ //returnnewFeignInterceptor();//}//测试事件publicstaticvoidtestEvent(){ ApplicationContextcontext=newAnnotationConfigApplicationContext(EventConfig.class);DemoEventdemoEvent=newDemoEvent(context,"小明",);context.publishEvent(demoEvent);}}3.2.2创建一个自定义的监听器@ComponentpublicclassDemo2ApplicationListenerimplementsApplicationListener<ApplicationEvent>{ @OverridepublicvoidonApplicationEvent(ApplicationEventevent){ //针对自定义事件做处理if(eventinstanceofDemoEvent){ System.out.println(event);DemoEventdemoEvent=(DemoEvent)event;System.out.println("姓名:"+demoEvent.getUsername()+",年龄:"+demoEvent.getAge());System.out.println("自定义DemoEvent事件............................");}}}3.2.3创建一个自定义的事件publicclassDemoEventextendsApplicationEvent{ privateStringusername;privateintage;/***CreateanewApplicationEvent.**@paramsourcetheobjectonwhichtheeventinitiallyoccurred(never{ @codenull})*/publicDemoEvent(Objectsource,Stringusername,intage){ super(source);this.username=username;this.age=age;}publicStringgetUsername(){ returnusername;}publicvoidsetUsername(Stringusername){ this.username=username;}publicintgetAge(){ returnage;}publicvoidsetAge(intage){ this.age=age;}}3.2.4启动项目,查看日志如何阅读spring源码?
如何阅读Spring源码
探究每一个核心的实现细节(UML图、跑单元测试用例、DEBUG,体悟)以上,仅为我自己阅读源码的方式。
此处请大家内心默读三遍。阅读源码的魅力在于:分享一本阿里内部人都在使用的Spring源码手册分享给读者朋友们,学会掌握了本手册内容,距离成为阿里人也是成功的跨了一大步子。
首先,股长主图源码在工程右键,属性中,添加必要的jar包。选中必要的jar包,上面给出的源码jar包中,导入spring0.5中的所有jar包。其中lib内的是spring的jar包,用到哪个导入哪个,不知道的话,全部导入就行了。
准备工作:在官网上下载了Spring源代码之后,导入Eclipse,以方便查询。
Spring提供的@Transactional注解由SpringTransactionAnnotationParser进行解析。SpringTransactionAnnotationParser的源码还是很简单的,它使用AnnotatedElementUtils工具类定义的find语义来获取@Transactional注解信息。
如何将spring开源代码导入idea中进行阅读
1、首先,可以点击上方的Run的选项。然后点击EditConfigurations这个选项。然后看到这里的ServiceApplication这个选项。然后选择到Configuration这个选项。然后经常需要设置的为下面的Parameters的选项。
2、创建一个ntelliJIDEA的新项目的(File|Newproject)。打开newProject窗口。选择Importprojectfromexternalmodel,Next选择导入Eclipse项目,还支持Flash/FlexBuilder和Maven项目。Next选择Eclipse应用所在目录。
3、首先,应该去官网spring.io阅读写spring框架的理念,就好比读一本书,要阅读这本书的纲要,要明白为什么要设计spring架构。
4、你好。根据你的描述:直接把source的zip或者目录往libarary里面加就行了,会自动关联的,仅供参考。
5、SpringSpring是一个开源框架,Spring是于年兴起的一个轻量级的Java开发框架,由RodJohnson在其著作ExpertOne-On-OneJ2EEDevelopmentandDesign中阐述的部分理念和原型衍生而来。
怎么阅读Spring源码探究每一个核心的实现细节(UML图、跑单元测试用例、DEBUG,体悟)以上,仅为我自己阅读源码的方式。
准备工作:在官网上下载了Spring源代码之后,导入Eclipse,以方便查询。
首先,在工程右键,属性中,添加必要的jar包。选中必要的jar包,上面给出的源码jar包中,导入spring0.5中的所有jar包。其中lib内的是spring的jar包,用到哪个导入哪个,不知道的话,全部导入就行了。
更重要的是这些所谓的结论大多是抄来抄去,基本源自一家,真实性也有待考证。那作为程序员怎么能知其所以然呢?此处请大家内心默读三遍。
SpringSecurity源码整体解析遍历securityFilterChainBuilders(其实就是HttpSecurity)列表调用其build方法,生成SecurityFilterChain实例,最后利用多个SecurityFilterChain实例组成List,再封装到FilterChainProxy。
本文适合:对SpringSecurity有一点了解或者跑过简单demo但是对整体运行流程不明白的同学,对SpringSecurity有兴趣的也可以当作你们的入门教程,示例代码中也有很多注释。
Session本身是由Servlet容器进行管理,在内部可以完成Session的创建、销毁等,当达到了会话的最大非活动间隔时长,那么会话会在服务器端会被失效。
SpringSecurityOauth2Token提取流程源码分析spring-security-Oauth2版本:RELEASE整个流程下来,是通过OAuth2AuthenticationProcessingFilter提取请求头参数,获取不到再去获取请求参数。
从SpringSecurity解析一:安全配置过程概览章节我们知道了springSecurityFilterChain的大致构建过程,这里进步探讨其创建的细节。
如何高效阅读源代码?1、首先要理清楚代码结构和业务结构(应该有些文档或者大的流程图),这是阅读具体代码的前提。阅读Javaweb项目的代码:你需要找到View层的代码:前端页面、、资源文件都在其中。
2、当然有。终于到重点了,隆重推出由官方支持的方式:只需要在代码仓库页面按一下.就可以直接使用VSCode打开,而且支持编辑。也可以通过地址访问,把.com改成.dev,比如:太方便了,太优雅了。
3、查看拦截器,监听器代码,知道拦截了什么请求,这个类完成了怎样的工作。
4、用命令(apktooldxxx.apkxxx_xml)反编译xxx.apk包从xxx_xml文件夹得到xml文件第二步得到的程序源代码和第三步得到的xml文件组合下,即可得到完整的apk源码。
5、先找出功能体系,再分离出功能模块。知道能干什么,再知道怎么干。
Spring源码- Spring IoC容器启动之refresh方法
在注册阶段,AnnotationConfigApplicationContext构造方法中的第一个方法被分析过。接下来,我们关注第二个方法:register(componentClasses)。在使用XML配置方式时,通过new ClassPathXmlApplicationContext("classpath:spring.xml")来创建实例,其中需要指定xml配置文件路径。使用注解方式时,也需要为ApplicationContext提供起始配置源头,这里使用配置类代替xml配置文件,按照配置类中的注解(如@ComponentScan、@Import、@Bean)解析并注入Bean到IoC容器。
通过配置类,Spring解析注解实现Bean的注入。使用@Configuration注解定义的配置类相当于xml配置文件,但目前Spring推荐使用注解方式,xml配置的使用概率正在降低。
register(componentClasses)方法的核心逻辑在AnnotatedBeanDefinitionReader#doRegisterBean中,将传入的配置类解析为BeanDefinition并注册到IoC容器。ConfigurationClassPostProcessor这个BeanFactory后置处理器在IoC初始化时,获取配置类的BeanDefinition集合,开始解析。
真正启动IoC容器的流程在refresh()方法中,这是了解IoC容器启动流程的关键步骤。refresh方法在AbstractApplicationContext中定义,采用模板模式,提供IoC初始化流程的基本实现,子类可以扩展。
下面分析refresh()方法的每个步骤,以了解IoC容器的启动流程。
prepareRefresh方法主要在refresh执行前进行准备工作,如设置Context的启动时间、状态,以及扩展系统属性相关。
initPropertySources()方法主要用于扩展配置来源,如网络、物理文件、数据库等加载配置信息。StandardEnvironment默认只提供加载系统变量和应用变量的功能,用于子类扩展。
❝initPropertySources方法常见扩展场景包括:❞
getEnvironment().validateRequiredProperties()确保设置的必要属性在环境中存在,否则抛出异常终止应用。
BeanFactory是Spring的基本IoC容器,ApplicationContext包装了BeanFactory,提供更智能、更便捷的功能。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();获取的BeanFactory是IoC容器初始化工作的基础。
上面获取的BeanFactory还不能直接使用,需要填充必要的配置信息。至此,IoC容器的启动流程基本完成。
这里对IoC启动流程有个大致、直观的印象。主要步骤包括:准备阶段、配置来源扩展、初始化BeanFactory、填充配置、解析配置类、注册Bean、实例化BeanPostProcessor、初始化国际化和事件机制、以及创建内嵌Servlet容器(在SpringBoot中实现)。这些步骤确保了IoC容器顺利启动并管理Bean。
SpringBoot源码学习——SpringBoot自动装配源码解析+Spring如何处理配置类的
SpringBoot通过SPI机制,借助外部引用jar包中的META-INF/spring.factories文件,实现引入starter即可激活功能,简化手动配置bean,实现即开即用。
启动SpringBoot服务,通常使用Main方法启动,其中@SpringBootApplication注解包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan,自动装配的核心。
深入分析@SpringBootApplication,其实质是执行了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解的功能,简化了配置过程,强调了约定大于配置的思想。
SpringBoot的自动装配原理着重于研究如何初始化ApplicationContext,Spring依赖于ApplicationContext实现其功能,SpringApplication#run方法为初始化ApplicationContext的入口。
分析SpringApplication构造方法,SpringApplication.run(启动类.class, args) 实际调用的是该方法,其关键在于根据项目类型反射生成合适的ApplicationContext。
选择AnnotationConfigServletWebServerApplicationContext,此上下文具备启动Servlet服务器和注册Servlet或过滤器类型bean的能力。
准备刷新ApplicationContext,SpringBoot将主类注册到Spring容器中,以便@ConfigurationClassPostProcessor解析主类注解,发挥@Import、@ComponentScan的作用。
刷新ApplicationContext过程包括一系列前置准备,如将主类信息封装成AnnotatedGenericBeanDefinition,解析注解并调用BeanDefinitionCustomizer自定义处理。
解析配置类中的注解,通过BeanDefinitionRegistryPostProcessor和ConfigurationClassParser实现,筛选、排序候选者,并解析@Import注解实现自动装配。
增强配置类,ConfigurationClassPostProcessor对full模式的配置进行增强,确保@Import正确处理,CGLIB用于增强原配置类,确保生命周期完整,避免真正执行@Bean方法逻辑。
深入解析AutoConfigurationImportSelector实现自动装配,通过spring.boot.enableautoconfiguration设置开启状态,读取spring-autoconfigure-metadata.properties和META-INF/spring.factories文件,筛选并加载自动配置类。