1.SpringBoot中CommandLineRunner详解(含源码)
2.Spring扩展点探索之BeanFactoryPostProcessor
3.Spring面试中常问的重写重写FactoryBean与其他的Bean不同之处在哪?
4.Spring源码7.如何添加自定义的BeanFactoryPostProcessor
5.使用Gateway作为SpringCloud网关
6.盘点 Spring Boot 解决跨域请求的几种方法
SpringBoot中CommandLineRunner详解(含源码)
Spring Boot的CommandLineRunner接口是一个函数式接口,用于在Spring Boot应用程序启动后执行一些初始化操作。源码
使用CommandLineRunner接口,实现可以在应用程序启动后执行一些必要的重写重写初始化操作,例如加载配置文件、源码初始化数据库连接、实现bgpnet源码创建默认数据等。重写重写可以通过实现CommandLineRunner接口,源码并重写run方法来定义自己的实现初始化逻辑。
在上面的重写重写示例中,我们创建了一个名为MyCommandLineRunner的源码类,并实现了CommandLineRunner接口。实现在run方法中,重写重写我们可以编写需要在应用程序启动后执行的源码初始化逻辑。
需要注意的实现是,实现CommandLineRunner接口的类需要被Spring容器扫描到,可以使用@Component注解或其他方式将其注册为Spring Bean。
可以通过@Order()来设置Runner的先后顺序,在上面例子的基础上增加OrderRunner1OrderRunner2执行结果通常用法加载初始化数据。
可以实现CommandLineRunner接口,在run方法中加载一些初始化数据到数据库等。适合做一些数据预加载工作。
这里创建了一个DataInitializer类,实现CommandLineRunner接口。在run()方法中,我们注入了UserRepository,然后创建了两个用户对象保存到数据库中。这个类会在Spring Boot应用启动完成后执行,从而实现了数据预加载的效果。通过CommandLineRunner,我们可以灵活地在Spring Boot启动时进行一些初始化操作,如预先加载测试数据、插入管理员账户等,很好地增强了应用的功能。
假设我们有一个User模型和用户Repository,需要在Spring Boot启动时预加载几个用户数据,可以这样使用CommandLineRunner:
这里我们实现了CommandLineRunner接口,然后注入UserRepository bean。在run方法中,linux wget 源码下载首先清空所有数据,然后创建两个用户对象并保存,最后打印已保存的用户数。这样在Spring Boot应用启动完成后,就会自动执行run方法,预加载指定的用户数据。
可以打印出一些应用启动信息,如启动端口、运行环境信息等,用于确认应用配置。
可以使用多线程启动一些异步任务,进行后台数据处理等复杂业务逻辑。
可以调用并验证依赖服务的健康状态,如果不正常可以终止Spring Boot启动。
可以在启动时调用外部服务,进行验证、数据同步等操作。
可以对输入的运行参数做校验,如果不满足条件可以终止Spring Boot启动。
可以根据运行参数等条件动态设置Spring Boot的配置,实现不同环境的适配。
可以使应用启动后阻塞住主线程,防止main方法直接退出,从而保持Spring Boot应用运行。
通过CommandLineRunner,我们可以深度控制Spring Boot应用的启动流程,在应用启动阶段增强各种自定义逻辑。是Spring Boot提供的一个很实用的扩展点。
Spring扩展点探索之BeanFactoryPostProcessor
Spring的BeanFactoryPostProcessor是一种强大的工具,它允许在Bean实例化前对Bean的属性进行后置处理。想象一下,如果你的Bean中存在占位符,BeanFactoryPostProcessor就像一个预处理器,负责在配置参数填充这些占位符,确保Bean在初始化时得到正确的值。
这个接口仅需实现一个postProcessBeanFactory()方法,通过它,开发者可以根据需要定制Bean的spring mvc源码分享属性。例如,创建一个User类,配置类将其注册到Spring容器,然后自定义一个MyBeanFactoryPostProcessor,重写postProcessBeanFactory()方法,用于修改User的属性,如将userName从Jack改为Tom。
当你在测试类中获取并打印User对象时,可以看到属性已经被修改为Tom。这显示了BeanFactoryPostProcessor如何在初始化阶段灵活地改变Bean的行为。Spring通过refresh()方法中的invokeBeanFactoryPostProcessors()函数,自动调用每个注册的BeanFactoryPostProcessor,实现了这个过程的自动化。
源码分析揭示,Spring内部通过遍历BeanFactoryPostProcessor列表并调用postProcessBeanFactory(),确保在Bean实例化之前,所有定制的处理逻辑得以执行。因此,BeanFactoryPostProcessor是Spring框架中实现Bean属性动态修改的关键环节。
Spring面试中常问的FactoryBean与其他的Bean不同之处在哪?
在Spring框架中,FactoryBean作为一种特殊的Bean,其存在意义在于能够生成和管理Bean,提供了一种灵活的Bean创建机制。相比于普通的Bean,FactoryBean的独特之处在于它能够提供对象的创建和类型判断的功能。通过实现FactoryBean接口,Spring能够将复杂的Bean创建逻辑封装,从而更方便地进行管理和使用。
FactoryBean接口包含三个核心方法:getObject、getObjectType和isSingleton。getObject方法用于创建和返回实际的Bean对象,getObjectType方法用于返回创建对象的类型,isSingleton则用于指示该对象是否为单例。这三个方法共同协作,使得Spring能够在配置文件中定义复杂的Bean创建逻辑,并且仍然保持了Spring的自动化管理能力。
下面以Spring Boot环境为例,演示如何定义自定义的微擎cms源码FactoryBean。以一个简单的Student类作为例子,通过FactoryBean来创建和管理Student对象。此外,为方便验证,重写toString方法,用于输出对象信息。
首先定义Student类,包含两个属性,并重写toString方法以输出对象信息。接下来,实现FactoryBean接口,仅在getObject方法内部new一个Student对象并返回。同时,通过重写toString方法,便于测试与验证。
通过测试方法验证FactoryBean的使用,会发现通过"myFactoryBean"获取到的是Student对象,而通过"&myFactoryBean"获取到的是FactoryBean对象本身。这种现象直观展示了FactoryBean的神奇之处——它不仅能够生产Bean,还能够返回自身。
FactoryBean的作用在于允许开发者自定义复杂Bean的创建逻辑,特别是那些需要初始化多个变量或执行复杂操作的Bean。使用Spring的自动装配功能往往难以满足这些需求,因此,FactoryBean为开发者提供了一种解决方案,将这些工作交由Spring进行管理。
例如,在MyBatis与Spring集成时,会遇到一个名为SqlSessionFactoryBean的FactoryBean,它的目标是返回一个由Spring管理的SqlSessionFactory。在MyBatis中创建SqlSessionFactory需要配置多个属性,因此SqlSessionFactoryBean应运而生,它封装了创建过程,使得集成更加简洁和高效。
在源码层面,SqlSessionFactoryBean的getObejct方法负责生成SqlSessionFactory实例,getObjectType方法返回SqlSessionFactory的类型信息,而isSingleton方法则用于判断该对象是thinkphp 游戏 源码下载否为单例。这些细节共同确保了SqlSessionFactory的正确创建和管理。
总之,FactoryBean在Spring框架中扮演了重要角色,它提供了一种灵活、强大的Bean创建机制,使得开发者能够更自由地定制和管理Bean。通过理解FactoryBean的工作原理和使用方式,可以更好地利用Spring框架的特性,实现更高效、灵活的系统开发。
Spring源码7.如何添加自定义的BeanFactoryPostProcessor
关于BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的父子关系鉴定:
由图示可知,BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类。
实现步骤包括新建类并实现接口,通过配置文件或自定义函数让Spring识别。
实现方式一:在配置文件中定义,启动类添加代码,输出结果验证。
实现方式二:重写ClassPathXmlApplicationContext的customizeBeanFactory函数,新建MyApplicationContext类,修改启动类,再次验证。
两种方法区别在于,方式二虽能成功执行新建类,但spring上下文对象的BeanDefinitionNames和BeanDefinitionMap不包含这些类。
使用Debug方式进一步确认,方式一能将新建类添加到Spring上下文,而方式二则不会。
总结:通过配置文件让Spring识别更为有效,能将自定义的BeanFactoryPostProcessor类添加到Spring上下文的BeanDefinitionMap和BeanDefinitionNames集合中。
使用Gateway作为SpringCloud网关
本着能用原生就用原生的原则,我们这里使用SpringGateway来作为云服务的网关
配置
从官网的介绍来看,spring网关拥有的功能有,路由(配置,过滤,重写等),熔断以及流量控制
首先引入包
动态路由
路由的配置比较简单,有两种方法:使用配置文件和代码注入,我们这里简单展示下两种方法
或者使用
路由配置中id、uri、order、predicates.path/host没什么好说的,根据需求配置即可,filters相关参数,这里最好还是参考源码相关部分或者Spring Cloud Gateway比较全面,比如常用的前缀切割
这里我们以常用的两种filter,流量控制和熔断降级举例
流量控制
通常我们需要限流来保证服务的可用性,保护一些不太稳定的服务不会因为高并发的请求而挂掉,这里我们一般在网关层做流量控制,减少实际进入的请求达到平波峰的目的
计数器算法
如果某个服务会在请求中数量达到时候挂掉,请求平均时间为2s,我们给一段时间一个请求量的限制,比如2秒次,每次请求进入就减少计数,每2s开始时重新计数,这样就能保证服务请求中数量在以内。但是对于抢购类接口,可能前ms请求数量就用完了,后面所有请求都被拒绝,即请求突刺现象,这样的用户体验是非常差的所以我们需要尽可能在所有的时间内保证接口的可用性(计数器算法就像DRAM中的集中式刷新一样不太能被接受),而且短时间内大量请求运行在相同代码段是非常危险的,在设计不好的情况很可能会出现数据库死锁等等问题
漏桶算法
我们需要让请求尽可能地能进行来,就需要平波峰填波谷,就上例而言,2s内最大请求为,也就是每个请求占用的时间比例为ms,我们设计一个容量为的桶(队列)每ms向接口发一个请求,可以让服务中请求数量不超过的情况下,每ms都能接受一个新的请求,这样就缓解了请求突刺现象。但是这里还有一个问题,对于抢购类接口,个容量可能ms就用完了,在第ms可能还会有个请求抢1个位置,个请求会被取消,这样也是相对来说不能被接受的
令牌桶算法
令牌桶算法就是目前spring cloud gateway采用的算法,这里采用的用户时间换用户失败的策略,假设我们认为用户的平均忍耐时间为8秒,接口超过8秒一些用户就要骂街了,减去实际执行的2秒,也就是说我们的可以利用6秒的时间容纳更多的请求。依上文而言每ms去调用这个端口,那么也就是说桶的设计可以更大,在桶里放上令牌,每个请求需要在桶里面拿到令牌才能调用,这里的桶容量就是6s/ms为个。但是我们的执行速度是不变的,也就是结果是,在请求多的情况下用户的执行时间在8秒左右,而在请求少的情况下执行速度在2s左右,这样就缓解了短时间内大量请求导致大量失败的问题了。这里比较重要的参数有两个,第一个是桶请求容量 defaultBurstCapacity,第二个是每秒执行的请求速度(也就是桶的填充速率)defaultReplenishRate
在这个例子中defaultBurstCapacity=而defaultReplenishRate=,这两个参数我们会在下方配置
这里我们需要引用redis包,再说明一下,本站使用的是jdk的版本,其他版本的配置和引用可能会稍有变化,需要调整
覆写KeyResolver的实现类
流量控制,这里同样有代码实现和配置文件实现,由于目前idea对于复杂配置文件的支持不太好,如果使用配置文件方式会疯狂报红,但是如果全部使用代码的话会不方便实现动态路由,因为gateway是先加载配置再处理代码的。所以这里我们路由使用配置,filter之类复杂的使用代码实现,下面是简单示例
这样全服务层面的接口流量控制就完成了,具体的哪些服务使用流量控制,具体控制参数的配置,自行稍作修改即可
测试流量控制的话,可以将令牌回复量和令牌总容量调至比较低的水平,然后再浏览器直接curl接口,比如令牌回复量和容量为1,则单秒内curl即可触发浏览器提示,线上大令牌容量测试能需要多线程curl了,这里参考官方文档给的lua脚本
ip限流
如果我们需要对某个ip进行限流,比如防止脚本抢货,我们这里需要KeyResolver的实现不再使用exchange.getRequest().getURI().getPath() ,而是使用 exchange.getRequest().getRemoteAddress() 。但是这里还有一个问题,我们请求是经过层层转发的,nginx,docker等,所以我们可能并不能拿到原始的请求地址,所以这里我们需要在最外层,比如nginx中将原始地址存到header或者cookie当中,这里给出简单示例
当然还有其他类似X-Forwarded-For的字段不再本文主要探讨范围就不多拓展了,在nginx中配置记录初始远程地址到header后,我们这里需要在程序中取出来,如果你这里使用的标准的X-Real-IP的字段去存储,那么只需要
即可获取真实地址,如果你这里自定义了一个header的key那么需要在exchange.getRequest().getHeaders()里面自己找出来了
最后我们这里给出对同一个接口同时配置两种限流的示例
我在ip限流这里修改了返回的code由改为了,方便测试,这里我们将ip的限流参数设置为(2,2),将path的限流参数设置为(1,)然后不断请求接口就发现一开始返回错误,后续path令牌桶用完后返回错误,即设置成功
补充
如果这里你不希望返回,并且要求返回一个用户可读的带有json信息结果,那么比较好的业务处理方式是前端完成。如果是对外接口的话,那么我们这里就只能重写RateLimiter的实现了,不再使用RedisRateLimiter的类,而是自己去继承RateLimiter接口去实现,
参考 SpringCloudGateway限流后,默认返回的改造:改跳转或增加响应body,这篇文章已经很详细,这里就不赘述了
熔断降级
熔断降级,即某个接口调用失败时使用其他接口代替,来保证整体服务对外的可用性
首先需要引入熔断包
circuitbreaker-reactor-resilience4j 熔断的相关配置分为两个部分,熔断逻辑本身的配置以及在集成到gateway中时候,网关的配置,熔断的重要的配置有,触发熔断的接口,代替接口,熔断超时时间(当然还有其他的,比如自定义熔断HttpStatus等等,详细参数参考 Spring Cloud Circuit Breaker以及resilience4j官网)
这里熔断触发接口和代替接口配置位于gateway中,这里我们使用代码实现,位置参考前述
这里setName的目的是和熔断包中的配置产生对应关系,下方为熔断包的配置,这里定义默认超时时间(也就是没有匹配到name的超时时间)为s,your_breaker_id的超时时间为3s
最后
到这里网关的基本功能就差不多了,自定义的一些业务功能配置,比如header,cookie,以及调用方ip的处理逻辑等等其实都是在网关层处理的,可以参考 Spring Cloud Gateway WebFilter Factories以及Writing Custom Spring Cloud Gateway Filters,但是这种配置基本都没什么坑,这里就不谈了
网关由于不经常作为业务逻辑被重构,所以网络上的资料相对比较少,我这里使用的又是最新的版本还是蛮多和前版本不一样的地方,尤其是webflux的一些东西,很多问题需要看源码才能解决,非常的消耗意志力。这里建议小伙伴们如果是业务使用的这种资料相对较少的架构,最好还是不要使用最新版本的比较好,毕竟万一遇到坑,踩个一两天是很正常的事情,而这种在业务场景可能就没那么容易接受了
盘点 Spring Boot 解决跨域请求的几种方法
在 web 系统开发中,跨域请求是一个常见的问题。浏览器基于同源策略,限制了不同源间的资源访问,导致接口请求无法正常进行。本文将介绍 Spring Boot 解决跨域请求的几种方法。
首先,要理解什么是跨域请求。简单来说,同源策略是浏览器出于安全考虑,仅允许协议、域名、端口号完全一致的资源访问,否则被认为是跨域请求。即使服务端能接收并返回结果,浏览器也会拦截请求。
以示例中的错误为例,访问源是 http://.0.0.1:/,而接口请求源为 http://localhost:,因不一致导致跨域异常。解决方法在于,通过 CORS 协议在浏览器内实现站内跨域请求访问。
实现此功能主要涉及添加特殊的 Header 响应属性。Spring Boot 提供了多种实现方式,包括过滤器、全局配置类和注解等。
方法一:通过过滤器全局配置跨域访问,实现过程包括创建过滤器、注册到 Servlet 容器,然后启动服务并测试。方法二:利用全局配置类简化实现,只需重写 WebMvcConfigurer 接口中的方法。方法三:针对特定接口进行局部跨域访问,使用 @CrossOrigin 注解控制。
总结,Spring Boot 可通过不同方式实现跨域访问,适合在开发环境中调试前后端。生产环境中应谨慎使用,可能需关闭或限制。如需获取源代码,点击链接即可。本文已整理技术笔记,包含 Spring 相关技术栈,点击链接获取。