springboot @ApiModelProperty()注解

springboot @ApiModelProperty()注解,第1张

     @ApiModelProperty()注解用于方法、字段,表示对model属性的说明或者数据 *** 作更改,以下是它的源码:
value:字段说明,

name:重写属性名字,

dataType:重写属性类型,

required:是否必须,默认false,

example:举例,

hidden:隐藏。
@ApiModel(value="user对象",description="用户对象user")publicclassUserimplements Serializable{

    privatestaticfinallongserialVersionUID = 1L;

    @ApiModelProperty(value="用户名",name="username",example="xingguo")

    private String username;

    @ApiModelProperty(value="状态",name="state",required=true)

      private Integer state;

      private String password;

      private String nickName;

      private Integer isDeleted;

      @ApiModelProperty(value="id数组",hidden=true)

      private String[] ids;

      privateList idList;

    //省略get/set}

以上是一个最简单的Springboot程序(203版本)示例,也是我们最通用的写法,但其中其实封装这一系列复杂的功能 *** 作,让我们开始逐步进行分析。

首先这里最重要的必然是注解 @SpringBootApplication

@SpringBootApplication 注解由几个注解复合组成,其中最主要的就是 @SpringBootConfiguration 、 @EnableAutoConfiguration 和 @ComponentScan 这三个。

其中的 @ComponentScan 是spring的原生注解, @SpringBootConfiguration 虽然是springboot中的注解,但其实质就是包装后的 @Configuration ,仍然是spring中的注解,用于代替xml的方式管理配置bean

@EnableAutoConfiguration 的定义如上,这里最重要的注解是 @Import ( @AutoConfigurationPackage 注解的实现也是基于 @Import ),借助 @Import 的帮助,将所有符合自动配置条件的bean定义加载到IoC容器中。关于 @EnableAutoConfiguration 注解后续涉及到时会再详细说明。这里我们先回到启动类的 run 方法从头分析初始化流程。

可以看到'run'方法最终调用的是 new SpringApplication(primarySources)run(args) ,这里首先创建了 SpringApplication 对象,然后调用其 run 方法

这里主要是为 SpringApplication 对象进行初始化,这里要专门提一下的是 webApplicationType 和 getSpringFactoriesInstances 。

它用来标识我们的应用是什么类型的应用,来看一下 deduceWebApplicationType() 方法的实现

其返回值是 WebApplicationType 类型的枚举类,其值有 NONE 、 SERVLET 、 REACTIVE 三种,分别对应非WEB应用,基于servlet的WEB应用和基于reactive的WEB应用。

这里的核心是 SpringFactoriesLoaderloadFactoryNames(type, classLoader) 方法,来看一下

重点关注一下 loadSpringFactories(classLoader) 做了什么

这里的 FACTORIES_RESOURCE_LOCATION 定义为 META-INF/springfactories ,因此该方法会扫描所有包下的该文件,将其解析成map对象并缓存到 cache 中以避免重复加载,springboot包下该文件的部分片段如下

从这里可以看出, setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializerclass)) 和 setListeners((Collection) getSpringFactoriesInstances(ApplicationListenerclass)); 分别对应设置的是上述这些类。

解析完成后调用 createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names) 处理解析结果,生成对应的实例,源码如下

这里的核心是通过 ClassUtilsforName(name, classLoader) 方法,以反射的方式生成类实例 instanceClass 。由此可以看出 SpringFactoriesLoaderloadFactoryNames(type, classLoader) 的作用就是将 META-INF/springfactories 中配置的内容进行实例化的工厂方法类,具备很强的扩展性,与SPI机制有异曲同工
的效果。

看完 SpringApplication 的初始化,接着跳回 run 方法继续分析

这里挑其中比较重要的几个方法进行分析

通过 getOrCreateEnvironment() 方法创建容器环境

可以看到 environment 存在则不会重复创建,当应用类型为servlet时创建的是 StandardServletEnvironment 对象,否则创建 StandardEnvironment 对象。

接着来看 configureEnvironment(environment, applicationArgumentsgetSourceArgs())

configurePropertySources(environment, args) 加载启动命令行的配置属性,来看一下实现

这里的 MutablePropertySources 对象用于存储配置集合,其内部维护了一个 CopyOnWriteArrayList 类型的list对象,当默认配置存在时,会向该list的尾部插入一个 new MapPropertySource("defaultProperties", thisdefaultProperties) 对象。

接着来看 configureProfiles(environment, args)

这里主要做的事情就是获取 environmentgetActiveProfiles() 的参数设置到 environment 中,即 springprofilesactive 对应的环境变量。

最后来看一下 listenersenvironmentPrepared(environment)

这里的 listeners 就是之前通过 META-INF/springfactories 注册的所有listeners,后面我们先以其中最重要的 ConfigFileApplicationListener 做为例子进行分析,接着来看 listenerenvironmentPrepared(environment)

可以看到这里创建了一个 ApplicationEnvironmentPreparedEvent 类型的事件,并且调用了 multicastEvent 方法,通过该方法最终会调用到listener的 onApplicationEvent 方法,触发事件监听器的执行。

接下来具体看一下 ConfigFileApplicationListener 的 onApplicationEvent 方法做了什么

可以看到当监听到 ApplicationEnvironmentPreparedEvent 类型的事件时,调用 onApplicationEnvironmentPreparedEvent( (ApplicationEnvironmentPreparedEvent) event) 方法

可以看到这里通过 loadPostProcessors() 方法加载了 META-INF/springfactories 中的所有 EnvironmentPostProcessor 类到list中,同时把 ConfigFileApplicationListener 自己也添加进去了。接着遍历list中所有对象,并执行 postProcessEnvironment 方法,于是接着来看该方法

这里的核心是 new Loader(environment, resourceLoader)load() ,这里的 Loader 是一个内部类,用于处理配置文件的加载,首先看一下其构造方法

可以看到这里的 resourceLoader 又是通过 SpringFactoriesLoader 进行加载,那么来看看 META-INF/springfactories 中定义了哪些 resourceLoader

从名字就可以看出来, PropertiesPropertySourceLoader 和 YamlPropertySourceLoader 分别用于处理properties和yml类型的配置文件。

接着来看看 load() 方法做了什么

initializeProfiles() 进行了 profiles 的初始化,默认会添加 null 和 default 到 profiles 中, null 对应配置文件applicationproperties和applicationyml, default 对应配置文件application-defaultyml和application-defaultproperties,这里的 null 会被优先处理,由于后处理的会覆盖先处理的,因此其优先级最低。

接着来看 load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false)) 方法

这里重点是通过 getSearchLocations() 获取配置文件的路径,默认会获得4个路径

接着会遍历这些路径,拼接配置文件名称,选择合适的yml或者properties解析器进行解析,最后将结果添加到 environment 的 propertySources 中。

可以看到这里也是根据 webApplicationType 的取值,分别创建不同的返回类型。

这里的 sources 装的就是我们的启动类,然后通过 load(context, sourcestoArray(new Object[0])) 方法进行加载

来看一下 loader 是如何被加载的

经过一系列调用之后最终由 load(Class<> source) 方法执行,这里比较有趣的是当Groovy存在时居然是优先调用Groovy的方式进行加载,否则才走 thisannotatedReaderregister(source) 方法将启动类注册到 beanDefinitionMap 中。

这个 refresh() 方法相当重要,尤其是 invokeBeanFactoryPostProcessors(beanFactory) ,这是实现spring-boot-starter-(mybatis、redis等)自动化配置的关键部分,后续再详细讲解。

至此Springboot的启动流程已经大体分析完了,也了解了配置文件和启动类分别是是如何被加载的,但仍有两个问题待解,一是Springboot的核心思想约定大于配置是如何做到的,二是Springboot的各种spring-boot-starter-是如何发挥作用的,这两个问题留待后续文章继续分析。

基于(springboot+vue+mqtt协议)的智能家居系统,可以用于二次开发。

二、实现功能


三、技术选型

后端(springboot、mybatis、mysql 、redis、mqtt)

前端(vue、elementUI)

安装使用docker

四、界面展示


五、源码地址

私信回复:智能家居


大家好,一直以来我都本着 用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 「基础知识」 的铺垫

「大佬可以绕过 ~」

本节给大家讲讲 「Java的SpringBoot框架」 , 之前我们学习的都是java的基础知识和底层提供的一些能力,我们日常工作都是在写接口。在我们在产品开发中,一般我们都会选择比较稳定的框架来帮我们加速开发,不会自己去造轮子,而在java众多框架中,spring框架表现的非常好,大部分公司都会首选它作为开发框架,而至今,大部分企业都是以 springboot 来构建项目了~

上期我们讲解了springboot中的 >了解springboot aop的动态代理方式有哪些种类?

有3种,前提均开启springaopauto=true: 
1 jdk动态代理:当springaopproxy-target-class=false, 引入了aspectjweaver依赖时生效
2 cglib代理:当springaopproxy-target-class=true, 引入了aspectjweaver依赖时生效
3 基础代理:当springaopproxy-target-class=true, 若没有aspectjweaver依赖时生效,只作用于框架内部的advisors,
我们既然用springboot那么就采用springboot的AopAutoConfiguration自动配置类来加载aop机制的,内部对@EnableAspectJAutoProxy进行了封装,扩展了一些配置项,同时还提供了ClassProxyingConfiguration配置(下面会讲到)

这个自动装配类会是spring boot框架自动会装配的,所以说默认aop机制是打开的,可以通过配置项:springaopauto=false 手工关闭。

这个配置类会根据springaopproxy-target-class配置项来决定采用jdk动态代理或者cglib动态代理:

注意:AspectJAutoProxyingConfiguration配置类生效前提是@ConditionalOnClass(Adviceclass),说明只有当引入了依赖项才生效:

而这里推荐使用spring-boot-starter-aop来传递依赖:

这里我们已经看到提供了原生spring的两种代理方式,接着看AopAutoConfiguration源码发现还有个ClassProxyingConfiguration配置类,其生效条件之一是@ConditionalOnMissingClass("orgaspectjweaverAdvice"),就是当项目里没有aspectjweaver的依赖的时候生效。

我们进入AopConfigUtilsregisterAutoProxyCreatorIfNecessary(registry)方法,通过几步调用跳转:

发现会去注册InfrastructureAdvisorAutoProxyCreator后置处理器,查看源码注释:

表明了InfrastructureAdvisorAutoProxyCreator只为基础的advisor做动态代理,而忽略应用定义的Advisors,说明项目中我们自定义的切面是不会被AOP代理的。

1、ApplicationContextInitializer,在Spring上下文被刷新之前进行初始化的 *** 作。这个时候已经创建了ApplicationContext ,但是没有refresh(),ApplicationContextInitializer对ApplicationContext进行初始话 *** 作。

2、SpringApplicationRunListener,对ApplicationContext的运行各个时期的事件进行广播,时事件能够被ApplicationListener所监听到。

3、Runner,Spring上下文后置处理 Runners可以是两个接口的实现类: orgspringframeworkbootApplicationRunner orgspringframeworkbootCommandLineRunner 其实没有什么不同之处,除了接口中的run方法接受的参数类型是不一样的以外。一个是封装好的ApplicationArguments类型,另一个是直接的String不定长数组类型。因此根据需要选择相应的接口实现即可。

SpringBoot启动的时候,不论调用什么方法,都会构造一个SpringApplication的实例,然后调用这个实例的run方法,这样就表示启动SpringBoot。

在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:

SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:

在@SpringBootApplication标签中引入了 EnableAutoConfigurationImportSelector ,其中调用了selectImports()方法,方法中调用orgspringframeworkbootautoconfigureEnableAutoConfigurationImportSelector#getCandidateConfigurations方法,使用SpringFactoryLoader把META-INF文件夹中的 springfactories 文件中 EnableAutoConfiguration 为key的文件加载了。 加载的文件全部都是java config配置文件(有默认配置),利用 @Conditional (Class< extends Condition>[]) 标签,对相应的bean进行选择性的加载。

比较基本而且重要的一个类,运行加载了MATE-INF中的springfactories 文件

@Conditional标签是全部Conditional相关标签的根源。 源码中Conditional标签使用的是ConditionEvaluator来解析,如下 orgspringframeworkcontextannotationAnnotatedBeanDefinitionReader#registerBean(javalangClass<>, javalangString, javalangClass< extends javalangannotationAnnotation>) orgspringframeworkcontextannotationConditionEvaluator#shouldSkip(orgspringframeworkcoretypeAnnotatedTypeMetadata, orgspringframeworkcontextannotationConfigurationConditionConfigurationPhase)

在初始化AnnotationConfigApplicationContext的时候,对ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等类进行了注册。如下

ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor,所以会对BeanDefinitionRegistry或者BeanDefinition创建之后进行后置加工(refresh方法中,已经创建了BeanFactory,具体到运行到哪里看源码)。

import解析原理根据的是ConfigurationClassPostProcessor,ConfigurationClassPostProcessor的加载过程参考上面 主要分析为啥@import标签是引入配置的但是却能够调用Selector的方法 orgspringframeworkcontextannotationConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry orgspringframeworkcontextannotationConfigurationClassPostProcessor#processConfigBeanDefinitions orgspringframeworkcontextannotationConfigurationClassParser#parse(javautilSet<orgspringframeworkbeansfactoryconfigBeanDefinitionHolder>) orgspringframeworkcontextannotationConfigurationClassParser#processDeferredImportSelectors 接着如下,调用了selectImports方法


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/dianzi/13094640.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-30
下一篇 2023-05-30

发表评论

登录后才能评论

评论列表(0条)