关于springboot:SpringBoot启动流程原理解析二

<article class=“article fmt article-content”><blockquote>在上一章咱们剖析了SpingBoot启动流程中实例化SpingApplication的过程。</blockquote><p><code>return new SpringApplication(primarySources).run(args);</code><br/>这篇文章咱么说下<code>run()</code>办法开始之后都做了那些事件。<br/><br/>持续往下跟着源码进入到<code>run()</code>这个是比拟外围的一个办法了<br/></p><pre><code> public ConfigurableApplicationContext run(String… args) { StopWatch stopWatch = new StopWatch(); // 计时器开始 stopWatch.start(); // 创立启动上下文对象 DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; // 配置Handless模式,是在短少显示屏、键盘或鼠标时的系统配置 // 默认为true configureHeadlessProperty(); //获取并启动监听器 SpringApplicationRunListeners listeners = getRunListeners(args); // 启动监听器 listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 筹备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); // 疏忽配置的bean configureIgnoreBeanInfo(environment); // 打印banner,就是启动的时候在控制台的spring图案 Banner printedBanner = printBanner(environment); // 创立容器 context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 筹备利用上下文(spring容器前置解决) prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 刷新容器 refreshContext(context); // 刷新容器后的扩大接口(spring容器后置解决) afterRefresh(context, applicationArguments); // 完结计时器并打印,这就是咱们启动后console的显示的工夫 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 公布监听利用上下文启动实现(收回启动完结事件) listeners.started(context); // 执行runner callRunners(context, applicationArguments); } catch (Throwable ex) { // 异样解决,如果run过程产生异样 handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { // 监听利用上下文运行中 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } // 返回最终构建的容器对象 return context; }</code></pre><p>接下来就对下面的关键步骤一一解释</p><h3>1. 获取所有的监听器</h3><p><br/>这段代码咱们比拟相熟了,上一篇咱么具体介绍过,它的次要作用就是去<code>META-INFO/spring.factories</code> 中加载配置SpringApplicationRunListener的监听器如下<br/><br/>显然只有一个事件公布监听器类,拿到了<code>EventPublishingRunListener</code>启动事件公布监听器,下一步就是开始启动了<code>listeners.starting()</code>;咱们往下跟源码看</p><pre><code> @Override public void starting(ConfigurableBootstrapContext bootstrapContext) { this.initialMulticaster .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args)); }</code></pre><p>启动的时候实际上是又创立了一个<code>ApplicationStartingEvent</code>对象,其实就是监听利用启动事件。<br/>其中 <code>initialMulticaster</code>是一个<code>SimpleApplicationEventMuticaster</code></p><pre><code> public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); // 获取线程池,为每个监听事件创立一个线程 Executor executor = this.getTaskExecutor(); // 依据ApplicationStartingEvent事件类型找到对应的监听器,并迭代 Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { // executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } } }</code></pre><h3>2.筹备环境</h3><p><code>ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);</code></p><pre><code> private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment // 这里咱们退出了web依赖所以是一个servlet容器 ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置环境 configureEnvironment(environment, applicationArguments.getSourceArgs()); // 环境筹备实现 ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); configureAdditionalProfiles(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }</code></pre><p>因为咱们是增加了web的依赖 <code>getOrCreateEnvironment()</code>返回的是一个<code>standardservletEnviroment</code> 规范的servlet环境</p><h4>2.1 配置环境</h4><pre><code> protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { // 嵌入式的转换器 ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService) conversionService); } // 配置属性资源文件 configurePropertySources(environment, args); // 配置文件 configureProfiles(environment, args); }</code></pre><p>利用嵌入的转换器<code>ApplicationConversionService</code></p><pre><code> public static void configure(FormatterRegistry registry) { DefaultConversionService.addDefaultConverters(registry); DefaultFormattingConversionService.addDefaultFormatters(registry); // 格局转换 addApplicationFormatters(registry); // 类型转换 addApplicationConverters(registry); } ===============格局转换================= public static void addApplicationFormatters(FormatterRegistry registry) { registry.addFormatter(new CharArrayFormatter()); registry.addFormatter(new InetAddressFormatter()); registry.addFormatter(new IsoOffsetFormatter()); } ========================类型转换=================== public static void addApplicationConverters(ConverterRegistry registry) { addDelimitedStringConverters(registry); registry.addConverter(new StringToDurationConverter()); registry.addConverter(new DurationToStringConverter()); registry.addConverter(new NumberToDurationConverter()); registry.addConverter(new DurationToNumberConverter()); registry.addConverter(new StringToPeriodConverter()); registry.addConverter(new PeriodToStringConverter()); registry.addConverter(new NumberToPeriodConverter()); registry.addConverter(new StringToDataSizeConverter()); registry.addConverter(new NumberToDataSizeConverter()); registry.addConverter(new StringToFileConverter()); registry.addConverter(new InputStreamSourceToByteArrayConverter()); registry.addConverterFactory(new LenientStringToEnumConverterFactory()); registry.addConverterFactory(new LenientBooleanToEnumConverterFactory()); if (registry instanceof ConversionService) { addApplicationConverters(registry, (ConversionService) registry); } } </code></pre><h4>2.2 环境筹备实现</h4><blockquote>同下面启动监听事件,这次的环境筹备也是同样的代码</blockquote><pre><code> @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { this.initialMulticaster.multicastEvent( // 创立一个应用环境筹备事件对象 new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment)); }</code></pre><p>debug进去之后代码跟AppLicationstrigevent 事件对象是一样的。不再赘述。<br/>不过这里是7个监听器对象</p><h4>3.配置疏忽的bean</h4><p><code>configureIgnoreBeanInfo(environment);</code></p><h4>4.打印banner</h4><blockquote>这是SpringBoot默认的启动时的图标<br/><code>Banner printedBanner = printBanner(environment);</code><br/><br/>这个是能够自定义的,也能够是图篇或是文本文件中的图形</blockquote><h3>5.创立容器</h3><p>紧接着上一篇,接下来就是创立容器</p><pre><code> protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }</code></pre><h3>6.筹备利用上下文</h3><pre><code> private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 设置环境参数 context.setEnvironment(environment); // 设置后处理利用上下文 postProcessApplicationContext(context); //把从spring.factories中加载的org.springframework.bt.context.ConfigurationwarningsApplicationContextIitiaLizer,进行初始化操作 applyInitializers(context); //EventPubLishingRunListener公布利用上下文事件 listeners.contextPrepared(context); // 打印启动日志 bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton(“springApplicationArguments”, applicationArguments); if (printedBanner != null) { //注册一个字是springAppLicationArguments单例的bean beanFactory.registerSingleton(“springBootBanner”, printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources 获取所有资源 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, “Sources must not be empty”); // 创立BeanDefinitionLoader加载器加载注册所有的资源 load(context, sources.toArray(new Object[0])); // 同之前,公布利用上下文 加载事件 listeners.contextLoaded(context); }</code></pre><h3>7.刷新利用上下文</h3><blockquote>刷新利用上下文就进入了spring的源码了</blockquote><pre><code> public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start(“spring.context.refresh”); // Prepare this context for refreshing. //筹备刷新上下文 this.prepareRefresh(); // Tetl the subclass to refresh the internal bean facto // 告诉子类刷新外部工厂 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 筹备Bean工厂 this.prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in contex t subc lasses. // 容许在上下文子类中对bean工厂进行后处理。 // Invoke factory processors registered as beans in the context, this.postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start(“spring.context.beans.post-process”); this.invokeBeanFactoryPostProcessors(beanFactory); // 注册后置处理器。 this.registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // 初始化信息源 this.initMessageSource(); // 初始化上下文事件公布器 this.initApplicationEventMulticaster(); // 初始化其余自定义bean this.onRefresh(); // 注册监听器 this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); //实现刷新,清缓存,初始化生命周期,事件公布等 this.finishRefresh(); } catch (BeansException var10) { if (this.logger.isWarnEnabled()) { this.logger.warn(“Exception encountered during context initialization - cancelling refresh attempt: " + var10); } // 销毁bean this.destroyBeans(); // Reset ‘active’flag. this.cancelRefresh(var10); throw var10; } finally { this.resetCommonCaches(); contextRefresh.end(); } } }</code></pre><p>刷新的代码有点深,也是在这时创立了Tomcat对象,这也是<code>SpringBoot</code><strong> 一键启动</strong>web工程的要害<br/></p><p><br/>创立了Tomcat对象,并设置参数</p><pre><code> @Override public WebServer getWebServer(ServletContextInitializer… initializers) { if (this.disableMBeanRegistry) { Registry.disableRegistry(); } Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir(“tomcat”); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); connector.setThrowOnFailure(true); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); // 返回TomcatWebServer服务 return getTomcatWebServer(tomcat); }</code></pre><p></p><h3>8.刷新后处理</h3><blockquote><code>afterReftesh();</code> //是个一空实现,留着前期扩大</blockquote><pre><code> /** * Called after the context has been refreshed. * @param context the application context * @param args the application arguments */ protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { }</code></pre><h3>9.公布监听利用启动事件</h3><pre><code> @Override public void started(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context)); AvailabilityChangeEvent.publish(context, LivenessState.CORRECT); }</code></pre><blockquote>这里是调用context.publishEvent()办法,公布利用启动事件ApplicationStartedEvent.</blockquote><h3>10.执行Runner</h3><blockquote>获取所有的ApplicationRuner和CommandLineRunner来初始化一些参数,callRuner(是一个回调函数)</blockquote><pre><code> private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }</code></pre><h3>11.公布上下文筹备实现的事件</h3><p><code>listeners.running(context);</code></p><pre><code> @Override public void running(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context)); AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC); }</code></pre><p>这段代码看上去似成相识,后面有很多相似的代码,不同的是这里上下文筹备实现之后公布了一个ApplicationReadyEvent事件,申明一下利用上下文筹备实现。</p><h3>小结</h3><p>这篇次要是介绍了SpringBoot启动过程中<code>run()</code>的这个过程。从中咱们也能够发现一些十分好的编码习惯,大家能够在日常的工作中从模拟到内化,缓缓变成本人的货色。</p><blockquote>如果你最近正在学习SpringBoot,能够参考我的集体网站:程序员波特,目前曾经更新了SpringBoot2.x,SpringBoot3.x的系列学习教程,心愿能够帮忙到你。</blockquote></article> ...

March 4, 2024 · 4 min · jiezi

关于springboot:SpringCloud微服务实战搭建企业级开发框架四十二集成分布式任务调度平台XXLJOB实现定时任务功能

February 27, 2024 · 0 min · jiezi

关于springboot:接私活利器推荐一个基于SpringBoot3的后台管理框架

大家好,我是 Java陈序员。 明天,给大家举荐一个后盾治理框架,适宜二次定制开发、接私活、源码学习等场景。 关注微信公众号:【Java陈序员】,获取开源我的项目分享、AI副业分享、超200本经典计算机电子书籍等。我的项目介绍Admin3 —— 一个笨重的后盾治理框架,我的项目后端基于 Java17、SpringBoot3.0,前端基于 TypeScript、Vite3、Vue3、Element Plus,提供登录会话、用户治理、角色治理、权限资源管理、事件日志、对象存储等根底性能。 性能特色: 我的项目截图 疾速上手环境筹备: JDK 17MySQL 8.0Maven 3.6.0+Node.js1、拉取代码 git clone https://github.com/cjbi/admin3.gitTips:前后端代码都在一个我的项目下。2、创立数据库 CREATE DATABASE admin3 CHARACTER SET utf8 COLLATE utf8_general_ci;3、批改配置文件 application.yml 中的数据库地址、用户名、明码 4、启动后端服务 // 启动类tech.wetech.admin3.Admin3ServerApplication5、接口文档 Swagger 地址 http://localhost:8080/admin3/swagger-ui/index.html6、启动前端服务 cd admin3-ui## 装置依赖pnpm i## 启动我的项目pnpm run dev最初举荐的开源我的项目曾经收录到 GitHub 我的项目,欢送 Star: https://github.com/chenyl8848/great-open-source-project或者拜访网站,进行在线浏览: https://chencoding.top:8090/#/大家的点赞、珍藏和评论都是对作者的反对,如文章对你有帮忙还请点赞转发反对下,谢谢!

February 22, 2024 · 1 min · jiezi

关于springboot:SpringBoot工具类

<article class=“article fmt article-content”><p>断言<br/>1.断言是一个逻辑判断,用于查看不应该产生的状况</p><p>2.Assert 关键字在 JDK1.4 中引入,可通过 JVM 参数-enableassertions开启</p><p>3.SpringBoot 中提供了 Assert 断言工具类,通常用于数据合法性检查</p><pre><code>// 要求参数 object 必须为非空(Not Null),否则抛出异样,不予放行// 参数 message 参数用于定制异样信息。void notNull(Object object, String message)// 要求参数必须空(Null),否则抛出异样,不予『放行』。// 和 notNull() 办法断言规定相同void isNull(Object object, String message)void isNull(Object object, String message)void notEmpty(Collection collection, String message)void hasLength(String text, String message)void hasText(String text, String message)</code></pre><p>对象、数组、汇合<br/>ObjectUtils</p><pre><code>// 获取对象的类名。参数为 null 时,返回字符串:“null” String nullSafeClassName(Object obj) // 参数为 null 时,返回 0 int nullSafeHashCode(Object object) // 参数为 null 时,返回字符串:“null” String nullSafeToString(boolean[] array) // 获取对象 HashCode(十六进制模式字符串)。参数为 null 时,返回 0 String getIdentityHexString(Object obj) // 获取对象的类名和 HashCode。 参数为 null 时,返回字符串:"" String identityToString(Object obj) // 相当于 toString()办法,但参数为 null 时,返回字符串:"" String getDisplayString(Object obj)</code></pre><p>判断工具</p><pre><code>// 判断数组是否为空boolean isEmpty(Object[] array)// 判断参数对象是否是数组boolean isArray(Object obj)// 判断数组中是否蕴含指定元素boolean containsElement(Object[] array, Object element)// 相等,或同为 null时,返回 trueboolean nullSafeEquals(Object o1, Object o2)/*判断参数对象是否为空,判断规范为: Optional: Optional.empty() Array: length == 0 CharSequence: length == 0 Collection: Collection.isEmpty() Map: Map.isEmpty() */boolean isEmpty(Object obj)</code></pre><p>StringUtils</p><p>字符串判断工具</p><pre><code>// 判断字符串是否为 null,或 “"。留神,蕴含空白符的字符串为非空boolean isEmpty(Object str)// 判断字符串是否是以指定内容完结。疏忽大小写boolean endsWithIgnoreCase(String str, String suffix)// 判断字符串是否已指定内容结尾。疏忽大小写boolean startsWithIgnoreCase(String str, String prefix) // 是否蕴含空白符boolean containsWhitespace(String str)// 判断字符串非空且长度不为 0,即,Not Emptyboolean hasLength(CharSequence str)// 判断字符串是否蕴含理论内容,即非仅蕴含空白符,也就是 Not Blankboolean hasText(CharSequence str)// 判断字符串指定索引处是否蕴含一个子串。boolean substringMatch(CharSequence str, int index, CharSequence substring)// 计算一个字符串中指定子串的呈现次数int countOccurrencesOf(String str, String sub)字符串操作工具// 查找并替换指定子串String replace(String inString, String oldPattern, String newPattern)// 去除尾部的特定字符String trimTrailingCharacter(String str, char trailingCharacter) // 去除头部的特定字符String trimLeadingCharacter(String str, char leadingCharacter)// 去除头部的空白符String trimLeadingWhitespace(String str)// 去除头部的空白符String trimTrailingWhitespace(String str)// 去除头部和尾部的空白符String trimWhitespace(String str)// 删除结尾、结尾和两头的空白符String trimAllWhitespace(String str)// 删除指定子串String delete(String inString, String pattern)// 删除指定字符(能够是多个)String deleteAny(String inString, String charsToDelete)// 对数组的每一项执行 trim() 办法String[] trimArrayElements(String[] array)// 将 URL 字符串进行解码String uriDecode(String source, Charset charset)门路相干工具办法// 解析门路字符串,优化其中的 “..” String cleanPath(String path) // 解析门路字符串,解析出文件名局部 String getFilename(String path) // 解析门路字符串,解析出文件后缀名 String getFilenameExtension(String path) // 比拟两个两个字符串,判断是否是同一个门路。会主动解决门路中的 “..” boolean pathEquals(String path1, String path2) // 删除文件路径名中的后缀局部 String stripFilenameExtension(String path) // 以 “. 作为分隔符,获取其最初一部分 String unqualify(String qualifiedName) // 以指定字符作为分隔符,获取其最初一部分 String unqualify(String qualifiedName, char separator)</code></pre><p>CollectionUtils</p><pre><code>汇合判断工具// 判断 List/Set 是否为空boolean isEmpty(Collection<?> collection)// 判断 Map 是否为空boolean isEmpty(Map<?,?> map)// 判断 List/Set 中是否蕴含某个对象boolean containsInstance(Collection<?> collection, Object element)// 以迭代器的形式,判断 List/Set 中是否蕴含某个对象boolean contains(Iterator<?> iterator, Object element)// 判断 List/Set 是否蕴含某些对象中的任意一个boolean containsAny(Collection<?> source, Collection<?> candidates)// 判断 List/Set 中的每个元素是否惟一。即 List/Set 中不存在反复元素boolean hasUniqueObject(Collection<?> collection)</code></pre><p>文件、资源、IO 流</p><p>FileCopyUtils</p><pre><code>// 从文件中读入到字节数组中byte[] copyToByteArray(File in)// 从输出流中读入到字节数组中byte[] copyToByteArray(InputStream in)// 从输出流中读入到字符串中String copyToString(Reader in)// 从字节数组到文件void copy(byte[] in, File out)// 从文件到文件int copy(File in, File out)// 从字节数组到输入流void copy(byte[] in, OutputStream out) // 从输出流到输入流int copy(InputStream in, OutputStream out) // 从输出流到输入流int copy(Reader in, Writer out)// 从字符串到输入流void copy(String in, Writer out)</code></pre><p>ResourceUtils</p><p>从资源门路获取文件</p><pre><code>// 判断字符串是否是一个非法的 URL 字符串。static boolean isUrl(String resourceLocation)// 获取 URLstatic URL getURL(String resourceLocation) // 获取文件(在 JAR 包内无奈失常应用,须要是一个独立的文件)static File getFile(String resourceLocation)</code></pre><p>AopUtils</p><pre><code>判断代理类型// 判断是不是 Spring 代理对象boolean isAopProxy()// 判断是不是 jdk 动静代理对象isJdkDynamicProxy()// 判断是不是 CGLIB 代理对象boolean isCglibProxy()获取被代理对象的 class// 获取被代理的指标 classClass<?> getTargetClass()</code></pre><p>AopContext</p><pre><code>// 获取以后对象的代理对象Object currentProxy()</code></pre></article> ...

February 20, 2024 · 2 min · jiezi

关于springboot:SpringBoot执行异步任务Async介绍

前言本篇文章的代码示例已放到 github 上,Git地址为:advance(记录每一个学习过程),大家把代码下载下来之后,全局搜寻一些要害代码,即可找到该文章的源码。 大家感觉有用的话,麻烦点个star再走呗!应用场景当咱们在应用SpringBoot进行开发的时候,可能会遇到一些执行异步工作的场景,如果每次执行这些异步工作都去新建一个异步线程来执行的话,那代码就太冗余了。幸好SpringBoot给咱们提供了Async的注解,让咱们可能很轻松地对这些异步工作进行执行。 应用示例在启动类上应用@EnableAsync注解,示意开启异步工作 @EnableAsync@SpringBootApplicationpublic class AsycnDemoApplication { public static void main(String[] args) { SpringApplication.run(AsycnDemoApplication.class, args); }}将须要执行的异步办法所在的类,退出到Spring的容器中,能够应用@Component注解 @Componentpublic class AsyncComponent {}在须要异步执行的办法上,退出@Async注解 @Componentpublic class AsyncComponent { @Async public void async(String str){ System.out.println("输出的内容是" + str + ",异步工作正在休眠5秒.."); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { System.out.println("休眠失败"); } System.out.println("输出的内容是" + str + ",异步工作执行完结"); }}在其余须要调用的中央,将这个异步办法所在的类进行注入,而后调用 @Componentpublic class LineRunner implements CommandLineRunner { @Autowired private AsyncComponent asyncComponent; @Override public void run(String... args) throws Exception { System.out.println("主线程开始"); asyncComponent.async("明天不下班,好耶"); asyncComponent.selfAsync(); System.out.println("主线程完结"); }}执行后果 ...

September 23, 2023 · 1 min · jiezi

关于springboot:SpringBoot-如何集成-Redis-实现布隆过滤器

前言本篇文章的代码示例已放到 github 上,Git地址为:advance(记录每一个学习过程),我的项目的介绍页面是我所有文章的一个援用目录,大家在援用目录外面即可找到对应文章的一个代码门路。 大家感觉有用的话,麻烦点个star再走呗!应用场景针对 Redis 的缓存穿透问题,布隆过滤器是一个常见的解决办法。在单机的场景下,咱们能够应用谷歌的 guava 包外面提供的布隆过滤器。在分布式的场景下,咱们也能够选用 Redis 来实现布隆过滤器。 尽管,Redis 的 BitMap人造就能够作为 布隆过滤器来实现,但毕竟本人实现的话,还是会有点麻烦。因而,咱们能够选用 redisson 提供的布隆过滤器,进步咱们的开发效率。 罕用办法配置布隆过滤器的Bean @Beanpublic RBloomFilter<String> bloomFilter(){ // 定义一个布隆过滤器,指定布隆过滤器的名称 RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("bloomTest"); //定义布隆过滤器的大小,以及误差率 bloomFilter.tryInit(100000L, 0.003); return bloomFilter;}获取布隆过滤器 配置完之后,这个布隆过滤器就在 Spring 容器外面了,能够间接注入进来 @Autowiredprivate RBloomFilter<String> bloomFilter;增加元素 String name1 = "小明";String name2 = "小张";bloomFilter.add(name1);bloomFilter.add(name2);判断布隆过滤器中是否存在某元素 boolean flag1 = bloomFilter.contains("小明");System.out.println("布隆过滤器中是否可能有小明?" + flag1);获取布隆过滤器的元素总数 System.out.println("以后布隆过滤器中有多少个数?" + bloomFilter.count());获取布隆过滤器预计能够插入多少个数 System.out.println("预计布隆过滤器中能够插入多少个数?" + bloomFilter.getExpectedInsertions());获取布隆过滤器的容错率 System.out.println("布隆过滤器的容错率:" + bloomFilter.getFalseProbability());获取哈希函数的个数 System.out.println("布隆过滤器哈希哈数的个数:" + bloomFilter.getHashIterations());获取 Bit 位的个数 System.out.println("布隆过滤器的bit位有多少个?" + bloomFilter.getSize());应用示例@Componentpublic class LineRunner implements CommandLineRunner { @Autowired private RBloomFilter<String> bloomFilter; @Override public void run(String... args) throws Exception { String name1 = "小明"; String name2 = "小张"; bloomFilter.add(name1); bloomFilter.add(name2); boolean flag1 = bloomFilter.contains("小明"); System.out.println("布隆过滤器中是否可能有小明?" + flag1); boolean flag2 = bloomFilter.contains("小李"); System.out.println("布隆过滤器中是否可能有小李?" + flag2); System.out.println("以后布隆过滤器中有多少个数?" + bloomFilter.count()); System.out.println("预计布隆过滤器中能够插入多少个数?" + bloomFilter.getExpectedInsertions()); System.out.println("布隆过滤器的容错率:" + bloomFilter.getFalseProbability()); System.out.println("布隆过滤器哈希哈数的个数:" + bloomFilter.getHashIterations()); System.out.println("布隆过滤器的bit位有多少个?" + bloomFilter.getSize()); }}运行后果 ...

September 23, 2023 · 1 min · jiezi

关于springboot:SpringBoot疫苗在线预约接种系统

SpringBoot疫苗在线预约接种零碎零碎性能首页: 图片轮播宣传 疫苗列表 在线预约疫苗 新闻资讯 新闻详情 登录注册 留言板 集体核心 我的预约 后盾治理: 登录 新闻治理 留言板治理 回复治理 预约治理 用户治理 疫苗库治理 系统管理 用户治理 角色治理 日志治理 操作日志 登录日志 开发环境和技术开发语言:Java应用框架: SpringBoot + Mybatis + shiro前端: thymeleaf数据库:Mysql架构:B/S源码类型: Web编译开发工具:Idea、Eclipse、MyEclipse (选其一)其余:jdk1.8性能图片展现 总结源码获取: 大家可点赞、珍藏、关注、评论、私信

September 21, 2023 · 1 min · jiezi

关于springboot:Spring-Boot分页

第一步:定义方法 @PostMapping("list") public Object list(@RequestBody PageParam pageParam) { //以后页码 int current = (int)pageParam.getPageNum(); //每页条数 int size = (int)pageParam.getPageSize(); //构建 分页结构器 IPage<User> page = new Page(current, size); //构建 条件结构器 QueryWrapper<User> wrapper = new QueryWrapper<>(); userMapper.selectPage(page, wrapper); List<User> records = page.getRecords();//当前页数据 long total = page.getTotal();//总条数 long pages = page.getPages();//总页数 records.forEach(System.out::println); System.out.println("以后数据总共有:"+total); System.out.println("共"+pages+"页"); System.out.println("当前页数据:"+records); return Result.suc(records, total); }第二步:定义UserMapper.java package com.example.demo12.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.example.demo12.entity.User;import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapperpublic interface UserMapper extends BaseMapper<User> { List<User> listAll();}第三步:UserMapper.xml <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.demo12.mapper.UserMapper"> <select id = "listAll" resultType="com.example.demo12.entity.User"> select * from user </select> <select id = "userCount" resultType="java.lang.Integer"> select count(1) from user </select> <select id = "listTest" resultType="com.example.demo12.entity.User"> select * from user </select> <select id = "testUserCount" resultType="java.lang.Integer"> select count(1) from user </select></mapper>

September 21, 2023 · 1 min · jiezi

关于springboot:Spring-Boot-30-正式发布王炸

Spring Boot 3.0 正式公布大家好,我是栈长。 Spring Boot 3.0 正式公布了: 同时公布更新的还有 2.7.x 和 2.6.x 两条版本线,Spring Boot 是我见过的发版最守时的技术框架之一。 Spring Boot 3.0 这是一个重大的主版本更新,间隔上一代的 Spring Boot 2.0 的公布曾经过来 4 年多了,Spring Boot 3.0 也是第一个反对 Spring 6.0+ 和 GraalVM 的 Spring Boot 正式版本。 Spring Boot 3.0 重大新个性时隔四年多,Spring Boot 3.0 这是一个断崖式的版本更新,这四年多的工夫,技术突飞猛进,无疑更新了太多的个性,也修复了海量的 bug 的性能晋升,明天栈长就聊聊 Spring Boot 3.0 的几个重大新个性。 1、最低环境要求Spring Boot 3.0 最低要求 Java 17,并向上兼容反对 Java 19。 所以,如果你想降级 Spring Boot 3.0,请确保你的 JDK 版本是否符合要求,毕竟当初大部分人还是用的 Java 8,降级 JDK 版本不是一件小事,尽管当初 Java 17+ 是收费应用的,但不确定哪个工夫点会免费,也能够转战 OpenJDK 或者其余开源的 JDK 版本。 ...

September 19, 2023 · 2 min · jiezi

关于springboot:聊聊springboot自动装配出现的TypeNotPresentExceptionProxy异常排查

前言注释开始前,咱们做个小测试,假如咱们封装了一个springboot starter,其主动拆卸类形如下内容 @Configuration@EnableConfigurationProperties({ApolloRefreshProperties.class})public class ApolloRefreshAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnClass({ConfigService.class}) public ApolloRefreshService apolloRefreshService(ApolloRefreshProperties properties) { return new ApolloRefreshService(properties); } }该starter的pom引入的apollo gav是optional <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>${apollo-client.version}</version> <optional>true</optional> </dependency>我的问题是 在运行环境为jdk8的springboot我的项目引入上述的starter,是否会有问题?咱们运行一下,发现会呈现而后咱们不改任何一行代码,把JDK调成11或者以上版本,再运行我的项目胜利运行。那咱们的修复的第一直觉是不是把JDK8的版本进步。 咱们团队的小伙伴第一工夫也是这么干的,他去和业务团队的技术经理沟通,看他们能不能把JDK8调整成JDK11,而后失去了业务团队技术经理的高度否定,因为他们大部分业务都跑在jdk8,冒然升级成jdk11,也不晓得会不会因为了解决一个问题,而引入其余问题 问题排查因为这个starter的主动拆卸配置的内容绝对简略,基于老司机的第六感,问题大概率是呈现在@ConditionalOnClass这注解上,于是点开@ConditionalOnClass,他的注解上有如下提醒他的粗心是,能够在@Configuration classes上平安地指定value(),因为在加载类之前会应用ASM解析正文元数据。当搁置在@Bean办法上时,须要分外小心,请思考在独自的Configuration类中隔离条件,特地是当办法的返回类型与条件的指标匹配时。如果非要用办法注解,倡议应用ConditionalOnClass外面的name字段 于是咱们听官网的倡议,将starter调整如下 @Configuration@EnableConfigurationProperties({ApolloRefreshProperties.class})public class ApolloRefreshAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnClass(name = "com.ctrip.framework.apollo.ConfigService") public ApolloRefreshService apolloRefreshService(ApolloRefreshProperties properties) { return new ApolloRefreshService(properties); } }再次运行,果然不再报错。具体问题起因,我就不班门弄斧了,能够查看官网的issue https://github.com/spring-projects/spring-boot/issues/27846 https://github.com/spring-projects/spring-boot/issues/17282 总结首先如果用 @ConditionalOnClass注解,强烈建议应用name属性,而不要用value属性。其次如果有提供组件给其余业务团队应用,要特地关注版本问题,以及做好向下兼容,不然指不定又掉坑了。

September 19, 2023 · 1 min · jiezi

关于springboot:SSM-SpringBoot-vue快递柜管理系统

SSM SpringBoot vue快递柜管理系统零碎性能登录 注册 集体核心 快递员治理 用户信息管理  用户寄件治理 配送信息管理 存放信息管理 开发环境和技术开发语言:Java应用框架: SSM(Spring + SpringMVC + Mybaits)或SpringBoot前端: vue数据库:Mysql架构:B/S源码类型: Web编译开发工具:Idea、Eclipse、MyEclipse (选其一)其余:jdk1.8性能图片展现 总结源码获取: 大家可点赞、珍藏、关注、评论、私信

September 11, 2023 · 1 min · jiezi

关于springboot:SpringBoot集成微信支付JSAPIV3保姆教程

前言最近为一个公众号h5商城接入了微信领取性能,查找材料过程中踩了很多坑,以此文章记录一下和大家分享 后期筹备公众号认证微信领取性能须要开明企业号并进行资质认证,费用一年300,且需企业营业执照等信息,对公账户打款验证 登录微信公众平台https://mp.weixin.qq.com/,创立服务号 如果已有服务号扫码登录后点击公众号头像抉择认证详情菜单 商户开明点击公众号左侧微信领取菜单,抉择右侧关联商户按钮,如果没有商户按指引申请 参数获取公众号参数点击左侧根本配置菜单,记录右侧的利用ID(appid) 商户参数点击公众号左侧微信领取菜单,滑动到已关联商户号,点击查看按钮 进入商户后,抉择产品核心,左侧开发配置,记录商户号(mchId) 进入商户后,抉择账户核心,左侧API平安,依照指引获取APIV3密钥(apiV3Key),API证书的序列号(merchantSerialNumber)和私钥文件apiclient_key.pem 参数配置外网映射在微信领取本地调试时须要用到外网映射工具,这里举荐NATAPP:https://natapp.cn/(非广) 一个月带备案域名的映射隧道12元,咱们须要两个,一个映射公众号菜单页面,一个映射后端接口 公众号参数进入公众点击左侧自定义菜单,右侧点击增加菜单,输出外网映射后的菜单地址 如果你是老手,须要进行网页受权认证获取用户openid,那你还须要进行网页受权域名的设置 点左侧接口权限菜单,批改右侧的网页受权用户信息获取 进入后设置JS接口平安域名,会须要将一个txt认证文件搁置到你的动态页面目录,参照指引即可 商户参数进入商户后,抉择产品核心,左侧我的产品,进入JSAPI领取 点击产品设置,在领取配置模块,增加领取受权目录(后端接口和前端网页都增加) 领取对接参数申明wechartpay: # 公众号id appId: xxx # 公众号中微信领取绑定的商户的商户号 mchId: xxxx # 商户apiV3Keyz密钥 apiV3Key: xxxx #商户证书序列号 merchantSerialNumber: xxxx # 领取回调地址 v3PayNotifyUrl: http://xxxxxx/wechatpay/pay_notify # 退款回调地址 v3BackNotifyUrl: http://xxxxx/wechatpay/back_notify @Value("${wechartpay.appId}") private String appId; @Value("${wechartpay.mchId}") private String mchId; @Value("${wechartpay.apiV3Key}") private String apiV3Key; @Value("${wechartpay.merchantSerialNumber}") private String merchantSerialNumber; @Value("${wechartpay.v3PayNotifyUrl}") private String v3PayNotifyUrl; @Value("${wechartpay.v3BackNotifyUrl}") private String v3BackNotifyUrl; public static RSAAutoCertificateConfig config = null; public static JsapiServiceExtension service = null; public static RefundService backService = null; private void initPayConfig() { initConfig(); // 构建service if (service == null) { service = new JsapiServiceExtension.Builder().config(config).build(); } } private void initBackConfig() { initConfig(); // 构建service if (backService == null) { backService = new RefundService.Builder().config(config).build(); } } private void initConfig() { String filePath = getFilePath("apiclient_key.pem"); if (config == null) { config = new RSAAutoCertificateConfig.Builder() .merchantId(mchId) .privateKeyFromPath(filePath) .merchantSerialNumber(merchantSerialNumber) .apiV3Key(apiV3Key) .build(); } } public RSAAutoCertificateConfig getConfig() { initConfig(); return config; } public static String getFilePath(String classFilePath) { String filePath = ""; try { String templateFilePath = "tempfiles/classpathfile/"; File tempDir = new File(templateFilePath); if (!tempDir.exists()) { tempDir.mkdirs(); } String[] filePathList = classFilePath.split("/"); String checkFilePath = "tempfiles/classpathfile"; for (String item : filePathList) { checkFilePath += "/" + item; } File tempFile = new File(checkFilePath); if (tempFile.exists()) { filePath = checkFilePath; } else { //解析 ClassPathResource classPathResource = new ClassPathResource(classFilePath); InputStream inputStream = classPathResource.getInputStream(); checkFilePath = "tempfiles/classpathfile"; for (int i = 0; i < filePathList.length; i++) { checkFilePath += "/" + filePathList[i]; if (i == filePathList.length - 1) { //文件 File file = new File(checkFilePath); if (!file.exists()) { FileUtils.copyInputStreamToFile(inputStream, file); } } else { //目录 tempDir = new File(checkFilePath); if (!tempDir.exists()) { tempDir.mkdirs(); } } } inputStream.close(); filePath = checkFilePath; } } catch (Exception e) { e.printStackTrace(); } return filePath; }将apiclient_key.pem私钥文件拷贝到resources文件夹根目录 ...

September 11, 2023 · 5 min · jiezi

关于springboot:Springboot-Security登陆简单实现

前一段时间写了无关登陆的性能。包含Springboot security的简略应用,微信扫码登陆,接入spring cloud 的微信登陆。本文就无关Springboot security的登陆做一些简略记录。 我的项目地址见文末 Springboot security登陆对于登陆性能的实现采取的是Basic64传输登陆信息,token认证。本文以此为例。 用户登陆就是服务器接管到用户输出的用户名和明码而后与数据库中的用户名和明码比对。胜利,则颁发X-auth-token,失败则返回401 而通过Springboot Security去实现登陆性能,能够实现登陆与认证的自动化。 实现流程用户在浏览器中输出用户名明码进行登陆,该信息通过Base64编码之后放到申请头并发动申请。后盾接管到相干申请之后调用Basic64的解码形式进行解码并获取到用户名和明码信息。调用loadUserByUsername()办法获取相应用户实体。获取用户实体之后将该用户申请中的明码和实体的明码进行匹配。匹配胜利:颁发token,前台进行相干跳转;匹配失败:返回401。注:登录流程的实现由过滤器实现 Springboot security配置项通过图示,能够看出咱们须要通知Springboot security解码形式(Basic64),如何获取用户信息,如何比对明码(PasswordEncoder),后续通信如何进行身份认证(X-auth-token) 其中①解码形式,②明码比对形式,③身份认证形式 在我的项目中由配置类设定。④如何获取用户信息则由实现接口办法实现。 配置文件在config文件夹中创立一个配置类MvcSecurityConfig,内容如下。 @Configuration@EnableWebSecurity@EnableSpringHttpSessionpublic class MvcSecurityConfig extends WebSecurityConfigurerAdapter { private final BCryptPasswordEncoder passwordEncoder; public MvcSecurityConfig() { this.passwordEncoder = new BCryptPasswordEncoder(); User.setPasswordEncoder(this.passwordEncoder); } /** * https://spring.io/guides/gs/securing-web/ * * @param http http平安 * @throws Exception 异样 */ @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 凋谢端口 .antMatchers("/h2-console/**").permitAll() .antMatchers("/wechat/**").permitAll() .antMatchers("/websocket/**").permitAll() .anyRequest().authenticated() .and() .httpBasic() .and().cors() .and().csrf().disable(); http.headers().frameOptions().disable(); } @Bean PasswordEncoder passwordEncoder() { return this.passwordEncoder; } @Bean public HttpSessionStrategy httpSessionStrategy() { return new HeaderAndParamHttpSessionStrategy(); } @Bean public SessionRepository sessionRepository() { return new MapSessionRepository(); }}①解码形式,②明码比对形式,③身份认证形式别离对应其中的httpBasic(), passwordEncoder(), httpSessionStrategy()。而 ④如何获取用户信息 则在UserService中实现UserDetailsService接口来规定。 ...

September 10, 2023 · 1 min · jiezi

关于springboot:聊聊springboot的ConfigurationProperties的绑定

序本文次要钻研一下springboot的ConfigurationProperties的绑定 ConfigurationPropertiesBindingPostProcessororg/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java /** * {@link BeanPostProcessor} to bind {@link PropertySources} to beans annotated with * {@link ConfigurationProperties @ConfigurationProperties}. * * @author Dave Syer * @author Phillip Webb * @author Christian Dupuis * @author Stephane Nicoll * @author Madhura Bhave * @since 1.0.0 */public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean { /** * The bean name that this post-processor is registered with. */ public static final String BEAN_NAME = ConfigurationPropertiesBindingPostProcessor.class.getName(); private ApplicationContext applicationContext; private BeanDefinitionRegistry registry; private ConfigurationPropertiesBinder binder; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void afterPropertiesSet() throws Exception { // We can't use constructor injection of the application context because // it causes eager factory bean initialization this.registry = (BeanDefinitionRegistry) this.applicationContext.getAutowireCapableBeanFactory(); this.binder = ConfigurationPropertiesBinder.get(this.applicationContext); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 1; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName)); return bean; } private void bind(ConfigurationPropertiesBean bean) { if (bean == null || hasBoundValueObject(bean.getName())) { return; } Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '" + bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean"); try { this.binder.bind(bean); } catch (Exception ex) { throw new ConfigurationPropertiesBindException(bean, ex); } } private boolean hasBoundValueObject(String beanName) { return this.registry.containsBeanDefinition(beanName) && this.registry .getBeanDefinition(beanName) instanceof ConfigurationPropertiesValueObjectBeanDefinition; } /** * Register a {@link ConfigurationPropertiesBindingPostProcessor} bean if one is not * already registered. * @param registry the bean definition registry * @since 2.2.0 */ public static void register(BeanDefinitionRegistry registry) { Assert.notNull(registry, "Registry must not be null"); if (!registry.containsBeanDefinition(BEAN_NAME)) { BeanDefinition definition = BeanDefinitionBuilder .genericBeanDefinition(ConfigurationPropertiesBindingPostProcessor.class, ConfigurationPropertiesBindingPostProcessor::new) .getBeanDefinition(); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(BEAN_NAME, definition); } ConfigurationPropertiesBinder.register(registry); }}ConfigurationPropertiesBindingPostProcessor实现了BeanPostProcessor、PriorityOrdered、ApplicationContextAware、InitializingBean四个接口;其getOrder办法返回的是Ordered.HIGHEST_PRECEDENCE + 1即仅次于最高的优先级;其postProcessBeforeInitialization办法次要是执行bind办法(先通过ConfigurationPropertiesBean.get获取ConfigurationPropertiesBean,再通过binder进行bind);其afterPropertiesSet次要是获取BeanDefinitionRegistry与ConfigurationPropertiesBinderConfigurationPropertiesBean.getorg/springframework/boot/context/properties/ConfigurationPropertiesBean.java ...

September 7, 2023 · 5 min · jiezi

关于springboot:spring循环依赖启动不来

援用的中央加@Lazy注解

September 6, 2023 · 1 min · jiezi

关于springboot:Springboot-使用easyexcel读写Excel

<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency>简略粗犷无效,间接ImportExcel.class对象全副String类型,读取到data后,按需本人解决 public String readExcel(@RequestPart("file") MultipartFile file) { try { EasyExcel.read(file.getInputStream(), ImportExcel.class, new ReadListener<ImportExcel>() { public static final int BATCH_COUNT = 10; private List<ImportExcel> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); @Override public void invoke(ImportExcel data, AnalysisContext context) { // todo 全副为String类型的按需转换为本人最终想要的类型 data.setHeight(setHeight(data.getHeight())); log.error("{}", data); cachedDataList.add(data); if (cachedDataList.size() >= BATCH_COUNT) { saveData(); cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } private String setHeight(String height) { return new BigDecimal(height).add(new BigDecimal("200000")).toString(); } @Override public void doAfterAllAnalysed(AnalysisContext context) { saveData(); } private void saveData() { log.info("{}条数据,开始存储数据库!", cachedDataList.size()); log.info("存储数据库胜利!"); } }).sheet().doRead(); } catch (Exception e) { e.printStackTrace(); } return "ok"; }

September 5, 2023 · 1 min · jiezi

关于springboot:知识整理基于Springboot的Kafka消费者动态操作

基于Springboot的Kafka消费者动静操作1. 问题 在基于Springboot开发Kafka相干业务时,遇到如下业务场景: 执行局部操作时,如进行服务替换镜像、执行非凡业务解决等,须要先进行Consumer接管Kafka音讯,待处理实现后再开启Consumer接续接管Kafka音讯为并发生产Kafka音讯,可通过配置spring.kakfa.listener.concurency来设置Consumer的并发数;但spring.kakfa.listener.concurency是一个全局配置,当一个服务须要同时监听多个Topic,并且不同的Topic的Consumer须要设置不同的并发数时,这种办法就不实用2. 解决思路2.1 源码剖析 在Springboot我的项目中,个别通过办法上的@KafkaListener注解来注册Consumer,在Springboot服务启动过程中,通过实现了Springboot的扩大点的KafkaListenerAnnotationBeanPostProcessor类,在postProcessAfterInitialization办法中辨认含有@KafkaListener注解的办法,并注册至KafkaListenerEndpointRegistry中(具体的源码在此不开展形容,有趣味的能够自行翻阅源码或查问材料)。因而,后续的操作也将围绕着Listener容器MessageListenerContainer和注册表KafkaListenerEndpointRegistry开展。 2.2 动静启停Consumer Listener容器MessageListenerContainer接口扩大了SmartLifecycle接口,在Lifecycle接口的start()办法根底上,扩大了pause()办法和resume()办法。通过正文能够晓得,这三个办法别离对应了Listener的启动、暂停和复原。 在KafkaListenerEndpointRegistry类中,提供了依据ID获取MessageListenerContainer的办法。 因而,只有通过ID在KafkaListenerEndpointRegistry中获取了Listener容器MessageListenerContainer后,即可进行对应的开始、暂停和复原Consumer的操作。 2.3 动静批改参数 要想为不同的Listener配置不同的concurrency参数,首先得晓得concurrency参数是在哪里被设置至Listener中的。通过Debug剖析源码可知,在实现了MessageListenerContainer接口的ConcurrentMessageListenerContainer类中有一个setConcurrency(int)办法,能够设置容器的并发数。同时,Listener的注册表KafkaListenerEndpointRegistry类同样实现了SmartLifecycle接口,并在start()办法中理论启动Listener容器,因而想要动静批改参数,必须在容器启动前,即KafkaListenerEndpointRegistry执行start()办法前进行解决。 3. 动静启停Consumer 首先,定义一个公共的抽象类AbstractScheduledConsumer。 public abstract class AbstractScheduledConsumer<T> { @Resource private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; public abstract void onMessage(T data); protected abstract String getId(); protected MessageListenerContainer getListenerContainer() { String containerId = this.getId(); MessageListenerContainer container = this.kafkaListenerEndpointRegistry.getListenerContainer(containerId); Assert.notNull(container, String.format("MessageListenerContainer [%s] 获取失败", containerId)); return container; } /** * 启动 */ public void start() { MessageListenerContainer container = getListenerContainer(); if (!container.isRunning()) { container.start(); } else { container.resume(); } } /** * 暂停 */ public void pause() { getListenerContainer().pause(); } /** * 复原 */ public void resume() { getListenerContainer().resume(); }} 业务解决的Consumer类只须要继承AbstractScheduledConsumer类即可实现Consumer的动静启停。变量ID即为Listener的ID,须要为每个Consumer定义不同的ID。 ...

September 4, 2023 · 3 min · jiezi

关于springboot:知识整理Springboot启动扩展点

SpringBoot启动扩大点整顿1. 前言 在Springboot服务启动阶段,Springboot提供了许多扩大点。在理论的业务开发过程中,局部非凡的业务需要须要再Springboot服务启动过程中动静的加载配置或者执行业务解决,特此将罕用的Springboot启动扩大点做一个简略的整顿。 2. 筹备阶段2.1 EnvironmentPostProcessor接口门路org.springframework.boot.env.EnvironmentPostProcessor官网阐明 容许在刷新应用程序上下文之前自定义应用程序的Environment须要在META-INF/spring.factories文件中定义Allows for customization of the application's {@link Environment} prior to the application context being refreshed. EnvironmentPostProcessor implementations have to be registered in {@code META-INF/spring.factories}, using the fully qualified name of this class as the key. 利用场景 能够加载自定义的配置文件并增加至Environment中 回调机会 代码示例public class DemoEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(@NonNull ConfigurableEnvironment environment, @NonNull SpringApplication application) { System.out.println(">>> 执行EnvironmentPostProcessor.postProcessEnvironment()办法"); }}失效形式 在META-INF/spring.factories文件中增加内容 org.springframework.boot.env.EnvironmentPostProcessor = com.example.demo.extension.DemoEnvironmentPostProcessor2.2 ApplicationContextInitializer接口门路org.springframework.context.ApplicationContextInitializer利用场景 Spring会在容器刷新之前调用此类的initialize办法,能够激活一些配置或者获取Enviroment进行一些业务解决。 ...

September 4, 2023 · 3 min · jiezi

关于springboot:SpringBoot-博客网站

SpringBoot 博客网站零碎性能登录注册 博客列表展现 搜寻 分类 集体核心 文章分类管理 我的文章治理 公布文章 开发环境和技术开发语言:Java应用框架: SpringBoot + jpa + H2 Spring Boot是一个用于构建Java应用程序的开源框架,它是Spring框架的一个扩大,旨在简化和减速Spring应用程序的开发过程。Spring Boot的次要指标是提供一种简化的形式来创立独立的、生产就绪的Spring应用程序,而无需太多的样板代码和配置。前端: thymeleaf数据库:H2 (内存数据库)H2数据库是一个轻量级的、嵌入式的、开源的关系型数据库管理系统(RDBMS),它齐全由Java编写,因而能够在各种平台上运行,包含Windows、Linux和macOS。架构:B/S源码类型: Web编译开发工具:Idea、Eclipse、MyEclipse (选其一)其余:jdk1.8性能图片展现 总结源码获取: 大家可点赞、珍藏、关注、评论、私信

September 1, 2023 · 1 min · jiezi

关于springboot:谁家面试往死里问-Swagger-啊

大家好,我是小富~ 前言说个挺奇葩的事,有个老铁给我发私信吐槽了一下它的面试经验,他去了个国企单位面试,而后面试官跟他就Swagger的问题聊了半个多小时。额~ 面试嘛这些都不稀奇,总能遇到是千奇百怪的人,千奇百怪的问题。不过,我剖析这个面试官是不太好意思间接让他走,哈哈哈! 什么是Swagger?Swagger目前是比拟支流的RESTful格调的API文档工具,做过开发的人应该都用过它吧! 它提供了一套工具和标准,让开发人员可能更轻松地创立和保护可读性强、易于应用和交互的API文档(官网口气)。 title: Swaggerdesc: Swagger 官方网站logo: https://static1.smartbear.co/swagger/media/assets/images/swagger_logo.svglink: https://swagger.io/为什么用Swagger?以往在没有这样的API文档工具,开发人员须要手动编写和保护性能API的文档。而且,因为API变更往往难以及时更新到文档中,这可能会给依赖文档的开发者带来困惑。 说几个Swagger的特点: 最重要的一点能够依据代码注解主动生成API文档,能生成的相对不手写,而且API文档与API定义会同步更新。它提供了一个可执行的Web界面,反对API在线测试,能够间接在界面上间接设置参数测试,不必额定的测试工具或插件。反对多种编程语言,Java、PHP、Python等语言都反对,喜爱什么语言构建API都行。总的来说,Swagger能够让咱们更多工夫在专一于编写代码(摸鱼),而不是破费额定精力来保护文档,实际出真知先跑个demo试试。 Swagger搭建maven 依赖目前应用的版本是Swagger3.0、Springboot 2.7.6,Swagger2.0与3.0依赖包名称的变动有些大,须要特地留神一下。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.6</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version></dependency>配置类首先咱们创立一个控制器TestController类,里边只有一个最简略的申请 /test。 @RestControllerpublic class TestController { @RequestMapping("/test") public String test(String name) { return name; }}接下来创立配置类SwaggerConfig,类标注@EnableSwagger2注解是要害,到这最简略的Swagger文档环境就搭建好了。 import org.springframework.context.annotation.Configuration;import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration@EnableSwagger2public class SwaggerConfig {}启动报错启动时可能会报如下的谬误,这是因为高版本的Springboot与Swagger版本应用的门路匹配策略抵触导致的。 Springfox应用的门路匹配规定为AntPathMatcher 的,而SpringBoot2.7.6应用的是PathPatternMatcher,两者抵触了。org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.24.jar:5.3.24] at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_341] at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) [spring-boot-2.7.6.jar:2.7.6] at com.springboot101.SwaggerApplication.main(SwaggerApplication.java:10) [classes/:na]解决方案这个谬误的解决办法比拟多,我整顿了四种解决此问题的计划,你看哪个更适合你。 ...

August 31, 2023 · 4 min · jiezi

关于springboot:Spring-Boot-集成-SpringSecurity-入门教程

Spring-Security 简介官网简介 Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements Spring 是一个十分风行和胜利的 Java 利用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 利用安全性的残缺解决方案。一般来说,Web 利用的安全性包含用户认证(Authentication)和用户受权(Authorization)两个局部。用户认证指的是验证某个用户是否为零碎中的非法主体,也就是说用户是否拜访该零碎。用户认证个别要求用户提供用户名和明码。零碎通过校验用户名和明码来实现认证过程。用户受权指的是验证某个用户是否有权限执行某个操作。在一个零碎中,不同用户所具备的权限是不同的。比方对一个文件来说,有的用户只能进行读取,而有的用户能够进行批改。一般来说,零碎会为不同的用户调配不同的角色,而每个角色则对应一系列的权限。 ...

August 29, 2023 · 1 min · jiezi

关于springboot:南生论坛私信话题热评话题分享功能实现2023年8月

更新了啥性能: 新增【私信】性能 反对搜寻全站用户,私信数量无限度反对发送文本/emoji/图片类型音讯反对新音讯提醒、草稿箱等罕用性能还有很多细节同学们自行体验性能: 话题新增“热评”和分享性能 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛新增话题模块实现第三方登录2023年7月

更新了啥性能: 新增【话题】模块,话题,让然分享更容易\~ 不同于“文章”,话题公布是不须要审核的,这是一个轻量级的交换页面,不会像“文章”那么正式。能够了解成劳动摸鱼、探讨技术、静止健身、交友相亲等【随便】吐槽交换的中央 性能: 减少第三方登录性能 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛新增积分系统签到系统分片上传2023年6月

更新了啥性能: 优化积分零碎 性能: 新增签到性能(签到会加南生值) 入口每日签到性能: 新增文件分片上传、秒传及断点续传的全局上传性能 反对分片上传(大文件间接上传不仅效率低而且特地大的文件还反对不了,故分片上传能够解决这样的问题)反对秒传(曾经上传过的文件间接显示上传胜利-返回下载地址,依据MD5判断是否是同一个文件)反对断点续传(首先会判断哪些分片曾经上传过,咱们持续上传剩下的分片即可)反对全局上传(上传文件的同时能够去其余页面解决事件,不会影响文件上传)反对多文件同时上传 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛收藏集我的足迹功能实现2023年5月

更新了啥性能: 新增我的脚印(文章浏览记录) 性能: 优化用户header展现(这样显得更业余) 性能: 新增珍藏集性能 珍藏文章 我的珍藏集 珍藏集详情 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛文章举报广告位消息通知功能实现2023年4月

更新了啥性能: 新增文章举报性能 性能: 新增广告位 性能: 优化音讯告诉能力 可能及时发现谁回复了你的文章/评论 可能及时通晓谁点赞了你的文章/评论 可能及时发现谁关注了你 可能及时看见作者公布的零碎告诉 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛文章增加使用标签2023年3月

更新了啥性能:  减少应用标签(用户撰写文章用到的所有标签) 性能:  优化管理员视图(审核) 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛代码块复制功能实现2023年2月

更新了啥性能:  实现代码块复制性能(兼容简直所有终端) 性能:  手机端展现优化、文章展现优化 限度非通过审核(待审核、审核回绝)的文章只能自己和超管查看(其他人404)找不到的文章不再报错,而是显示404页面优化手机端展现成果(根本曾经欠缺)我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛评论锁定过滤实现功能实现2022年12月

更新了啥性能: 锁定评论实现:http://76.nanshengbbs.top/video/comment-positioning.mp4 性能: 减少“最热”和“最新”评论过滤,默认展现最热评论 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛-管理员视角操作优化2022年11月

更新了啥性能:  管理员视角操作优化(首页) 性能:  管理员视角操作优化(标签) 性能:  管理员视角操作优化(资源) 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛用户动态文章目录高亮功能实现2022年10月

更新了啥性能:  减少用户动静记录 性能:  目录题目高亮以及定位锁定性能实现 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛实现找回密码功能2022年9月

更新了啥性能:  实现找回明码性能 绑定过手机 或者 绑定过邮箱的用户才能够找回哟 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:南生论坛文章审核功能实现2022年8月

更新了啥性能:  文章审核性能实现 我的项目官网http://bbs.nanshengbbs.top 我的项目架构 举荐理由简洁好看: 专为浏览设计的UI,蕴含一个论坛的必要性能,简洁而时尚,同时页面浏览有着极致体验。大厂设计: 架构设计先进正当,技术团队能够十分不便疾速的对接公司本人的数据和接口,以及减少新的功能模块。谋求极致: 作者会继续一直的更新南生论坛,内容会越来越丰盛,操作会越来越丝滑,谋求极致永不停歇。技术栈后端:\SpringBoot、Dubbo、ZooKeeper、RocketMQ、Redis、MyBatis、MySQL、MongoDB、Shiro、七牛云(图片/视频全副存于此)、…前端:\Vue、Axios、Vue Router、Ant Design of Vue、Webpack、Less、Vuex、ES6、Node.js、mavonEditor、ECharts、…我的项目源码后端源码(github)前端源码(github) 后端源码(github)前端源码(github) 性能用户零碎-性能结构图管理系统-性能结构图

August 28, 2023 · 1 min · jiezi

关于springboot:Spring-Boot-版本2023年选择指南

目前 Spring Boot 框架的版本次要有以下三个系列可抉择(截至到2023年8月28日): 3.1.x系列(以后最新为3.1.3)3.0.x系列(以后最新为3.0.10)2.7.x系列(以后最新为2.7.15)那么以上三个系列该如何抉择呢? 咱们先来看看每个系列的差异有哪些。 1. 技术支持时长 能够看到,2.7.x系列的官网技术支持截止到2023-11-18,3.0.x系列截止到2023-11-24,3.2.x系列截止到2024-11-23。 2. 零碎要求Spring Boot 2.7.x requires Java 8 and is compatible up to and including Java 20. Spring Framework 5.3.29 or above is also required. Explicit build support is provided for the following build tools: Build ToolVersionMaven3.5+Gradle6.8.x, 6.9.x, 7.x, and 8.xSpring Boot 3.0.x requires Java 17 and is compatible up to and including Java 20. Spring Framework 6.0.11 or above is also required. ...

August 28, 2023 · 1 min · jiezi

关于springboot:SpringBootVue3Element-Plus-打造分布式存储系统完结

download:SpringBoot+Vue3+Element Plus 打造分布式存储系统整数类型是一种基本的数据类型,它可能示意没有小数部分的数值,如 0, 1, -2, 100 等。在 C 语言中,有多种整数类型,它们的大小和范畴取决于编译器和平台。为了帮助你学习整数类型的概念和用法,我为你筹备了一篇示例文章,它将向你介绍以下内容: 整数类型的分类和个性整数类型的申明和赋值整数类型的运算和转换整数类型的输出和输入上面是示例文章的内容: // 整数类型讲解的示例文章// 本文将向你介绍 C 语言中的整数类型,包含它们的分类、个性、申明、赋值、运算、转换、输出和输入等。// 首先,咱们需要使用 #include 指令来引用标准输入输出库 stdio.h,它蕴含了许多罕用的函数,如 printf 和 scanf 等。 include <stdio.h>// 而后,咱们需要使用 int 关键字来定义 main 函数,它是程序的入口点,也就是程序开始执行的地方。// main 函数必须有一个 int 类型的返回值,示意程序的执行状态。// main 函数也可能有一个 char 类型的指针数组参数,表示命令行参数。int main(int argc, char *argv[]){ // 接下来,咱们可能在 main 函数中编写咱们想要执行的代码。// 首先,咱们来了解一下 C 语言中有哪些整数类型。// 在 C 语言中,有以下几种整数类型:// char:字符型,占用 1 个字节(8 位),可能示意 -128 到 127 的整数,也可能示意 ASCII 码对应的字符。// short:短整型,占用 2 个字节(16 位),可能示意 -32768 到 32767 的整数。// int:整型,占用 4 个字节(32 位),可能示意 -2147483648 到 2147483647 的整数。// long:长整型,占用 4 或 8 个字节(32 或 64 位),取决于编译器和平台,可能示意 -2147483648 到 2147483647 或 -9223372036854775808 到 9223372036854775807 的整数。// long long:长长整型,占用 8 个字节(64 位),可能示意 -9223372036854775808 到 9223372036854775807 的整数。// 这些整数类型都可能在后面加上 unsigned 关键字来示意无符号的整数,即不分别正负号,只能示意非负的整数。// unsigned 关键字会使整数类型的范畴翻倍,例如:// unsigned char:无符号字符型,占用 1 个字节(8 位),可能示意 0 到 255 的整数。// unsigned short:无符号短整型,占用 2 个字节(16 位),可能示意 0 到 65535 的整数。// unsigned int:无符号整型,占用 4 个字节(32 位),可能示意 0 到 4294967295 的整数。// unsigned long:无符号长整型,占用 4 或 8 个字节(32 或 64 位),取决于编译器和平台,可能示意// 0 到// $$4294967295$$// 或// $$18446744073709551615$$// 的整数。// unsigned long long:无符号长长整型,占用 8 个字节(64 位),可能示意// 0 到// $$18446744073709551615$$// 的整数。// 而后,咱们来看一下如何申明和赋值整数类型的变量。// 申明整数类型的变量的语法是:// 类型 变量名;// 例如:char a; // 申明一个 char 类型的变量 ashort b; // 申明一个 short 类型的变量 bint c; // 申明一个 int 类型的变量 clong d; // 申明一个 long 类型的变量 dlong long e; // 申明一个 long long 类型的变量 eunsigned char f; // 申明一个 unsigned char 类型的变量 funsigned short g; // 申明一个 unsigned short 类型的变量 gunsigned int h; // 申明一个 unsigned int 类型的变量 hunsigned long i; // 申明一个 unsigned long 类型的变量 iunsigned long long j; // 申明一个 unsigned long long 类型的变量 j// 赋值整数类型的变量的语法是:// 变量名 = 表达式;// 例如:a = 65; // 给变量 a 赋值为 65,相当于字符 'A'b = -100; // 给变量 b 赋值为 -100c = 1000; // 给变量 c 赋值为 1000d = 1000000L; // 给变量 d 赋值为 1000000,注意要加上 L 后缀示意长整数e = 1000000000000LL; // 给变量 e 赋值为 1000000000000,注意要加上 LL 后缀示意长长整数f = 255; // 给变量 f 赋值为 255,相当于字符 '\377'g = 65535; // 给变量 g 赋值为 65535h = 4294967295U; // 给变量 h 赋值为 4294967295,注意要加上 U 后缀示意无符号整数i = 4294967295UL; // 给变量 i 赋值为 4294967295,注意要加上 UL 后缀示意无符号长整数j = 18446744073709551615ULL; // 给变量 j 赋值为 18446744073709551615,注意要加上 ULL 后缀示意无符号长长整数// 接着,咱们来看一下如何对整数类型的变量进行运算和转换。// 对整数类型的变量可能进行以下几种运算:// 算术运算:+ - * / % ++ --// 比较运算:== != > < >= <=// 逻辑运算:&& || !// 位运算:& | ^ ~ << >>// 赋值运算:= += -= *= /= %= &= |= ^= <<= >>=// 条件运算:? :// 逗号运算:,

August 27, 2023 · 2 min · jiezi

关于springboot:关于SpringBoot的示例代码文章

对于SpringBoot的示例代码文章须要有明确的段落构造。一般来说,一篇文章能够分为以下几个局部: 引言:介绍文章的主题和目标,概述SpringBoot的特点和劣势,吸引读者的注意力。注释:分几个大节,别离介绍SpringBoot的不同方面或性能,给出相应的示例代码和解释,展现SpringBoot的用法和成果。论断:总结文章的次要内容和观点,强调SpringBoot的价值和意义,给出一些倡议或瞻望。为了让你更好地了解如何写篇有对于SpringBoot的示例代码文章,我为你生成了一个简略的文章纲要,你能够参考并批改: SpringBoot入门教程引言在Java开发畛域,Spring框架是一个十分风行和弱小的框架,它提供了很多性能和组件,能够帮忙开发者疾速构建高质量的应用程序。然而,在应用Spring框架时,也会遇到一些问题,比方配置简单、依赖冗余、启动慢等。为了解决这些问题,Spring团队推出了一个基于Spring框架的开发工具——SpringBoot。 SpringBoot是一个用于创立独立运行的生产级Java应用程序的工具。它能够让开发者不必写大量的配置文件和代码,只需大量或无需配置就能够疾速启动一个应用程序。它还提供了很多便当的性能和组件,比方嵌入式服务器、主动配置、热部署、监控等。应用SpringBoot能够让开发者更专一于业务逻辑,进步开发效率和品质。 本文将介绍如何应用SpringBoot进行Java开发,并给出一些示例代码,心愿可能帮忙初学者疾速上手和把握SpringBoot的根本用法。 注释创立和运行SpringBoot我的项目要创立一个SpringBoot我的项目,有多种形式,比方应用命令行工具、IDE插件、在线工具等。本文将应用Spring官网提供的一个在线工具——[Spring Initializr]。它能够让开发者通过简略的几步,就能够生成一个根本的SpringBoot我的项目。 首先,关上[Spring Initializr]的网站,抉择我的项目的一些根本信息,比方我的项目类型、语言、版本、名称、包名等。而后,抉择我的项目须要的依赖,比方Web、JPA、MySQL等。最初,点击Generate按钮,就能够下载一个ZIP文件,解压后就是一个SpringBoot我的项目。 要运行一个SpringBoot我的项目,也有多种形式,比方应用命令行工具、IDE工具等。本文将应用IDEA这个IDE工具来运行我的项目。首先,关上IDEA,抉择Import Project,找到方才解压的我的项目文件夹,抉择Open。而后,期待IDEA加载和解析我的项目,实现后,在左侧的Project视图中找到我的项目的主类(个别是以Application结尾的类),右键点击,抉择Run或Debug。就能够看到控制台输入一些日志信息,并显示我的项目启动胜利。 编写和测试REST接口在SpringBoot我的项目中,要编写一个REST接口,只需创立一个类,并应用@RestController注解标记。而后,在类中定义一些办法,并应用@RequestMapping注解指定申请门路和办法。在办法中,能够应用@RequestParam注解获取申请参数,并返回一个对象或字符串作为响应后果。SpringBoot会主动将对象转换为JSON格局,并设置响应头和状态码。 例如,上面的代码定义了一个简略的REST接口,用于解决用户相干的申请: @RestController@RequestMapping("/user")public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public User getUserById(@PathVariable Long id) { return userService.getUserById(id); } @PostMapping public User createUser(@RequestBody User user) { return userService.createUser(user); } @PutMapping("/{id}") public User updateUser(@PathVariable Long id, @RequestBody User user) { return userService.updateUser(id, user); } @DeleteMapping("/{id}") public void deleteUser(@PathVariable Long id) { userService.deleteUser(id); }}要测试一个REST接口,有多种形式,比方应用浏览器、Postman、curl等。本文将应用Postman这个工具来测试接口。首先,关上Postman,创立一个新的申请,并抉择申请办法和门路。而后,在Headers选项卡中设置申请头,比方Content-Type、Accept等。在Body选项卡中设置申请体,比方JSON格局的数据。最初,点击Send按钮,就能够发送申请,并查看响应后果。 例如,上面的截图展现了应用Postman测试创立用户接口的过程: ![postman] 配置和应用数据库在SpringBoot我的项目中,要配置和应用数据库,只需增加相应的依赖和配置文件即可。SpringBoot会主动加载并初始化数据库连接池、数据源、事务管理器等组件,并提供一些简便的操作数据库的形式。 例如,在pom.xml文件中增加以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency>在application.properties文件中增加以下配置: ...

August 27, 2023 · 1 min · jiezi

关于springboot:聊聊springboot的启动事件

序本文次要钻研一下springboot的启动事件 SpringApplicationEventorg/springframework/boot/context/event/SpringApplicationEvent.java public abstract class SpringApplicationEvent extends ApplicationEvent { private final String[] args; public SpringApplicationEvent(SpringApplication application, String[] args) { super(application); this.args = args; } public SpringApplication getSpringApplication() { return (SpringApplication) getSource(); } public final String[] getArgs() { return this.args; }}SpringApplicationEvent继承了ApplicationEvent,它有几个子类分表是ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent,期间有异样则抛出ApplicationFailedEventSpringApplication.runorg/springframework/boot/SpringApplication.java public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }SpringApplication的run办法,先触发listeners.starting(),而后执行了prepareEnvironment,之后createApplicationContext,再进行prepareContext和refreshContext,最初触发listeners.started(context),之后执行callRunners,最初触发listeners.running(context),如有异样则会执行handleRunFailureprepareEnvironment private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }prepareEnvironment会触发listeners.environmentPrepared(environment),即公布ApplicationEnvironmentPreparedEventprepareContext private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // 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); }prepareContext会触发listeners.contextPrepared(context),即公布ApplicationContextInitializedEvent,执行实现之后触发listeners.contextLoaded(context),即公布ApplicationPreparedEventrefreshContext private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } } protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); } refreshContext会执行refresh办法org/springframework/context/support/AbstractApplicationContext.java ...

August 25, 2023 · 3 min · jiezi

关于springboot:聊聊springboot的EnvironmentPostProcessor

序本文次要钻研一下springboot的EnvironmentPostProcessor EnvironmentPostProcessororg/springframework/boot/env/EnvironmentPostProcessor.java @FunctionalInterfacepublic interface EnvironmentPostProcessor { /** * Post-process the given {@code environment}. * @param environment the environment to post-process * @param application the application to which the environment belongs */ void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);}springboot提供了EnvironmentPostProcessor接口,该接口有postProcessEnvironment办法,其中envrionment参数类型为ConfigurableEnvironment,即利用能够通过实现这个接口进行env环境变量的操作EnvironmentPostProcessorApplicationListenerorg/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java /** * {@link SmartApplicationListener} used to trigger {@link EnvironmentPostProcessor * EnvironmentPostProcessors} registered in the {@code spring.factories} file. * * @author Phillip Webb * @since 2.4.0 */public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered { /** * The default order for the processor. */ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; private final DeferredLogs deferredLogs; private int order = DEFAULT_ORDER; private final EnvironmentPostProcessorsFactory postProcessorsFactory; /** * Create a new {@link EnvironmentPostProcessorApplicationListener} with * {@link EnvironmentPostProcessor} classes loaded via {@code spring.factories}. */ public EnvironmentPostProcessorApplicationListener() { this(EnvironmentPostProcessorsFactory .fromSpringFactories(EnvironmentPostProcessorApplicationListener.class.getClassLoader())); } /** * Create a new {@link EnvironmentPostProcessorApplicationListener} with post * processors created by the given factory. * @param postProcessorsFactory the post processors factory */ public EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory) { this(postProcessorsFactory, new DeferredLogs()); } EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory, DeferredLogs deferredLogs) { this.postProcessorsFactory = postProcessorsFactory; this.deferredLogs = deferredLogs; } @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType) || ApplicationFailedEvent.class.isAssignableFrom(eventType); } @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); } if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent((ApplicationPreparedEvent) event); } if (event instanceof ApplicationFailedEvent) { onApplicationFailedEvent((ApplicationFailedEvent) event); } } private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) { ConfigurableEnvironment environment = event.getEnvironment(); SpringApplication application = event.getSpringApplication(); for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(event.getBootstrapContext())) { postProcessor.postProcessEnvironment(environment, application); } } private void onApplicationPreparedEvent(ApplicationPreparedEvent event) { finish(); } private void onApplicationFailedEvent(ApplicationFailedEvent event) { finish(); } private void finish() { this.deferredLogs.switchOverAll(); } List<EnvironmentPostProcessor> getEnvironmentPostProcessors(ConfigurableBootstrapContext bootstrapContext) { return this.postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs, bootstrapContext); } @Override public int getOrder() { return this.order; } public void setOrder(int order) { this.order = order; }}EnvironmentPostProcessorApplicationListener用于在接管到ApplicationEnvironmentPreparedEvent事件时触发执行EnvironmentPostProcessor的postProcessEnvironment办法# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.ClearCachesApplicationListener,\org.springframework.boot.builder.ParentContextCloserApplicationListener,\org.springframework.boot.context.FileEncodingApplicationListener,\org.springframework.boot.context.config.AnsiOutputApplicationListener,\org.springframework.boot.context.config.DelegatingApplicationListener,\org.springframework.boot.context.logging.LoggingApplicationListener,\org.springframework.boot.env.EnvironmentPostProcessorApplicationListener,\org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener示例public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { Resource path = new ClassPathResource("com/example/myapp/config.yml"); PropertySource<?> propertySource = loadYaml(path); environment.getPropertySources().addLast(propertySource); } private PropertySource<?> loadYaml(Resource path) { if (!path.exists()) { throw new IllegalArgumentException("Resource " + path + " does not exist"); } try { return this.loader.load("custom-resource", path).get(0); } catch (IOException ex) { throw new IllegalStateException("Failed to load yaml configuration from " + path, ex); } }}EnvironmentPostProcessorExample实现了postProcessEnvironment办法,它额定加载com/example/myapp/config.yml外头的配置最为最初的propertySource小结springboot的EnvironmentPostProcessor提供了一个environment的扩大接口,不便利用去做environment的扩大,比方扩大propertySource等 ...

August 24, 2023 · 2 min · jiezi

关于springboot:聊聊springboot的Customizer

序本文次要钻研一下springboot的Customizer TaskExecutorCustomizer@FunctionalInterfacepublic interface TaskExecutorCustomizer { /** * Callback to customize a {@link ThreadPoolTaskExecutor} instance. * @param taskExecutor the task executor to customize */ void customize(ThreadPoolTaskExecutor taskExecutor);}之后再结构的时候通过ObjectProvider获取即可 @Bean @ConditionalOnMissingBean public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) { TaskExecutionProperties.Pool pool = properties.getPool(); TaskExecutorBuilder builder = new TaskExecutorBuilder(); builder = builder.queueCapacity(pool.getQueueCapacity()); builder = builder.corePoolSize(pool.getCoreSize()); builder = builder.maxPoolSize(pool.getMaxSize()); builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()); builder = builder.keepAlive(pool.getKeepAlive()); Shutdown shutdown = properties.getShutdown(); builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator); builder = builder.taskDecorator(taskDecorator.getIfUnique()); return builder; } /** * Set the {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be * applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order * that they were added after builder configuration has been applied. Setting this * value will replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(TaskExecutorCustomizer...) */ public TaskExecutorBuilder customizers(TaskExecutorCustomizer... customizers) { Assert.notNull(customizers, "Customizers must not be null"); return customizers(Arrays.asList(customizers)); } TaskSchedulerCustomizer@FunctionalInterfacepublic interface TaskSchedulerCustomizer { /** * Callback to customize a {@link ThreadPoolTaskScheduler} instance. * @param taskScheduler the task scheduler to customize */ void customize(ThreadPoolTaskScheduler taskScheduler);} @Bean @ConditionalOnMissingBean public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) { TaskSchedulerBuilder builder = new TaskSchedulerBuilder(); builder = builder.poolSize(properties.getPool().getSize()); Shutdown shutdown = properties.getShutdown(); builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); builder = builder.customizers(taskSchedulerCustomizers); return builder; } /** * Set the {@link TaskSchedulerCustomizer TaskSchedulerCustomizers} that should be * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the * order that they were added after builder configuration has been applied. Setting * this value will replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(TaskSchedulerCustomizer...) */ public TaskSchedulerBuilder customizers(TaskSchedulerCustomizer... customizers) { Assert.notNull(customizers, "Customizers must not be null"); return customizers(Arrays.asList(customizers)); } RestTemplateCustomizer@FunctionalInterfacepublic interface RestTemplateCustomizer { /** * Callback to customize a {@link RestTemplate} instance. * @param restTemplate the template to customize */ void customize(RestTemplate restTemplate);} @Bean @Lazy @ConditionalOnMissingBean public RestTemplateBuilderConfigurer restTemplateBuilderConfigurer( ObjectProvider<HttpMessageConverters> messageConverters, ObjectProvider<RestTemplateCustomizer> restTemplateCustomizers, ObjectProvider<RestTemplateRequestCustomizer<?>> restTemplateRequestCustomizers) { RestTemplateBuilderConfigurer configurer = new RestTemplateBuilderConfigurer(); configurer.setHttpMessageConverters(messageConverters.getIfUnique()); configurer.setRestTemplateCustomizers(restTemplateCustomizers.orderedStream().collect(Collectors.toList())); configurer.setRestTemplateRequestCustomizers( restTemplateRequestCustomizers.orderedStream().collect(Collectors.toList())); return configurer; }小结springboot提供了很多Customizer接口不便用户自行扩大,十分值得设计组件的时候应用 ...

August 22, 2023 · 2 min · jiezi

关于springboot:聊聊TaskExecutorMetricsAutoConfiguration

序springboot2.6.0版本提供了TaskExecutorMetricsAutoConfiguration,能够主动给线程池加上metrics TaskExecutorMetricsAutoConfigurationspring-boot-actuator-autoconfigure-2.7.14-sources.jar!/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfiguration.java /** * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available * {@link ThreadPoolTaskExecutor task executors} and {@link ThreadPoolTaskScheduler task * schedulers}. * * @author Stephane Nicoll * @author Scott Frederick * @since 2.6.0 */@AutoConfiguration(after = { MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class, TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class })@ConditionalOnClass(ExecutorServiceMetrics.class)@ConditionalOnBean({ Executor.class, MeterRegistry.class })public class TaskExecutorMetricsAutoConfiguration { @Autowired public void bindTaskExecutorsToRegistry(Map<String, Executor> executors, MeterRegistry registry) { executors.forEach((beanName, executor) -> { if (executor instanceof ThreadPoolTaskExecutor) { monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskExecutor) executor), beanName); } else if (executor instanceof ThreadPoolTaskScheduler) { monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskScheduler) executor), beanName); } }); } private void monitor(MeterRegistry registry, ThreadPoolExecutor threadPoolExecutor, String name) { if (threadPoolExecutor != null) { new ExecutorServiceMetrics(threadPoolExecutor, name, Collections.emptyList()).bindTo(registry); } } private ThreadPoolExecutor safeGetThreadPoolExecutor(ThreadPoolTaskExecutor taskExecutor) { try { return taskExecutor.getThreadPoolExecutor(); } catch (IllegalStateException ex) { return null; } } private ThreadPoolExecutor safeGetThreadPoolExecutor(ThreadPoolTaskScheduler taskScheduler) { try { return taskScheduler.getScheduledThreadPoolExecutor(); } catch (IllegalStateException ex) { return null; } }}这里会遍历executors,而后挨个执行monitor办法,而monitor办法则是创立ExecutorServiceMetrics而后绑定到meterRegistryExecutorServiceMetricsmicrometer-core-1.9.13-sources.jar!/io/micrometer/core/instrument/binder/jvm/ExecutorServiceMetrics.java ...

August 21, 2023 · 3 min · jiezi

关于springboot:SpringBoot3集成Kafka

标签:Kafka3.Kafka-eagle3;一、简介Kafka是一个开源的分布式事件流平台,常被用于高性能数据管道、流剖析、数据集成和要害工作利用,基于Zookeeper协调的解决平台,也是一种音讯零碎,具备更好的吞吐量、内置分区、复制和容错,这使得它成为大规模音讯解决应用程序的一个很好的解决方案; 二、环境搭建1、Kafka部署1、下载安装包:kafka_2.13-3.5.0.tgz2、配置环境变量open -e ~/.bash_profileexport KAFKA_HOME=/本地门路/kafka3.5export PATH=$PATH:$KAFKA_HOME/binsource ~/.bash_profile3、该目录【kafka3.5/bin】启动zookeeperzookeeper-server-start.sh ../config/zookeeper.properties4、该目录【kafka3.5/bin】启动kafkakafka-server-start.sh ../config/server.properties2、Kafka测试1、生产者kafka-console-producer.sh --broker-list localhost:9092 --topic test-topic>id-1-message>id-2-message2、消费者kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topicid-1-messageid-2-message3、查看topic列表kafka-topics.sh --bootstrap-server localhost:9092 --listtest-topic4、查看音讯列表kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning --partition 0id-1-messageid-2-message3、可视化工具配置和部署 1、下载安装包:kafka-eagle-bin-3.0.2.tar.gz2、配置环境变量open -e ~/.bash_profileexport KE_HOME=/本地门路/efak-web-3.0.2export PATH=$PATH:$KE_HOME/binsource ~/.bash_profile3、批改配置文件:system-config.propertiesefak.zk.cluster.alias=cluster1cluster1.zk.list=localhost:2181efak.url=jdbc:mysql://127.0.0.1:3306/kafka-eagle4、本地新建数据库:kafka-eagle,留神用户名和明码是否统一5、启动命令efak-web-3.0.2/bin/ke.sh start命令语法: ./ke.sh {start|stop|restart|status|stats|find|gc|jdk|version|sdate|cluster}6、本地拜访【localhost:8048】 username:admin password:123456 KSQL语句测试 select * from `test-topic` where `partition` in (0) order by `date` desc limit 5 select * from `test-topic` where `partition` in (0) and msg like '%5%' order by `date` desc limit 3 ...

August 18, 2023 · 1 min · jiezi

关于springboot:springboot-war包部署

利用在共有云上的时候是打成fatjar, 通过内嵌tomcat启动的. 在公有云上须要部署在一个过程中, 通过打成war包托管给tomcat启动. 1. 代码首先, Application启动类须要继承SpringBootServletInitializer并重写configure办法, sources的入参为Application.class. 2. pom<packaging>${project.packaging}</packaging><profiles> <profile> <id>jar</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <project.packaging>jar</project.packaging> </properties> </profile> <profile> <id>war</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.2.0</version> </plugin> </plugins> </build> <properties> <project.packaging>war</project.packaging> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies> </profile></profiles>在pom文件中通过profile管制打包行为, -Pwar时打成war包. 3. tomcattomcat10因为servlet被募捐后包名改成了jakarta, 须要升版本和批改依赖, 改变有点大, 因而抉择tomcat9, 或者tomcat8. 4. context留神war包名字批改为了ROOT, 默认状况下, 如果不是ROOT, 那么url会带上该名字作为context进行路由, 例如本来的地址为http://127.0.0.1:8080/test, 会变成http://127.0.0.1:8080/app/test. 如果带上context, 一些动态资源因为是绝对路径会找不到, 一些filter门路匹配也须要批改, 改变较大, 因而去除context躲避这些问题. tomcat也反对通过批改conf/server.xml来去除context, 这里简略起见采纳了重命名为ROOT的形式.如果利用没有提供http服务, 或者应用的是相对路径, 配置上也通过*进行门路匹配, 那么就不须要重命名. ...

August 16, 2023 · 1 min · jiezi

关于springboot:SpringBoot3集成ElasticSearch

标签:ElasticSearch8.Kibana8;一、简介Elasticsearch是一个分布式、RESTful格调的搜寻和数据分析引擎,实用于各种数据类型,数字、文本、地理位置、结构化数据、非结构化数据; 在理论的工作中,历经过Elasticsearch从6.0到7.0的版本升级,而这次SpringBoot3和ES8.0的集成,尽管脚本的语法变动很小,然而Java客户端的API语法变化很大; 二、环境搭建1、下载安装包须要留神的是,这些安装包的版本要抉择对应的,不然容易出问题; 软件包:elasticsearch-8.8.2-darwin-x86_64.tar.gz分词器工具:elasticsearch-analysis-ik-8.8.2.zip可视化工具:kibana-8.8.2-darwin-x86_64.tar.gz2、服务启动不论是ES还是Kibana,在首次启动后,会初始化很多配置文件,能够依据本人的须要做相干的配置调整,比方常见的端口调整,资源占用,平安校验等; 1、启动ESelasticsearch-8.8.2/bin/elasticsearch本地拜访:localhost:92002、启动Kibanakibana-8.8.2/bin/kibana本地拜访:http://localhost:5601# 3、查看装置的插件http://localhost:9200/_cat/plugins -> analysis-ik 8.8.2三、工程搭建1、工程构造 2、依赖治理在starter-elasticsearch组件中,实际上依赖的是elasticsearch-java组件的8.7.1版本; <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> <version>${spring-boot.version}</version></dependency>3、配置文件在下面环境搭建的过程中,曾经禁用了用户和明码的登录验证,配置ES服务地址即可; spring: # ElasticSearch配置 elasticsearch: uris: localhost:9200四、根底用法1、实体类通过Document和Field注解形容ES索引构造的实体类,留神这里JsonIgnoreProperties注解,解决索引中字段和实体类非一一对应的而引起的JSON解析问题; @JsonIgnoreProperties(ignoreUnknown = true)@Document(indexName = "contents_index", createIndex = false)public class ContentsIndex implements Serializable { private static final long serialVersionUID=1L; @Field(type= FieldType.Integer) private Integer id; @Field(type= FieldType.Keyword) private String title; @Field(type= FieldType.Keyword) private String intro; @Field(type= FieldType.Text) private String content; @Field(type= FieldType.Integer) private Integer createId; @Field(type= FieldType.Keyword) private String createName; @Field(type= FieldType.Date,format = DateFormat.date_hour_minute_second) private Date createTime;}2、初始化索引基于ElasticsearchTemplate类和上述实体类,实现索引构造的初始化,并且将tb_contents表中的数据同步到索引中,最初通过ID查问一条测试数据; ...

August 16, 2023 · 3 min · jiezi

关于springboot:SpringBoot-快速获取-IP-地址及归属地

大家好,我是 Java陈序员。咱们在刷抖音、B站的时候看评论的时候,发现会显示网络用户所在地。国内的用户显示的是省份,国外的用户显示是国家。公开显示网络用户所在地能够揭示用户审慎发言、治理水军、缩小假冒当事人等景象。 那么,这个性能是怎么实现的呢? Java 中获取 IP 归属地,次要是分为以下两步: 通过 HttpServletRequest 获取 Ip依据 IP 查问获取对应的归属地HttpServletRequest 获取 IP写一个工具类封装获取 IP public class IpUtil { private static final String UNKNOWN = "unknown"; private static final String HEADER_FORWARDED = "x-forwarded-for"; private static final String HEADER_PROXY = "Proxy-Client-IP"; private static final String HEADER_WL_PROXY = "WL-Proxy-Client-IP"; private static final String HEADER_HTTP = "HTTP_CLIENT_IP"; private static final String HEADER_HTTP_FORWARDED = "HTTP_X_FORWARDED_FOR"; private static final String LOCAL_IP = "127.0.0.1"; private static final String LOCAL_HOST = "localhost"; /** * 获取 IP 地址 * * @param request * @return */ public String getIpAddr(HttpServletRequest request) { String ip = request.getHeader(HEADER_FORWARDED); if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_PROXY); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_WL_PROXY); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_HTTP); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_HTTP_FORWARDED); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } // 本机拜访 if (LOCAL_IP.equalsIgnoreCase(ip) || LOCAL_HOST.equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) { // 依据网卡取本机配置的 IP try { InetAddress localHost = InetAddress.getLocalHost(); ip = localHost.getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } } // 对于通过多个代理的状况,第一个 IP 为客户端实在 IP,多个 IP 依照','宰割 if (ip != null && ip.length() > 15) { if (ip.indexOf(",") > 15) { ip = ip.substring(0, ip.indexOf(",")); } } return ip; }}Ip2region简介一个离线 IP 数据管理框架和定位库,反对亿级别的数据段,10 微秒级别的查问性能,提供了许多支流编程语言的 xdb 数据管理引擎的实现。Github 地址: ...

July 12, 2023 · 3 min · jiezi

关于springboot:IoTOSv121接入JIMtio后台通知App

IoTOS v1.2.1 一、登录页减少可批改轮播     登录页减少可批改数据轮播:首页轮播图由背景图片、题目、介绍、按钮一、按钮二(可配置跳转地址打开方式)组合而成二、登录页减少罕用运营商平台&对于-IoTOS链接    登录页减少国内罕用运营商平台网站、国内平台运营商网站、对于-IoTOS链接:中国移动- oneLink [https://ec.iot.10086.cn/] (中国移动物联卡服务平台)- oneNet [https://open.iot.10086.cn/] (中国移动物联网开放平台)- 能力开放平台 [https://api.iot.10086.cn/] (挪动物联卡能力开放平台)- 大数据 [https://iot.bigdata.10086.cn/app/] (OneLink&有方大数据)中国电信- ctwing [http://www.ctwing.cn/] (天翼物联网CTWing门户网站)- 5G-CMP [https://cmp.ctwing.cn:4821/] 物联网-5G连贯治理平台)- 4G-CMP [https://www.ct10649.com/#/] (开放平台-连贯管理子系统)- 国内业务-DCP [https://global.ct10649.com] (寰球连贯管理子系统)中国联通- 雁飞·智连-CMP [https://cmp.10646.cn/] (雁飞·智连CMP平台)- 凋谢能力平台 [https://gw.10646.cn/views/abilityIndex/abilityIndex/abilityIn...] (能力开放平台)- IOT Connect [https://sso.10646.cn/] (IOT Connect)国内平台- SMART [https://www.smart.com.kh/zh/] (菲律宾最大挪动运营商)- GLOBE [https://www.globe.com.ph/] (菲律宾的次要电信公司之一)- HTK [https://www.hktchina.com/] (香港名列前茅的电讯服务商)- SITECORE [https://www.sitecore.com/zh-cn] (台湾最大电信服务商)- SCT [https://www.south.com.hk/] (SCT北方电信(香港))三、登录页增平台能力、凋谢协定、系列产品阐明       登录页减少平台能力阐明、凋谢协定阐明、系列产品阐明:平台能力-   后盾提供PC端操作,挪动端采纳 uni-app 开发反对多端打包上架 编写一套代码,可公布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快利用等多平台-   提供多家运营商接口对接(蕴含罕用国内运营商接入),灵便的套餐包包装;后续可供反对套餐及时充值到账多上游套餐包装等;-    以高效、强壮、灵便设计 SaaS、多语言、机器人推送、自动化治理、数据同步多类型算法为次要业务 拿来即用开放式协定- 二次开发可商用,可衍生作品;商业和非商业环境中自在应用、批改和散发开源软件,同时爱护了软件的作者和贡献者的权利。它激励凋谢单干和共享翻新,促成了开源软件社区的凋敝倒退(收费商用、二次开发)系列产品- IoTOS [https://gitee.com/chinaiot/iotos] 综合后盾治理- IoTOS-App [https://gitee.com/chinaiot/iotos-app] 挪动端应用- IoTOS-IM [https://gitee.com/chinaiot/iotos-im] 综合音讯解决网络架构四、减少登录告诉     减少适配挪动端系统告诉登录后通过IoTOS-IM下发布告告诉:在后盾零碎减少零碎告诉会在用户登录挪动端后下发音讯到指定用户四、新增开源我的项目 IoTOS-IM    新增开源我的项目IoTOS-IM [https://gitee.com/chinaiot/iotos-im]END ...

July 9, 2023 · 1 min · jiezi

关于springboot:一键搞定发布自己Jar到Maven中央仓库

做java 开发那当然离不开jar包治理, 不知何时始终想想封装一个本人的jar包而后公布到maven地方仓库给他人应用。 hhh 我感觉本人写一个jar包工具而后,被很多人应用是一件很牛,很高兴事件。终于有了这个机会,和工夫。SpringBoot stater进去了 基于场景启动器你能够轻松定义本人的stater组件,而后甚至,能够公布到maven仓库。供大家应用。 我总结,写了一个作为我工作多年程序员,本人工具类库,stater。 Github地址 基于它,你能够轻松开发SpringBoot WEB API,提高效率。不在去关怀一些繁琐。反复工作,而是把重点聚焦到业务。 回到正题,这篇文章基于我这个,stater讲一下。如何把本人定义stater 公布到maven地方仓库。 注册 sonatype账号进入 issues.sonatype.org 注册本人的账号,基于这个平台,疾速公布到maven仓库 注册实现后记住,账号密码,前面公布须要应用受权 创立本人的maven我的项目工单注册实现后咱们创立本人,公布的maven我的项目,点击新建 项目选择:Community Support - Open Source Project Repository Hosting (OSSRH) 问题类型抉择:New Project *的是必填项,其余留空或者放弃默认即可,而后新建工单期待管理员审核 我的项目地址填一个你的我的项目的Github仓库地址。这里还是强调一下组id的填写,组id须要依据你本人的域名或者开源仓库地址来填。 前面在问题-我的报告中能够追踪issue的审核状况 期待管理员审核。审核实现,管理员会在上面提醒你让你验证这个域名是你的或者证实gitee或者github空间是你的 敞开maven工单我的项目maven工单我的项目审核通过后,会有邮件揭示。 新建胜利issue后须要期待Sonatype的工作人员进行审核,审核工夫大概几分钟左右(我过后5min貌似有人几小时的....),审核通过后issue的Status会转变为Resolved,此时你就能够进行下一步操作了 你点击问题---找到你本人新建的我的项目 而后点击Respond按钮开启工单,让管理员去验证。 期待验证实现,管理员就会接着回复你验证胜利,这就阐明你的工单通过了,能够上传我的项目了 如果是用域名,则管理员会让你给你的域名增加一个TXT解析,而后他来验证: 没问题,这个时候能够敞开问题 我的项目配置maven 配置在你maven配置文件中配置你注册issues.sonatype.org账号密码 在maven 的conf文件夹下settings.xml 文件的servers节点配置如下 <server> <id>snapshots</id> <username>kenx</username> <password>xxxx</password> </server> <server> <id>releases</id> <username>kenx</username> <password>xxxx</password> </server> <server> <id>ossrh</id> <username>kenx</username> <password>xxx</password> </server>秘钥配置应用gpg生成秘钥 ...

July 9, 2023 · 2 min · jiezi

关于springboot:手把手教你自定义自己SpringBoot-Starter组件源码剖析

咱们晓得SpringBoot Starter也就是启动器。是SpringBoot组件化的一大长处。基于这个思维,基于这个思维SpringBoot 才变得十分弱小,官网给咱们提供很多开箱即用的启动器。 Spring Boot Starter 是 Spring Boot 的一个重要个性,它有以下长处: 依赖治理:Starter 主动解决我的项目的依赖关系,使得开发者无需手动增加和治理每个依赖。主动配置:Starter 提供了一种主动配置的形式,能够依据你的 classpath 和你定义的属性主动配置 Spring 利用。简化开发:通过提供各种服务的 Starter(如数据库、平安、缓存等),极大地简化了开发过程。缩小样板代码:因为 Starter 的主动配置和依赖治理,开发者能够专一于业务逻辑,而不是配置和基础设施代码。疾速原型开发:应用 Starter 能够疾速创立可运行的原型。易于了解和应用:Spring Boot Starter 的设计指标之一就是让非专业的开发者也能疾速上手。社区反对:除了官网提供的 Starter,还有大量的社区提供的 Starter,能够满足各种特定需要。我当初手把手教大家如何封装本人的starter 做本人的springboot组件,当然你也能够公布本人的starter 到maven地方仓库供大家应用 分析SpringBoot自带Starter咱们以WebMvcAutoConfiguration这个主动加载为例 主动配置类要能加载,有一个要求,源码剖析后果是,须要在\META-INF\spring.factories中做如下配置# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\这样SpringBoot在启动实现时候,会找到咱们引入,的starter 找到\META-INF\spring.factories 属性文件,找到须要主动加载配置的类门路,而后帮咱们主动注入到Spring IOC 容器,咱们在我的项目中就能够间接应用了。 这里实现主动加载还要依赖一些注解如: @Configuration // 指定这个类是个配置类@ConditionalOnXXX // 在指定条件成立的状况下主动配置类失效@AutoConfigureOrder //配置类程序@AutoConfigureAfter // 在哪个配置类之后@Bean //给容器中增加组件@ConfigurationProperties //联合相干的XXXProperties类 来绑定相干的配置@EnableConfigurationProperties // 让XXXProperties退出到容器中,他人就能够主动拆卸自定义本人的starter分析了SpringBoot 官网的starter 咱们自定义本人的starter,(咱们仿照着写) 命名标准 配置提醒如果自定义属性文件中,须要IDEA智能提醒须要引入 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>定义starter这里我以本人封装总结我工作以来总结我的项目封装的一个SpringBoot starter为例 <dependency> <groupId>cn.soboys</groupId> <artifactId>rest-api-spring-boot-starter</artifactId> <version>1.2.0</version> </dependency>就是我本人封装的start。曾经公布地方仓库。 目前更新版本1.3.0 性能如下 ...

July 7, 2023 · 3 min · jiezi

关于springboot:SpringBoot定义优雅全局统一Restful-API-响应框架完结撒花篇封装starter组件

之前咱们曾经,出了一些列文章。 解说如何封对立全局响应Restful API。 感兴趣的能够看我后面几篇文章 (整个starter我的项目发展史) SpringBoot定义优雅全局对立Restful API 响应框架 SpringBoot定义优雅全局对立Restful API 响应框架二 SpringBoot定义优雅全局对立Restful API 响应框架三 SpringBoot定义优雅全局对立Restful API 响应框架四 SpringBoot定义优雅全局对立Restful API 响应框架五 SpringBoot定义优雅全局对立Restful API 响应框架六 后续我萌发里新的想法,SpringBoot 不是提供了本人的starter。咱们也能够自定义starter吗,于是我定义了rest-api-spring-boot-starter,曾经公布到maven地方仓库,对之前Restful API 响应框架 做了集成和重构, 在这个根底上我又总结封装了我本人工作以罕用的很多工具,联合SpringBoot 封装了全能的工具。 曾经更新到了1.3.0 不耦合任何依赖 请应用最新版本 目前更新版本1.3.0 性能如下 反对一键配置自定义RestFull API 对立格局返回反对RestFull API 谬误国际化反对全局异样解决,全局参数验证解决业务谬误断言工具封装,遵循谬误优先返回准则redis工作封装。反对所有key操作工具RestTemplate 封装 POST,GET 申请工具日志集成。自定义日志门路,依照日志等级分类,反对压缩和文件大小宰割。按工夫显示工具库集成 集成了lombok,hutool,commons-lang3,guava。不须要本人单个引入集成mybatisPlus一键代码生成github 地址 上面我讲一下怎么在我的项目中去应用 咱们新建一个SpringBoot Web我的项目 咱们只须要在pom中引入即可 <dependency> <groupId>cn.soboys</groupId> <artifactId>rest-api-spring-boot-starter</artifactId> <version>1.2.0</version> </dependency>在启动类或者配置类中加上 @EnableRestFullApi 注解即可 RestFull API应用这样在我的项目controller中咱们写一般的申请如: @PostMapping("/chat") public HashMap chatDialogue() { HashMap m = new HashMap(); m.put("age", 26); m.put("name", "Judy"); return m; }返回的就是全局对立RestFull API ...

July 6, 2023 · 3 min · jiezi

关于springboot:亿级日活业务稳如磐石-华为云发布性能测试服务CodeArts-PerfTest

 HDC期间可参加华为云PaaS生态抽奖流动,流动链接在文末计算机软件作为人类逻辑智慧的平凡结晶之一,曾经渗透到了人类社会的各个角落。晚期的计算机倒退对硬件有很强的依赖性,只有多数的集体或者机构能力领有软件这种“奢侈品”。但随着软件行业的高速倒退,软件逐渐走下了居高临下的神坛,用户也开始从经济学角度思考软件产品的投入产出比,并对软件的性能提出了更高要求。随着摩尔定律越来越难以维持,软件性能的晋升曾经成为重中之重。而软件性能测试作为掂量软件性能和发现性能瓶颈的要害伎俩之一,也失去越来越多的器重。 以以后炽热的数字化营销为例,线上的秒杀抢购、抢红包、热点营销等流动已成为企业必备的营销伎俩,随之而来的大规模流量浪涌对系统来说是个微小的考验,如何应答用户和流量激增的同时又能保障利用的稳固运行已成为各厂家必须解决的问题。国外某电商巨头的统计显示客户拜访的响应工夫每缩短1秒,网站一年就会缩小16亿美元销售额,首页关上工夫每减少100毫秒,网站的销售量会缩小1%。据估计,每年电子商务网站都会因载入速度过慢,而损失11亿~13亿美元的支出。换言之,一个好的网站,绝不允许其性能方面呈现问题。 华为云性能测试服务(PerformanceTest,简称PerfTest)是一项为基于HTTP/HTTPS/TCP/UDP/HLS/RTMP/WEBSOCKET/HTTP-FLV等协定构建的云利用提供性能测试的服务。反对疾速模仿大规模并发用户的业务顶峰场景,能够很好地反对报文内容和时序自定义、多事务组合的简单场景测试,测试实现后提供业余的测试报告,将性能压测自身的工作继续简化,帮忙客户将更多的精力投放到业务和性能问题自身。同时降低成本,晋升稳定性,优化用户体验,帮忙企业晋升商业价值。 近日,性能测试服务CodeArts PerfTest全新上线,提供低门槛、低成本的一站式云化性能测试解决方案,其服务设计理念为:“Anywhere”,反对多种协定,满足各行各业;“Anyone”,低门槛免编码发展各层次性能测试;“Anytime”,即开即用,任何时候发展测试。 华为云CodeArts PerfTest为利用保驾护航, 助力产品高质量公布 随着分布式架构和微服务的遍及,利用的复杂程度越来越高,在架构解构和性能晋升的同时,带来了生产环境性能问题定位难度高、修复周期长等问题。因而,如何做到无效防备并能疾速修复,成为高效发展性能测试的次要诉求。 华为云CodeArts PerfTest为华为外部百万微服务提供性能测试,帮忙研发人员日常性能诊断、故障定位和排查,将微服务的性能测试周期由周级升高至小时级,无力地撑持了华为云、终端、车、能源等各类型产品的利用性能评估和日常运维品质保障。 当初,华为云将外部多年积攒的利用性能测试能力积淀到CodeArts PerfTest,该工具具备4大个性:  个性一:千万级性能压测引擎,保障亿级日活零碎稳固牢靠 华为云CodeArts PerfTest提供千万级集群超大规模并发能力,涵盖超高并发刹时发动、梯度加压、动静压力调整等性能,满足亿级日活利用的压测要求;反对自定义插件,实现公有协定和函数的对接,满足各类协定与简单场景的性能压测,让企业可能灵便按需进行高并发测试,提前发现极限场景下的性能问题,保障产品上市品质。     编辑   个性二:8大特色压测模式,性能容量全场景智能评估 华为云CodeArts PerfTest积淀了30年高并发测试工程计划与实际,提供了浪涌(突发流量)、智能摸高(零碎性能摸底)、震荡(模仿高下峰)、TPS模式(压力自定义)等8大模式,疾速构建实在场景,助力产品压测场景覆盖率晋升50%,满足客户全场景的压测诉求。   编辑 个性三:存量资产零老本接入,性能压测开箱即用 华为云CodeArts PerfTest兼容JMeter脚本以及脚本的执行,企业仅需把原有JMeter脚本导入生成JMeter工程,即可疾速进行压测,缩短搭建JMeter大规模压测环境的工夫,按需弹性扩容并发执行机,晋升整体执行效率,撑持压测周期由周级升高至小时级。  编辑 个性四:产品性能全方位评估,疾速辨认性能瓶颈 华为云CodeArts PerfTest提供多维度指标的压测报告,蕴含TPS、RT、SuccessRate、TPxx、StatusCode、执行日志等20多项性能指标,可接入实时资源并调用链关系的可视化数据分析,全方位评估性能指标,通过多轮报告比照性能,疾速精确剖析出性能瓶颈点,为业务的上线保驾护航。 编辑 得益于以上个性,华为云CodeArts PerfTest现在已广泛应用于金融、车企、互联网、政企等畛域,帮忙企业预估性能容量基线,正当利用资源,晋升服务稳定性,为企业倒退夯实根底。如华为云CodeArts PerfTest专家团队帮助海内某通信平台,通过模仿业务10大外围千万级并发的实在业务场景,达成 1亿日活架构优化的指标,晋升资源利用率200%,节俭用户老本百万美金,无效保障业务急速扩张10倍,达成公司战略目标。 将来,华为云CodeArts PerfTest将一直积淀企业应用性能看护的最佳实际,提供一体化智能压测体系解决方案,继续晋升关键技术竞争力,守护客户产品稳固,助力客户商业胜利。 产品体验通道:https://console.huaweicloud.com/cpts/v3?region=cn-south-1#/home-mobile?utm_medium=hdc 抽奖流动:华为云论坛_云计算论坛_开发者论坛_技术论坛-华为云

July 5, 2023 · 1 min · jiezi

关于springboot:SpringBootVue3MySQL集群-开发健康体检双系统

一、介绍 SpringBoot是一个基于Spring框架的疾速开发框架,它可能帮忙开发者疾速搭建一个Web利用。Vue3是一种前端框架,它可能帮忙开发者疾速构建一个交互式的用户界面。SpringBoot和Vue3的联合,能够实现前后端拆散,进步开发效率。download:daxiacode.com本文将介绍如何应用SpringBoot和Vue3搭建一个Web利用,并实现根本的增删改查性能。 二、环境搭建 装置Java和Maven SpringBoot是一个Java框架,所以须要装置Java和Maven。能够从Oracle官网下载Java和Maven,并依照官网文档进行装置。 装置Node.js和Vue CLI Vue3是一个前端框架,所以须要装置Node.js和Vue CLI。能够从Node.js官网下载Node.js,并应用npm装置Vue CLI。 创立SpringBoot我的项目 能够应用Spring Initializr来创立SpringBoot我的项目。Spring Initializr是一个疾速创立SpringBoot我的项目的工具,能够抉择所需的依赖和插件,生成一个根本的SpringBoot我的项目构造。 创立Vue3我的项目 能够应用Vue CLI来创立Vue3我的项目。Vue CLI是一个疾速创立Vue3我的项目的工具,能够抉择所需的依赖和插件,生成一个根本的Vue3我的项目构造。 三、开发后端利用 增加依赖 在pom.xml文件中增加SpringBoot和JPA的依赖。 xml org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 runtime 创立实体类 创立一个实体类,用于映射数据库表。 @Entity @Table(name = "user") public cl* User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Integer age; private String email; // getter和setter办法省略 } 创立Repository 创立一个Repository,用于拜访数据库。 @Repository public interface UserRepository extends JpaRepository { } 创立Controller 创立一个Controller,用于解决HTTP申请。 @RestController ...

July 3, 2023 · 1 min · jiezi

关于springboot:SpringBoot-2-种方式快速实现分库分表轻松拿捏

大家好,我是小富~ 本文是《分库分表ShardingSphere5.x原理与实战》系列的第三篇文章,本文将为您介绍 ShardingSphere 的一些根底个性和架构组成,以及在 Springboot 环境下通过 JAVA编码 和 Yml配置 两种形式疾速实现分库分表。 本文案例demo地址 一、什么是 ShardingSphere?shardingsphere 是一款开源的分布式关系型数据库中间件,为 Apache 的顶级我的项目。其前身是 sharding-jdbc 和 sharding-proxy 的两个独立我的项目,起初在 2018 年合并成了一个我的项目,并正式更名为 ShardingSphere。 其中 sharding-jdbc 为整个生态中最为经典和成熟的框架,最早接触分库分表的人应该都晓得它,是学习分库分表的最佳入门工具。 现在的 ShardingSphere 曾经不再是单纯代指某个框架,而是一个残缺的技术生态圈,由三款开源的分布式数据库中间件 sharding-jdbc、sharding-proxy 和 sharding-sidecar 所形成。前两者问世较早,性能较为成熟,是目前广泛应用的两个分布式数据库中间件,因而在后续的文章中,咱们将重点介绍它们的特点和应用办法。 二、为什么选 ShardingSphere?为了答复这个问题,我整顿了市面上常见的分库分表工具,包含 ShardingSphere、Cobar、Mycat、TDDL、MySQL Fabric 等,并从多个角度对它们进行了简略的比拟。 CobarCobar 是阿里巴巴开源的一款基于MySQL的分布式数据库中间件,提供了分库分表、读写拆散和事务管理等性能。它采纳轮询算法和哈希算法来进行数据分片,反对分布式分表,然而不反对单库分多表。 它以 Proxy 形式提供服务,在阿里外部被宽泛应用已开源,配置比拟容易,无需依赖其余货色,只须要有Java环境即可。兼容市面上简直所有的 ORM 框架,仅反对 MySQL 数据库,且事务反对方面比拟麻烦。 MyCATMycat 是社区爱好者在阿里 Cobar 根底上进行二次开发的,也是一款比拟经典的分库分表工具。它以 Proxy 形式提供服务,反对分库分表、读写拆散、SQL路由、数据分片等性能。 兼容市面上简直所有的 ORM 框架,包含 Hibernate、MyBatis和 JPA等都兼容,不过,美中不足的是它仅反对 MySQL数据库,目前社区的活跃度绝对较低。 TDDLTDDL 是阿里巴巴团体开源的一款分库分表解决方案,能够主动将SQL路由到相应的库表上。它采纳了垂直切分和程度切分两种形式来进行分表分库,并且反对多数据源和读写拆散性能。 TDDL 是基于 Java 开发的,反对 MySQL、Oracle 和 SQL Server 数据库,并且能够与市面上 Hibernate、MyBatis等 ORM 框架集成。 ...

June 29, 2023 · 4 min · jiezi

关于springboot:Spring-Boot-单体应用一键升级成-Spring-Cloud-Alibaba

背景随着 Apache Dubbo、Nacos 以及 Spring Cloud 等服务框架的风行,越来越多的企业开始采纳微服务架构来构建其应用程序。微服务架构使企业可能将其应用程序拆分成多个小型服务,这些服务能够独立部署和扩大。这种架构模式也使企业更容易实现麻利开发和继续交付,从而进步了其业务效率和响应能力。 残缺内容请点击下方链接查看: https://developer.aliyun.com/article/1205641?utm_content=g_10... 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

June 28, 2023 · 1 min · jiezi

关于springboot:springboot-2712-logback日志切割

springboot自带logback日志,实现日志滚动切割,防止日志文件过大。 一、springboot自带 yml文件配置logging: #级别 level: root: DEBUG #文件名 file: name: log/zxh-test.log #切割设置 logback: rollingpolicy: #文件格式 file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i.log #重启是否删除过期日志 clean-history-on-start: false #文件大小 测试设置为1KB。请批改 max-file-size: 1KB #日志总大小 total-size-cap: 0 #保留天数 max-history: 15官网文档:springboot logback配置 官网文档留神: 如需设置门路,请间接在logging.file.name中加前缀,配置path不会起作用。只设置path,name会是spring.log。官网写的很分明。后果图: 二、自定义切割 筛选谬误日志。application.yml。path和name都须要。辨别门路和名字。和下面不同。 logging: #级别 level: root: DEBUG #文件名 file: name: zxh-test path: log #切割设置 logback: rollingpolicy: #文件格式 file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i.log #重启是否删除过期日志 clean-history-on-start: false #文件大小 测试设置为1KB。请批改 max-file-size: 10KB #日志总大小 total-size-cap: 0 #保留天数 max-history: 15减少配置文件。文件名肯定是logback-spring.xml (官网定义) <?xml version="1.0" encoding="UTF-8"?><!--scan:当此属性设置为true时,配置文件如果产生扭转,将会被从新加载,默认值为true。scanPeriod:设置监测配置文件是否有批改的工夫距离,如果没有给出工夫单位,默认单位是毫秒当scan为true时,此属性失效。默认的工夫距离为1分钟。debug:当此属性设置为true时,将打印出logback外部日志信息,实时查看logback运行状态。默认值为false。--><configuration scan="true" scanPeriod="60 seconds" debug="false"> <!--springboot 自带配置 defaults.xml console-appender.xml--> <include resource="org/springframework/boot/logging/logback/defaults.xml" /> <include resource="org/springframework/boot/logging/logback/console-appender.xml"/> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> <charset>${FILE_LOG_CHARSET}</charset> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--文件格式--> <fileNamePattern>${LOG_PATH}/${LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!--重启是否革除日志--> <cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart> <!--文件最大大小--> <maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize> <!--被删除之前最大大小--> <totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap> <!--保留天数--> <maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}</maxHistory> </rollingPolicy> </appender> <!--谬误日志筛选--> <appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> <charset>${FILE_LOG_CHARSET}</charset> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--文件格式--> <fileNamePattern>${LOG_PATH}/error/${LOG_FILE}.error.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!--重启是否革除日志--> <cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart> <!--文件最大大小--> <maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize> <!--被删除之前最大大小--> <totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap> <!--保留天数--> <maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}</maxHistory> </rollingPolicy> </appender> <!--辨别环境。在yml文件中配置spring.profiles.active。 零碎输入 or 所有日志 or 谬误日志 --> <springProfile name="dev"> <!--输入形式--> <root> <!--零碎打印。 会生成默认文件,但理论不会输入到文件--> <appender-ref ref="CONSOLE"/> </root> </springProfile> <springProfile name="prod"> <root> <!--零碎--> <appender-ref ref="CONSOLE"/> <!--所有文件--> <appender-ref ref="FILE"/> <!--谬误文件--> <appender-ref ref="FILE-ERROR"/> </root> </springProfile></configuration>后果图: ...

June 21, 2023 · 1 min · jiezi

关于springboot:项目启动超慢记录

最近新人在开发我的项目过程中革新了很多代码,启动过程中发现十分慢,于是我进去帮忙排查,简略记录下; 我的项目启动我开启了debug日志,发现次要耗时卡在jooq下面; 2023-06-16 19:43:31,346 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'dslContext' via factory method to bean named 'jooqConfiguration' 2023-06-16 19:43:31,957 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'dslContext' to allow for resolving potential circular references 2023-06-16 19:43:32,182 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2023-06-16 19:43:32,183 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2023-06-16 19:51:45,172 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'dslContext' 2023-06-16 19:51:45,173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'jooqConfiguration' 2023-06-16 19:51:45,173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'spring.jooq-org.springframework.boot.autoconfigure.jooq.JooqProperties' 2023-06-16 19:51:45,173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration' 2023-06-16 19:51:45,173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'dataSourceConnectionProvider' 2023-06-16 19:51:45,173 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionProvider' 发现实现dslcontext用了足足8分钟 ...

June 17, 2023 · 1 min · jiezi

关于springboot:springboot集成测试最小化依赖实践

目录简介版本及依赖引入 springboot版本我的项目局部依赖间接应用SpringBootTest形式 代码示例场景及优劣最小化依赖计划 代码思路及步骤最小化依赖计划的长处论断 简介想要代码跑的稳, 集成测试还是必不可少的, 不然呈现开发环境失常, 集成环境各种问题就坑爹了。 以后我的项目对外提供各种rest接口, 通过RestTemplate做接口测试, 同时须要注入一些SpringBean, 如何应用SpringBootTest又不须要启动整个容器? 版本及依赖引入 springboot版本<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --></parent> 我的项目局部依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency> 间接应用SpringBootTest形式 代码示例@RunWith(SpringRunner.class)// 默认启动容器@SpringBootTestpublic class BdgResourceITest { @Autowired @Qualifier(value = "iTestRestTemplate") private RestTemplate restTemplate; @Test public void testPull() throws URISyntaxException { // /pull/{mof_div_code}/{fiscal_year}/{agency_code} String url = "/api/pull/340000000/2022/001001"; final ResponseEntity<ResponseData> exchange = restTemplate.exchange( RequestEntity.get(new URI(url)).build(), ResponseData.class); Assert.isTrue(exchange.getStatusCode().equals(HttpStatus.OK), "本单位数据获取异样"); }} 场景及优劣劣势如果是测试类中大量引入了依赖, 这种状况下间接启动容器比拟不便, 不过集成测试个人感觉从入口拜访即可, 这种嵌套比拟深的倡议应用单元测试 ...

June 16, 2023 · 1 min · jiezi

关于springboot:6-种方式读取-Springboot-的配置老鸟都这么玩原理实战

大家好,我是小富~ 从配置文件中获取属性应该是SpringBoot开发中最为罕用的性能之一,但就是这么罕用的性能,依然有很多开发者在这个方面踩坑。 我整顿了几种获取配置属性的形式,目标不仅是要让大家学会如何应用,更重要的是弄清配置加载、读取的底层原理,一旦呈现问题能够剖析出其症结所在,而不是一报错取不到属性,无头苍蝇般的重启我的项目,在句句卧槽中逐步抓狂~ 以下示例源码 Springboot 版本均为 2.7.6下边咱们一一过下这几种玩法和原理,看看有哪些是你没用过的!话不多说,开始搞~ 一、Environment应用 Environment 形式来获取配置属性值非常简单,只有注入Environment类调用其办法getProperty(属性key)即可,但知其然知其所以然,简略理解下它的原理,因为后续的几种获取配置的办法都和它非亲非故。 @Slf4j@SpringBootTestpublic class EnvironmentTest { @Resource private Environment env; @Test public void var1Test() { String var1 = env.getProperty("env101.var1"); log.info("Environment 配置获取 {}", var1); }}1、什么是 Environment?Environment 是 springboot 外围的环境配置接口,它提供了简略的办法来拜访应用程序属性,包含零碎属性、操作系统环境变量、命令行参数、和应用程序配置文件中定义的属性等等。 2、配置初始化Springboot 程序启动加载流程里,会执行SpringApplication.run中的prepareEnvironment()办法进行配置的初始化,那初始化过程每一步都做了什么呢? private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { /** * 1、创立 ConfigurableEnvironment 对象:首先调用 getOrCreateEnvironment() 办法获取或创立 * ConfigurableEnvironment 对象,该对象用于存储环境参数。如果曾经存在 ConfigurableEnvironment 对象,则间接应用它;否则,依据用户的配置和默认配置创立一个新的。 */ ConfigurableEnvironment environment = getOrCreateEnvironment(); /** * 2、解析并加载用户指定的配置文件,将其作为 PropertySource 增加到环境对象中。该办法默认会解析 application.properties 和 application.yml 文件,并将其增加到 ConfigurableEnvironment 对象中。 * PropertySource 或 PropertySourcesPlaceholderConfigurer 加载应用程序的定制化配置。 */ configureEnvironment(environment, applicationArguments.getSourceArgs()); // 3、加载所有的零碎属性,并将它们增加到 ConfigurableEnvironment 对象中 ConfigurationPropertySources.attach(environment); // 4、告诉监听器环境参数曾经准备就绪 listeners.environmentPrepared(bootstrapContext, environment); /** * 5、将默认的属性源中的所有属性值移到环境对象的队列开端, 这样用户自定义的属性值就能够笼罩默认的属性值。这是为了防止用户无心中笼罩了 Spring Boot 所提供的默认属性。 */ DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); // 6、将 Spring Boot 应用程序的属性绑定到环境对象上,以便可能正确地读取和应用这些配置属性 bindToSpringApplication(environment); // 7、如果没有自定义的环境类型,则应用 EnvironmentConverter 类型将环境对象转换为规范的环境类型,并增加到 ConfigurableEnvironment 对象中。 if (!this.isCustomEnvironment) { EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader()); environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } // 8、再次加载系统配置,以避免被其余配置笼罩 ConfigurationPropertySources.attach(environment); return environment;}看看它的配置加载流程步骤: ...

June 16, 2023 · 4 min · jiezi

关于springboot:生产环境可用的-Seatago-120-来啦

文|刘月财(GitHub ID:luky116) 360 服务端开发专家 Seata-go 我的项目负责人 本文 2752 字 浏览 7 分钟 公布概览 Seata-go 1.2.0 版本反对 XA 模式。XA 协定是由 X/Open 组织提出的分布式事务处理标准,其长处是对业务代码无侵入。以后 Seata-go 的 XA 模式反对 MySQL 数据库。至此,Seata-go 曾经集齐 AT、TCC、Saga 和 XA 四种事务模式,实现了与 Seata Java 的性能对齐。 XA 模式的次要性能: 反对了 XA 数据源代理反对了 XA 事务模式XA 相干的 Samples 能够参考示例: https://github.com/seata/seata-go-samples/tree/main/xa 在本版本中还修复了近期大量用户在应用过程中提交的 issue。 版本的次要更新如下 Feature: [#467] 实现 XA 模式反对 MySQL https://github.com/seata/seata-go/pull/467 [#534] 反对 Session 的负载平衡 https://github.com/seata/seata-go/pull/534 Bugfix: [#540] 修复初始化 XA 模式的 bug https://github.com/seata/seata-go/pull/540 [#545] 修复 XA 模式获取 db 版本号的 bug ...

June 14, 2023 · 2 min · jiezi

关于springboot:SpringBoot定义优雅全局统一Restful-API-响应框架六

闲话不多说,持续优化 全局对立Restful API 响应框架 做到我的项目通用 接口可扩大。 如果没有看后面几篇文章请先看后面几篇 SpringBoot定义优雅全局对立Restful API 响应框架 SpringBoot定义优雅全局对立Restful API 响应框架二 SpringBoot定义优雅全局对立Restful API 响应框架三 SpringBoot定义优雅全局对立Restful API 响应框架四 SpringBoot定义优雅全局对立Restful API 响应框架五 这里讲一讲最初的版本和须要修复的一些问题 @PostMapping("/add/UserApiCombo") public R addApiCombo(@RequestBody @Validated UserApplyApiComboDto userApplyApiComboDto) { userApiComboService.addApiCombo(userApplyApiComboDto); return R.success(); }咱们看看这个代码,有什么问题。 咱们返回了对立的封装后果集R 然而前面所有的controller 都这么写不太敌对。 返回内容这么不够明确具体所有controller 这么写减少反复工作量咱们能够这么去优化: Spirng 提供了 ResponseBodyAdvice 接口,反对在音讯转换器执行转换之前,对接口的返回后果进行解决,再联合 @ControllerAdvice 注解即可轻松反对上述性能 package cn.soboys.springbootrestfulapi.common.handler;import cn.hutool.core.bean.BeanUtil;import cn.hutool.core.map.MapUtil;import cn.soboys.springbootrestfulapi.common.error.ErrorDetail;import cn.soboys.springbootrestfulapi.common.resp.R;import lombok.extern.slf4j.Slf4j;import org.springframework.core.MethodParameter;import org.springframework.http.MediaType;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/6/12 12:17 下午 * @webSite https://github.com/coder-amiao * @Slf4j * @ControllerAdvice */@Slf4j@ControllerAdvicepublic class ResponseResultHandler implements ResponseBodyAdvice<Object> { /** * supports办法: 判断是否要执行beforeBodyWrite办法, * true为执行,false不执行. * 通过该办法能够抉择哪些类或那些办法的response要进行解决, 其余的不进行解决. * * @param returnType * @param converterType * @return */ @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } /** * beforeBodyWrite办法: 对response办法进行具体操作解决 * 理论返回后果业务包装解决 * * @param body * @param returnType * @param selectedContentType * @param selectedConverterType * @param request * @param response * @return */ @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body instanceof R) { return body; } else if (body == null) { return R.success(); } else if (body instanceof ErrorDetail) { return body; } else if (body instanceof String) { return body; } else { return R.success().data(body); } }}在理论controller 返回中咱们间接返回数据内容就能够了 ...

June 13, 2023 · 3 min · jiezi

关于springboot:FeignClient自调用问题处理

我的项目中应用feignClient时,有时会遇到自调用状况,即A服务通过feignClient,调用了本人服务的接口。这种状况个别是因为谬误的办法应用,不正确的feignClient依赖导致,应予以修改。 但也有一些状况,比方依赖的内部sdk包中的service办法里,通过feignClient调用了近程办法,而这个近程办法的服务方正是本人(比方serviceA)。在这种状况下,能够通过以下步骤进行解决,将近程调用变为本地办法间接执行: 在定义近程调用的FeignClient类上,申明primary值为true: @FeignClient(value = "serviceA", contextId = "testFeign", path = "busitest", primary = false)public interface TestFeign { @GetMapping public String get();}将对应实现该FeignClient办法的Controller类上,补全继承关系,并申明@Primary: @RequestMapping("busitest")@RestController@Primarypublic class BusiTestController implements TestFeign{ @GetMapping public String get(){ return "get"; }}实现以上步骤后,重新部署api包。此时如果某服务的sdk包中存在如下Service: @Servicepublic class BusiService{ @Autowired private TestFeign testFeign; public Strinmg busiMethod(){ testFeign.get(); }}则该Service在serviceA之外的服务中应用时,执行busiMethod办法,会通过feignClient向serviceA发动近程调用;而在serviceA服务自身应用这个Service时,执行busiMethod办法,会间接执行BusiTestController的get()办法,而不再通过feignClient去解决申请。

June 12, 2023 · 1 min · jiezi

关于springboot:亿级数据毫秒级响应

作为一名深陷在增删改查泥潭中练习时长三年的夹娃练习生,偶然会因为没有开发工作不晓得周报写什么而苦恼。正愁这周写啥呢,组长过去交代了个跟进第三方公司性能测试报告的工作,我一寻思这活不最好干了吗,正愁不晓得周报咋写呢,又能提现工作量又不累,本认为轻松拿捏的后果差点让老弟翻车。因为咱们组次要做数仓治理这块的业务,这次的性能测试上有一些数据服务并发相干的指标须要后端配合测试,让一天搞定,我寻思半天搞完还能去掘金狠狠的摸半天鱼,岂不美哉。拿到测试指标之后间接手心出汗了。 啥意思,亿级数据查问毫秒级响应还要100并发继续5分钟,家人们谁懂啊。。。要害咱们负责的业务是tob的场景啊,哪有这么高并发。数据查问还在旧的python服务里,给提供的测试环境全是单机服务。加缓存既然是做性能测试那管数据对不对什么事,给你返回不就行了,在服务加个长期缓存,先把数据查问的耗时降下来再思考其余的。身为一个Javaboy,写python的代码10行代码得5行问chatGPT,好在是用redis加上了缓存。用jmeter浅试一下, 成果上看加上缓存查问速度确实变快了,然而均匀耗时离预期还是差距较大,最大耗时要靠近5s多,看来只加缓存是扛不住,耗时应该是服务扛不住并发,线程阻塞了。。。nginx横向扩大不得不吐槽下,服务真垃圾呐,工夫紧工作重,连忙想方法,间接把问题当成面试题,脑袋里间接开始翻阅八股文,什么高内聚、低耦合、高吞吐、月薪3000包吃住,第一个冲进去的想法就是扩大服务做负载。怎么负载呢,部署三份数据查问服务,nginx做upstream负载,成果应该顶得住,开搞开搞。后果python代码不太熟,多过程的形式启动torando就是报错。整的我满头大汗,下午就得给人提供接口了这咋整啊,不行问问组长去吧。后果组长间接说节约那工夫干啥啊,反正都是做做样子,在nginx里写个lua脚本,读一下本地文件返回数据不就能够了,第三方又不会管你咋实现的...都得都懂。lua脚本我认真一想也是,整那么缓和干啥,先实现了再说,因为环境里的nginx曾经装置了lua插件能够间接应用。先提前把申请的返回数据保留到txt里,而后用lua实现一个读取本地文件的办法,申请打过去之后判断body里的数据是否是指定的数据id,如果是间接读取数据返回。nginx和lua的性能别说100并发了1w并发也轻松拿捏。lua读取本地文件内容lua复制代码 function getFile(file_name) local f = assert(io.open(file_name, 'r')) local string = f:read("*all") f:close() return stringend找到nginx配置对应的申请url,增加access_by_lua_block代码块,将getFile办法申明在这里,并且写一下匹配逻辑,如果body中蕴含file_id,间接调用getFile办法返回,不蕴含还是走失常的查问逻辑。php复制代码 location = /api/data/preview { set $upstream 'fe_full_long'; access_by_lua_block { function getFile(file_name) local f = assert(io.open(file_name, 'r')) local string = f:read("*all") f:close() return string end ngx.req.read_body() local data = ngx.req.get_body_data() if ngx.re.match(ngx.var.request_body, "file_id") then ngx.say(getFile(string.format("/nginx/conf/conf.d/a.txt", f))); return end } proxy_pass http://$upstream; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}保留nginx -t,先查看后重启,避免手心冒汗,简略测了一下性能间接腾飞,间接提供给第三方测试了。亿级数据毫秒级响应?早晨上班前发过来了初版的测试报告,组长一看,间接给我阅起兵来了,"你这也太快了,搂着点啊,管家指标还一样,快改改"。 ...

June 6, 2023 · 1 min · jiezi

关于springboot:前后端分离架构下使用-SaToken-完成登录认证

一、架构剖析目前绝大多数零碎都曾经采纳 “前后端拆散” 架构来设计了,传统的Session模式鉴权也不再适宜这种架构(或者须要额定写很多的代码来专门适配)。 Sa-Token 是一个 java 轻量级权限认证框架,专为前后端拆散架构打造,次要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相干问题。 Gitee 开源地址:https://gitee.com/dromara/sa-token本文将介绍在 Springboot 架构下的前后端拆散我的项目,如何应用 Sa-Token 不便的实现登录认证。 首先在我的项目中引入 Sa-Token 依赖: <!-- Sa-Token 权限认证 --><dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.34.0</version></dependency>注:如果你应用的是 SpringBoot 3.x,只须要将 sa-token-spring-boot-starter 批改为 sa-token-spring-boot3-starter 即可。 二、无 Cookie 模式无 Cookie 模式:特指不反对 Cookie 性能的终端,艰深来讲就是咱们常说的 —— 前后端拆散模式。 惯例 Web 端鉴权办法,个别由 Cookie模式 实现,而 Cookie 有两个个性: 可由后端管制写入。每次申请主动提交。这就使得咱们在前端代码中,无需任何非凡操作,就能实现鉴权的全副流程(因为整个流程都是后端管制实现的)<br/>而在app、小程序等前后端拆散场景中,个别是没有 Cookie 这一性能的,此时大多数人都会一脸懵逼,咋进行鉴权啊? 见招拆招,其实答案很简略: 不能后端管制写入了,就前端本人写入。(难点在后端如何将 Token 传递到前端)每次申请不能主动提交了,那就手动提交。(难点在前端如何将 Token 传递到后端,同时后端将其读取进去)三、后端将 token 返回到前端首先调用 StpUtil.login(id) 进行登录。调用 StpUtil.getTokenInfo() 返回以后会话的 token 具体参数。 此办法返回一个对象,其有两个要害属性:tokenName和tokenValue(token 的名称和 token 的值)。将此对象传递到前台,让前端人员将这两个值保留到本地。代码示例: // 登录接口@RequestMapping("doLogin")public SaResult doLogin() { // 第1步,先登录上 StpUtil.login(10001); // 第2步,获取 Token 相干参数 SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); // 第3步,返回给前端 return SaResult.data(tokenInfo);}四、前端将 token 提交到后端无论是app还是小程序,其传递形式都大同小异。那就是,将 token 塞到申请header里 ,格局为:{tokenName: tokenValue}。以经典跨端框架 uni-app 为例:形式1,简略粗犷 ...

June 5, 2023 · 2 min · jiezi

关于springboot:SpringBoot-SSM-vue-在线办公系统

SpringBoot SSM vue 在线办公零碎零碎性能登录 遗记明码 首页统计分析 用户治理 员工治理 布告治理 考勤治理 绩效治理 薪酬治理 流程治理 留言治理 文件治理 开发环境和技术开发语言:Java应用框架: SpringBoot或SSM + Mybatis + MysqlSpring Boot是一个用于构建Java应用程序的开源框架。它基于Spring框架,通过主动配置和约定优于配置的准则,提供了一种疾速开发和部署的解决方案。前端: vue数据库:MySQL (Navicat可视化工具)架构:B/S源码类型: Web编译开发工具:Idea、Eclipse、MyEclipse (选其一)其余:jdk1.8、Tomcat8.5性能图片展现 总结源码获取: 大家可点赞、珍藏、关注、评论、私信

June 1, 2023 · 1 min · jiezi

关于springboot:揭开神秘面纱会stream流就会大数据

如果你会任意一门语言的stream流,没道理不会大数据开发。俗话说男追女隔座山,女追男隔层纱。如果说零根底学大数据,感觉后面是一座山,那么只有你会java或者任意一门语言的stream流,那大数据就只隔了一层纱。本文以java stream流计算为例,解说一些根底的spark操作。另一个风行的大数据框架flink同理。 筹备工作测试数据,以下列别离示意姓名,年龄,部门,职位。复制代码张三,20,研发部,普通员工李四,31,研发部,普通员工李丽,36,财务部,普通员工张伟,38,研发部,经理杜航,25,人事部,普通员工周歌,28,研发部,普通员工 创立一个Employee类。less复制代码 @Getter @Setter@AllArgsConstructor@NoArgsConstructor@ToStringstaticclass Employee implements Serializable { private String name; private Integer age; private String department; private String level;}} 版本:jdk:1.8spark:3.2.0scala:2.12.15下面的scala版本只是spark框架自身须要依赖到scala。因为scala的确是比拟小众的语言,本文还是应用java演示spark代码。1.map类1.1 java stream mapmap示意一对一操作。将上游数据的一行数据进行任意操作,最终失去操作后的一条数据。这种思维,在java和spark,flink都是统一的。咱们先用java stream演示读取文件,再应用map操作将每行数据映射为Employee对象。ini复制代码List<String> list = FileUtils.readLines(new File("f:/test.txt"), "utf-8"); List<Employee> employeeList = list.stream().map(word -> { List<String> words = Arrays.stream(word.split(",")).collect(Collectors.toList()); Employee employee = new Employee(words.get(0), Integer.parseInt(words.get(1)), words.get(2), words.get(3)); return employee; }).collect(Collectors.toList()); employeeList.forEach(System.out::println);转换后的数据:ini复制代码JavaStreamDemo.Employee(name=张三, age=20, department=研发部, level=普通员工)JavaStreamDemo.Employee(name=李四, age=31, department=研发部, level=普通员工)JavaStreamDemo.Employee(name=李丽, age=36, department=财务部, level=普通员工)JavaStreamDemo.Employee(name=张伟, age=38, department=研发部, level=经理)JavaStreamDemo.Employee(name=杜航, age=25, department=人事部, level=普通员工)JavaStreamDemo.Employee(name=周歌, age=28, department=研发部, level=普通员工) ...

May 30, 2023 · 7 min · jiezi

关于springboot:Spring-Boot-URule-规则引擎太顶了

大家好,我是不才陈某~ 前段时间,在做我的项目重构的时候,遇到很多中央须要做很多的条件判断。当然能够用很多的if-else判断去解决,然而过后也不分明怎么回事,就想玩点别的。于是乎,就去调研了规定引擎。 当然,市面上有很多成熟的规定引擎,性能很多,性能很好。然而,就是想玩点不一样的(大家做技术选型别这样,这个是反面教材)。最终一款URule的规定引擎吸引了我,次要还是采纳浏览器可间接配置,不须要过多装置,可视化规定也做的不错。通过一系列调研,前面就把它接入了我的项目中,顺便记录下调研的后果。 对于规定引擎,后面也有三篇文章介绍了,如下: 规定引擎深度比照,LiteFlow vs Drools!聊聊小而美的规定引擎 LiteFlowSpring Boot + 规定引擎Drools1. 介绍规定引擎其实是一种组件,它能够嵌入到程序当中。将程序简单的判断规定从业务代码中剥离进去,使得程序只须要关怀本人的业务,而不须要去进行简单的逻辑判断;简略的了解是规定承受一组输出的数据,通过预约好的规定配置,再输入一组后果。 当然,市面上有很多成熟的规定引擎,如:Drools、Aviator、EasyRules等等。然而URule,它能够运行在Windows、Linux、Unix等各种类型的操作系统之上,采纳纯浏览器的编辑模式,不须要装置工具,间接在浏览器上编辑规定和测试规定。 当然这款规定引擎有开源和pro版本的区别,至于pro版是啥,懂的都懂,上面放个表格,理解下具体的区别 个性PRO版开源版向导式决策集有有脚本式决策集有有决策树有有决策流有有决策表有有穿插决策表有无简单评分卡有无文件名、我的项目名重构有无参数名、变量常量名重构有无Excel决策表导入有无规定集模版保留与加载有无中文我的项目名和文件名反对有无服务器推送常识包到客户端性能的反对有无常识包优化与压缩的反对有无客户端服务器模式下大常识包的推拉反对有无规定集中执行组的反对有无规定流中所有节点向导式条件与动作配置的反对有无循环规定多循环单元反对有无循环规定中无条件执行的反对有无导入我的项目主动重命名性能有无规定树构建优化有无对象查找索引反对有无规定树中短路计算的反对有无规定条件冗余计算缓存反对有无基于计划的批量场景测试性能有无常识包调用监控有无更为欠缺的文件读写权限管制有无常识包版本控制有无SpringBean及Java类的热部署有无技术支持有无2. 装置应用理论应用时,有四种应用URule Pro的形式,别离是嵌入式模式、本地模式、分布式计算模式以及独立服务模式。 然而咱们这里不思考URule Pro,咱本人整个开源版,在开源版集成springboot的根底上做一个二次开发,搜了一圈,其实就有解决方案。大抵的我的项目模块如下: 本人创立个空数据库,只须要在edas-rule-server服务中批改下数据库的配置,而后启动服务即可。第一次启动实现,数据库中会创立表。 spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/urule-data?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=falsespring.datasource.username=rootspring.datasource.password=mysql关注公众号:码猿技术专栏,回复关键词:uRule 获取案例源码!下面说过,它是纯用浏览器进行编辑,配置规定的,只须要关上浏览器,输出地址:http://localhost:8090/urule/frame,看到这个界面,就阐明启动胜利了。 3. 根底概念3.1整体介绍先说下URule它的形成局部,次要是两局部:1、设计器局部 2、规定执行引擎。设计器局部次要是库文件和规定文件形成。上面看下整体的结构图 3.2库文件如上图介绍的,库文件有4种,包含变量库,参数库,常量库和动作库。其实相似于Java开发的零碎中的实体对象,枚举,常量以及办法。 下面说过,规定都是可视化配置的。在配置规定的过程中,就须要引入各种曾经定义好的库文件,再联合业务需要,从而配置出合乎业务场景的业务规定,所以哪里都有库文件的身影。 3.2.1变量库文件在业务开发中,咱们会创立很多Getter和Setter的Java类,比方PO、VO、BO、DTO、POJO等等,其实这些类new对象后次要起到的作用就是数据的载体,用来传输数据。 在URule中,变量库就是用来映射这些对象,而后能够在规定中应用,最终实现业务和规定的互动。最初上一张图,用来创立变量库 对了,下面废话了这么多可视化配置,这才是第一次展现配置界面,羞愧羞愧。 上图高深莫测,在“库”这个菜单底下右键,而后点击增加变量库即可,最初定义本人喜爱的变量库名,当然名字只反对中文或者英文,其余字符不可用。 创立完变量库后,就能够对变量库进行编辑,能够认为就是给POJO增加属性 也不弯弯绕绕讲什么术语,就集体了解。图右边是创立类,其中名称是它的别名,配置规定用它代替这个类。图左边是类的属性,我这里轻易写了几个,预计看了懂得都懂。 最初在业务零碎中创立对应的类,留神全限定名和配置变量库的类门路统一。 package com.cicada;import com.bstek.urule.model.Label;import lombok.Data;/** * @author 公众号:码猿技术专栏 * @version 1.0 * @date 2023/3/3 15:38 * @description */@Datapublic class Stu { @Label("姓名") private String name; @Label("年龄") private int age; @Label("班级") private String classes;}最初说下这个@Label注解,这个是由URule提供的注解,次要是形容字段的属性,跟变量库的题目一栏统一就行。听官网介绍能够通过这个注解,实现POJO属性和变量库属性映射。就是POJO写好,而后对应规定的变量库就不须要从新写,能够间接生成。反正就有这个性能,这里就间接一笔带过了。 ...

May 25, 2023 · 2 min · jiezi

关于springboot:SpringBoot-pdf打印及预览openhtmltopdffreemarker

SpringBoot pdf打印及预览(openhtmltopdf+freemarker)增加依赖openhtmltopdf+freemarker <properties> <openhtml.version>1.0.10</openhtml.version> </properties><!--openhtmltopdf --> <dependencies> <dependency> <!-- ALWAYS required, usually included transitively. --> <groupId>com.openhtmltopdf</groupId> <artifactId>openhtmltopdf-core</artifactId> <version>${openhtml.version}</version> </dependency> <dependency> <!-- Required for PDF output. --> <groupId>com.openhtmltopdf</groupId> <artifactId>openhtmltopdf-pdfbox</artifactId> <version>${openhtml.version}</version> </dependency> <dependency> <!-- Optional, leave out if you do not need logging via slf4j. --> <groupId>com.openhtmltopdf</groupId> <artifactId>openhtmltopdf-slf4j</artifactId> <version>${openhtml.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> </dependencies>在/resources/template/view/html新建模板xxx.ftl文件<html><head> <meta charset="UTF-8"/> <style> /* 特有css款式自行参考官网 */ @page { size: a4; @top-left { content: element(header-left); } @top-center { content: element(header-center); } @top-right { content: element(header-right); } @bottom-center { font-size: 14px; content: counter(page); font-family: 'simsun', serif; } margin: 50px; } * { margin: 0; padding: 0; font-family: 'simsun', serif; } #page-header-left { font-size: 10px; font-weight: bold; position: running(header-left); } #page-header-center { font-size: 10px; font-weight: bold; position: running(header-center); } #page-header-right { font-size: 10px; font-weight: bold; position: running(header-right); } table { width: 100%; font-size: 14px; border-collapse: collapse; font-family: 'simsun', serif; border-spacing: 0; /* The magical table pagination property. */ /*-fs-table-paginate: paginate;*/ /* Recommended to avoid leaving thead on a page by itself. */ -fs-page-break-min-height: 0.5cm; border-left: 0.07cm solid black; border-right: 0.07cm solid black; border-bottom: 0.03cm solid black; } .checkbox { display: inline-block; position: relative; top: 1px; width: 10px; height: 10px; border: 1px solid black; } .correct { display: inline-block; position: relative; top: 2px; right: 15px; width: 7px; height: 3px; border-left: 1px solid black; border-bottom: 1px solid black; -webkit-transform: rotate(-45deg); transform: rotate(-45deg); margin-right: -16px; } input[type = "checkbox"] { width: 10px; height: 10px; border: 1px solid black; } tr, thead, tfoot { page-break-inside: avoid; } td, th { page-break-inside: avoid; font-family: 'simsun', serif; padding: 1px; border-top: 0.03cm solid black; border-left: 0.03cm solid black; } td:first-child, th:first-child { border-left: 0; } #table-title { text-align: center; margin-top: 0; margin-bottom: 5px; font-weight: bold; } </style></head><body><div class="header-box"> <div id="page-header-left"> <span id="page-header-text">编号:<span style="font-weight: normal">${code!''}</span></span> </div> <div id="page-header-center"> <span id="page-header-text">工夫 <sup>1)</sup>:<span style="font-weight: normal">${time?date!''}</span></span> </div></div><div class="basic-box"> <table style="border-top: 0;"> <tr> <td>题目1</td> <td>${xx1!''}</td> <td>题目2</td> <td>${xx2!''}</td> <td>题目3</td> <td>${xx3!''}</td> </tr> <tr> <td style="font-weight: bold;text-align: left;">后果</td> <td colspan="3" style="text-align: left;"> <div> <div class="checkbox"></div> <#if result??&&result == '1'> <div class="correct"></div> </#if> <div style="display: inline-block">合格</div> <div class="checkbox"></div> <#if result??&&result == '0'> <div class="correct"></div> </#if> <div style="display: inline-block">不合格</div> </div> </td> <td colspan="4" style="font-weight: bold;text-align: left;">签字人:</td> </tr> </table></div></body></html>controller接口 @RequestMapping(value = "/print/pdf/{code}", produces = MediaType.APPLICATION_PDF_VALUE) public ResponseEntity<byte[]> printPdf(@PathVariable("code") String detectCode) throws IOException, TemplateException { Assert.hasText(code, "code不能为空"); return detectReportPrintService.findPdf(code); }service实现类pdf预览有中文乱码,须要从新引入simsun.ttf字体文件,放在/resources/fonts文件夹下(与代码门路统一即可),ftl文件中css款式必须font-family: 'simsun', serif; ...

May 17, 2023 · 3 min · jiezi

关于springboot:QLExpression之java基本语法

QLExpress是一种基于Java语言的动静脚本引擎,能够将脚本嵌入到Java应用程序中。Spring Boot是一种疾速开发框架,它能够轻松地集成其余Java技术和框架。在Spring Boot中集成QLExpress能够使应用程序更加灵便和动静,能够在运行时动静批改业务逻辑。 以下是QLExpress中罕用的语法和表达式: 变量:应用$符号加上变量名的形式来援用变量,例如$age示意援用变量age的值。常量:反对整数、浮点数、字符串、布尔值、空值等常量类型,例如1、2.5、"hello"、true、null等。算术表达式:反对加减乘除、取余、取反等算术运算,例如1+2、3*4、-5等。逻辑表达式:反对与、或、非等逻辑运算,例如true && false、true || false、!true等。比拟表达式:反对等于、不等于、大于、小于、大于等于、小于等于等比拟运算,例如1==2、"hello"!="world"、3>4等。条件表达式:反对三目运算符来示意条件表达式,例如age>18 ? "成年人" : "未成年人"。正则表达式:反对应用正则表达式进行匹配操作,例如"name =~ 'Tom.*'"示意name以Tom结尾的字符串。函数调用:反对调用内置函数和自定义函数,例如round(3.14159, 2)示意保留3.14159的小数点后2位。办法调用:反对调用对象的办法,例如user.getName()示意调用user对象的getName()办法。数组:反对定义和操作数组,例如a[0]示意拜访数组a的第一个元素。Map:反对定义和操作Map,例如map.get("key")示意获取Map中键为key的值。对象属性:反对拜访对象的属性,例如user.name示意拜访user对象的name属性。赋值表达式:反对将值赋给变量或对象属性,例如age = 20、user.name = "Tom"。代码块:反对应用大括号将多个表达式组成代码块,并通过return语句返回值,例如{a=1;b=2;return a+b;}。表达式语句:反对将多个表达式用分号分隔,示意多个语句组成一个代码块,例如a=1;b=2;c=3;。须要留神的是,QLExpress的语法和表达式十分丰盛,这里只列举了一部分罕用的语法和表达式,具体的语法规定能够参考官网文档。在应用QLExpress时,该当依据理论需要抉择适当的语法和表达式,并进行正当的组合和使用。 以下是将QLExpress集成到Spring Boot的简略步骤: 1.增加QLExpress依赖:在Spring Boot的pom.xml文件中增加QLExpress的依赖。 Spring Boot 1.x:实用QLExpress 2.x版本;Spring Boot 2.x:实用QLExpress 3.x版本;<dependency> <groupId>com.ql</groupId> <artifactId>qlExpress</artifactId> <version>3.2.0</version></dependency>2.创立QLExpress实例:在Spring Boot中,能够通过@Component注解将QLExpress实例注入到Spring容器中。能够在应用程序中应用@Autowired注解来主动拆卸QLExpress实例。 @Componentpublic class QLExpressComponent { private QLExpress qlExpress; public QLExpressComponent() { qlExpress = new QLExpress(); } public QLExpress getQLExpress() { return qlExpress; }}3.编写计算公式:比方个人所得税计算公式能够示意为以下表达式(可联合业务场景须要,用表来存储QL公式) (income - socialInsurance - personalDeduction) * taxRate - quickDeduction其中: income:集体年收入socialInsurance:集体缴纳的社会保险费用personalDeduction:个人所得税专项扣除额taxRate:个人所得税税率quickDeduction:个人所得税速算扣除数4.应用程序中应用QLExpress计算税额 public double calculateTax(double income, double socialInsurance, double personalDeduction) throws Exception { //公式 String expression = "(income - socialInsurance - personalDeduction) * taxRate - quickDeduction"; //变量对应的值:用于换算公式的计算 DefaultContext<String, Object> context = new DefaultContext<>(); context.put("income", income); context.put("socialInsurance", socialInsurance); context.put("personalDeduction", personalDeduction); context.put("taxRate", 0.03); // 个人所得税税率为 3% context.put("quickDeduction", 0); // 个人所得税速算扣除数为 0 QLExpress qlExpress = qlExpressComponent.getQLExpress(); Object result = qlExpress.execute(expression, context, null, true, false); return Double.parseDouble(result.toString()); }QLExpress 3.x版本的qlExpress.execute()办法的参数阐明: ...

May 15, 2023 · 1 min · jiezi

关于springboot:Springboot3微服务实战12306高性能售票系统相逢何必曾相识

download:Springboot3+微服务实战12306高性能售票零碎莫辞更坐弹一曲音乐,古琴,传统文化莫辞更是中国现代文人雅士中的代表人物之一,他是一位喜好古琴的文艺青年。据史料记录,莫辞更经常在宴会上弹奏古琴,给人们带来美好的音乐享受。其中最有名的就要数他“更坐弹一曲”的故事了。 相传有一次,莫辞更加入了一个宴会,过后的氛围非常热烈,人们喝着酒、谈着天。突然间,有人向莫辞更提出了一个挑战:“你能一边弹古琴,一边吟诗吗?”莫辞更并不慌乱,他微笑着承受了这个挑战,而后开始演奏起古琴来。他的指尖轻捷地拨动着琴弦,音乐随之流淌而出,像一朵绽开的花,漂亮而动人。同时,他还口吟着本人创作的诗歌,将音乐与诗意完满联合在一起。 这一幕场景,让在场的众人为之倾倒。他们惊叹于莫辞更的琴艺、诗才和气派,也由衷地感触到了中国传统文化的博大精深。 莫辞更“更坐弹一曲”的故事,至今仍被前人传颂不衰。这个故事通知咱们,艺术能够逾越时空的界线,它是人类智慧和理性的结晶。古琴作为中国传统音乐的代表,有着博大精深的历史渊源和独特的韵味,而莫辞更则将其演奏得酣畅淋漓,彰显出了中国文化的魅力与底蕴。 在当今社会,咱们应该更加关注和弘扬传统文化,让这些古老而神秘的艺术模式在古代焕发新的光辉。同时,咱们也要向莫辞更这样的前辈学习,用本人的才华和致力去发明属于本人的经典,为传统文化的倒退奉献本人的力量。

May 14, 2023 · 1 min · jiezi

关于springboot:SpringBoot-自定义全局异常捕获

SpringBoot 如何自定义异样类?全局对立解决异样的形式是什么?明天教大家应用@RestControllerAdvice和@ExceptionHandler注解定义全局异样捕捉以及自定义异样。 自定义异样类首先申明一个自定义异样类, 代码如下:/** * 自定义异样类,可依据需要本人增加属性和办法 */public class CustomException extends RuntimeException { public CustomException() { super(); } public CustomException(String message) { super(message); }}更多内容:http://www.javacorn.com/springboot/exception-handler.html

May 11, 2023 · 1 min · jiezi

关于springboot:SpringBoot-在线协同办公小程序开发-全栈式项目实战

download:SpringBoot 在线协同办公小程序开发 全栈式我的项目实战在现代,文人雅士经常被称为“风流”,他们谋求自在、优雅的生存形式,并通过诗歌、书画等艺术模式表白本人的情感。这种生存形式也被称为“风月”,其中“风”指的是自在洒脱,而“月”则代表着柔美浪漫。 生存与习惯现代文人雅士的生存形式非常非凡,他们通常不从事官员或商业活动,而是依附家族财产或私人支出来维持生计。他们喜爱在花园、湖泊等自然环境中漫步、吟咏,并且会举办文艺团聚和诗会来交换和展现本人的才华。此外,文人雅士还有一些独特的生活习惯,例如衣着皮鞋、长袍和头巾等装束,以及应用牙刷清洁口腔等。 情感与恋情文人雅士通常对自在、兽性和真谛等价值观有着独特的认识。他们强调集体情感和内心世界,谋求自由恋爱和婚姻,拥护封建礼教的解放。在他们的诗歌和书信中,经常出现对于恋情、友情、离别等主题的表白。因为文人雅士通常来自富裕家庭,所以他们也会在婚姻和恋情方面比拟凋谢和自在。 艺术与创作文人雅士的艺术创作受到了天然和集体情感的影响。他们喜爱通过诗歌、书画等模式来表白本人的思维和情感,并且谋求独特、自在的格调和体现形式。在诗歌创作方面,文人雅士通常重视韵律和节奏,而在书画方面,则重视笔墨、构图和意境等方面的体现。 总之,现代文人雅士的生存形式和情感表达方式都非常非凡和独特。他们通过“风月”、“情调”等形式来表白本人的思维和情感,这也成为了中国文化中不可或缺的一部分。

May 11, 2023 · 1 min · jiezi

关于springboot:SpringBoot定义优雅全局统一Restful-API-响应框架四

如果没有看后面几篇文章请先看后面几篇 SpringBoot定义优雅全局对立Restful API 响应框架 SpringBoot定义优雅全局对立Restful API 响应框架二 SpringBoot定义优雅全局对立Restful API 响应框架三 目前咱们如同仿佛解决所有问题,达到了咱们现实的成果如下 然而在业务谬误返回时候不太现实如下 没有必要返回 reuqest和errorMsg 还有如果业务非常复杂的时候,会不会呈现错误码调配应用凌乱和反复问题这个问题应该如何防止和解决呢?这个时候我想到 应用业务谬误常量来代替错误码,这样更加见字识意, 进一步形象谬误常量公共接口模块 package cn.soboys.springbootrestfulapi.common.error;import java.util.List;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/5/9 20:14 * @webSite https://github.com/coder-amiao * 定义谬误常量 代替错误码,防止业务简单错误码调配反复等问题 */public interface CommonErrorConstant { /** * 公共错误码定义 */ public static final String InvalidRequest = "InvalidRequest"; public static final String InvalidArgument = "InvalidArgument"; public static final String NotFound = "NotFound"; public static final String UnknownError = "UnknownError"; public static final String OK = "OK"; public static final String FAIL = "FAIL"; /** * 其余自定义业务错误码 */}通用错误码 ...

May 10, 2023 · 2 min · jiezi

关于springboot:Could-not-initialize-class-netsfcglibbeansBeanMapGenerator

#### 问题背景我的项目应用springboot整合easyexcel文件导出时报错Could not initialize class net.sf.cglib.beans.BeanMap$Generator easyexcel 版本为 3.0.5springboot 版本为 2.3.12 #### 解决方案调整pom依赖为以下 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.0.5</version> <exclusions> <exclusion> <groupId>cglib</groupId> <artifactId>cglib</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency>

May 10, 2023 · 1 min · jiezi

关于springboot:springboot访问静态页面

一、引入依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>二、动态资源地位以及优先级1.地位 static目录:css、js、图片等templates目录:html页面(templates目录下的html页面不能间接拜访,须要通过服务器外部进行拜访,能够防止无权限的用户间接拜访到隐衷页面,造成信息泄露)2.优先级 spring boot默认将/**动态资源拜访映射到以下目录: classpath:/staticclasspath:/publicclasspath:/resourcesclasspath:/META-INF/resources 这四个目录的拜访优先级:META-INF/resources > resources > static > public拜访门路与springboot.mvc.static-path-pattern、templates下文件夹等无关 三、编写Controller1.应用@Controller,不能应用@RestController 因为@RestController返回的是@ResponseBody的json数据,且不走SpringMVC的视图解析流程,所以跳不到html那里四、前端打包资源重定向应用vue等框架打包的单页面资源,能够应用相似{module}-web的拜访门路,并且在controller中应用通配门路{modele}-web/**指向index.html。

May 6, 2023 · 1 min · jiezi

关于springboot:聊聊Spring-Boot几个版本的区别

序本文次要钻研一下Spring Boot 2.7, 3.x这几个版本的区别 Spring Boot 2Spring Boot 2.0在2018年2月28日公布,Spring Boot 2.7是2.x的最初一个公布版本,该版本的开源将于2023年11月进行反对,商业反对可延长到2025年2月 从2.6迁徙到2.7flyway从8.0更新到了8.5H2更新到了2.1.120MSSQL driver从v9更新到了v10OkHttp3将不再反对,改为反对OkHttp4embedded mongo3.4不再反对Hazelcast 3.0不再被反对camelCase格调的metric tag将被重命名到lower-case并且以.来宰割降级Spring Security到5.7版本,废除了WebSecurityConfigurerAdapterrequestMappingHandlerMapping这个bean不再被标记为@Primary,因而注入的时候能够应用List<RequestMappingHandlerMapping>MySQL JDBC driver的8.0.31的坐标是com.mysql:mysql-connector-j以及mysql:mysql-connector-java,然而从8.0.32开始只公布到了com.mysql:mysql-connector-j这个坐标,而Spring Boot2.7.8版本更新该依赖到8.0.32版本auto-configuration和management context的发现机制产生了变动,它们不在spring.factories中注册了,改为在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports以及META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports中申明,而且之前的逗号分隔改为换行分隔新引入了@AutoConfiguration注解,用于顶级的auto-configuration,如果是内嵌的或者是被@AutoConfiguration注解的class援用的则持续应用@Configuration注解maven和gradle插件当初都反对了Podmanauto-configuration新增了对Cache2k的反对Spring Boot 3Spring Boot 3版本于2022年11月24日公布,它是Spring Boot的下一个大版本,基于Spring Framework 6.0,而且要求Java最低版本为Java17。Spring Framework 6.0于2022年11月16日公布,是Spring Framework的下一个大版本,该版本要求Java最低版本为Java17,而且迁徙到了Jakarta EE 9+版本,应用了jakarta.*替换掉了javax.*,反对了Tomcat 10.1,Hibernate ORM 6.1。另外开始反对AOT编译以及后续公布的协程。Jakarta EE 10应用了Servlet 6.0及JPA 3.1标准不再反对Image Banner日志的日期格局从以前的yyyy-MM-dd HH:mm:ss.SSS变更为yyyy-MM-dd’T’HH:mm:ss.SSSXXX,能够应用logging.pattern.dateformat属性进行更改不再反对auto-configuration注册到spring.factories尾斜杠默认不被反对,如果没有显式指定将返回404,能够通过configurer.setUseTrailingSlashMatch(true)来开启server.max-http-header-size被废除,改为应用server.max-http-request-header-sizeactuator endpoints开启加密机制,默认连key也会被加密,能够通过management.endpoint.env.show-values及management.endpoint.configprops.show-values来进行配置legacy application.propertisSpring Boot 2.4版本变更了application.properties以及application.yaml的加载形式,能够通过设置spring.config.use-legacy-process为true来复原以前的行为,不过在3.0版本legacy的解决形式不再被反对 如果仅仅是简略的application.properties以及application.yaml,则该变动没有影响,影响到的是带profile的写法具体见Spring Boot Config Data Migration GuidePathPatternParserSpring MVC提供了AntPathMatcher及PathPatternParser两种解析pattern的形式,在2.6版本默认应用PathPatternParser,通过spring.mvc.pathmatch.matching-strategy能够去扭转,后续举荐应用PathPatternParser,因为它的性能更好。 spring-boot-properties-migratorSpring Boot 3.0版本重命名或者移除了一些配置属性,能够通过spring-boot-properties-migrator来剖析和兼容 Spring Cloud版本Hoxton版本之后采纳日期的命名形式Spring Cloud 2020.0(Ilford版本)从2020.0.0到2020.0.6一共公布了7个版本,其中2020.0.2要求Spring Boot 2.4.3版本这个版本次要是从spring-cloud-netflix移除了一些组件,比方ribbon,hystrix,turbine兼容Spring Boot 2.4.x及2.5.x版本Spring Cloud 2021.0(Jubilee版本)从2021.0.0到2021.0.7一共公布了8个版本从2021.0.3版本开始次要是兼容Spring Boot 2.7.0及2.6.x版本Spring Cloud 2022.0(Kilburn版本)要求Spring Boot版本为3.xSpring Cloud Alibaba版本2.2.x对应的是 Spring Cloud Hoxton 与 Spring Boot 2.2.x,最低反对 JDK 1.8 ...

May 5, 2023 · 1 min · jiezi

关于springboot:SpringBoot定义优雅全局统一Restful-API-响应框架三

咱们目前曾经设计出了,蕴含全局响应,异样谬误响应进行了对立返回。然而谬误内容咱们设计的比拟含糊对立,还能够进行细化这样更有利于定位谬误 当咱们须要调用Http接口时,无论是在Web端还是挪动端,都有可能遇到各种谬误,例如参数缺失、类型谬误、零碎谬误等。为了标准错误信息的返回,咱们须要定义一个对立的接口谬误返回值。通过对接口谬误返回值的对立设计,咱们能够标准调用方对各种不同谬误的解决形式,并提供更加具体、精确的谬误提醒,同时也帮忙后端实现接口返回值的规范化设计。因而,接口谬误返回值的设计不仅仅是对错误信息的规范化解决,还波及到业务上的谬误设计。这样的设计能够无效地进步接口的应用效率和可维护性。 错误码定义依据 http stats 谬误通常能够分为以下几大类 200:申请胜利400:申请参数谬误401:未受权拜访403:示意禁止拜访资源。404:示意未找到资源。500:示意服务器外部谬误。错误码的设计,能够借用http错误码+三位api自定义错误码 一共是6位数字,具体每个模块代表什么能够依据你本人的业务逻辑,定义不同数字,位数对应不同模块 对应谬误格局如下 谬误接口package cn.soboys.springbootrestfulapi.common.error;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/5/2 21:33 * @webSite https://github.com/coder-amiao * 错误码接口,凡各模块错误码枚举类,皆须为此接口的子类型 */public interface ErrorCode { Integer getCode(); String getMessage(); boolean getSuccess();}自定义谬误实现枚举package cn.soboys.springbootrestfulapi.common.error;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/5/2 21:36 * @webSite https://github.com/coder-amiao */public enum CommonErrorCode implements ErrorCode { NOT_FOUND(false, 404, "接口不存在"), FORBIDDEN(false, 403, "资源回绝拜访"), UNAUTHORIZED(false, 401, "未认证(签名谬误)"), INTERNAL_SERVER_ERROR(false, 500, "服务网络不可用"), PARAM_ERROR(false, 110001, "参数谬误"); CommonErrorCode(Boolean success, Integer code, String message) { this.success = success; this.code = code; this.message = message; } /** * 响应是否胜利 */ private Boolean success; /** * 响应状态码 */ private Integer code; /** * 响应信息 */ private String message; @Override public Integer getCode() { return code; } @Override public String getMessage() { return message; } @Override public boolean getSuccess() { return success; }}全局异样错误处理package cn.soboys.springbootrestfulapi.common.exception;import cn.hutool.core.collection.CollectionUtil;import cn.soboys.springbootrestfulapi.common.error.CommonErrorCode;import cn.soboys.springbootrestfulapi.common.resp.R;import org.springframework.context.support.DefaultMessageSourceResolvable;import org.springframework.validation.BindException;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestControllerAdvice;import org.springframework.web.context.request.WebRequest;import javax.validation.ConstraintViolation;import javax.validation.ConstraintViolationException;import java.util.List;import java.util.stream.Collectors;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/4/29 00:21 * @webSite https://github.com/coder-amiao * 对立异样处理器 */@RestControllerAdvicepublic class GlobalExceptionHandler { /** * 通用异样解决办法 **/ @ExceptionHandler(Exception.class) @ResponseBody public R error(Exception e, WebRequest request) { e.printStackTrace(); return R.setResult(CommonErrorCode.INTERNAL_SERVER_ERROR) .request(request.getDescription(true)) .errorMsg(e.getMessage()); } /** * 解决 form data形式调用接口对象参数校验失败抛出的异样 */ @ExceptionHandler(BindException.class) @ResponseBody public R BindExceptionHandler(BindException e) { String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining()); return R.failure().code(CommonErrorCode.PARAM_ERROR.getCode()).message(message); } /** * 解决Get申请中 验证门路中 单个参数申请失败抛出异样 * @param e * @return */ @ExceptionHandler(ConstraintViolationException.class) public R ConstraintViolationExceptionHandler(ConstraintViolationException e) { String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining()); return R.failure().code(CommonErrorCode.PARAM_ERROR.getCode()).message(message); } /** * 解决 json 申请体调用接口对象参数校验失败抛出的异样 */ @ExceptionHandler(MethodArgumentNotValidException.class) public R jsonParamsException(MethodArgumentNotValidException e) { BindingResult bindingResult = e.getBindingResult(); String msg=";"; for (FieldError fieldError : bindingResult.getFieldErrors()) { msg = String.format("%s%s;", fieldError.getField(), fieldError.getDefaultMessage())+msg; } return R.failure().code(CommonErrorCode.PARAM_ERROR.getCode()).message(msg); } /** * 自定义异样解决办法 * * @param e * @return */ @ExceptionHandler(BusinessException.class) @ResponseBody public R error(BusinessException e) { e.printStackTrace(); return R.failure().message(e.getMessage()).code(e.getCode()); }}筹备从零做一套本人的开发脚手架模板 ,关注公众 程序员三时 ...

May 4, 2023 · 2 min · jiezi

关于springboot:容器

1. 创立容器1.1 (举荐)加载类门路下的配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");1.2 从文件系统下加载配置文件ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");总结 2. 获取bean2.1 强制转化 BookDao bookDao = (BookDao) ctx.getBean("bookDao");2.2 将强制转换环节改为参数传入BookDao bookDao = ctx.getBean("bookDao",BookDao.class);2.3 按类型找bean BookDao bookDao = ctx.getBean(BookDao.class);总结 3. 容器类层次结构4. BeanFactory

May 3, 2023 · 1 min · jiezi

关于springboot:数据源对象管理

不实用properties的数据源对象治理办法(繁琐):首先从Maven仓库https://mvnrepository.com/ 查问要导入的依赖例如这里查问c3p0点击第一个或第二个 点击最新的版本号 将下列代码放入pom文件中 在applicationContext.xml文件中配置相干的bean用于数据源对象治理外面的property都有哪些, 须要咱们具体情况具体分析, 个别操作为ctrl点进去,应用快捷键ctrl+f12 查问相干字段 总结不必properties文件, 间接手动配置的办法不仅繁琐, 而且耦合度高, 不利于前期代码保护上面引出第二种办法, 加载properties文件 加载properties文件1.开拓空间图中3个灰色字段为批改后开拓空间, 次要复制了原来下面一行的代码, 并将bean批改为context 2.应用context空间加载properties文件 3.应用属性占位符${}读取properties文件中的属性属性占位符 ${}.两个大括号两头填咱们须要的字段 这样properties文件中的字段就传入了bean中, 总结: 同时加载多个properties文件, 两头应用逗号, 分隔 或者应用星号, 加载所有properties文件(不够标准) (举荐,标准)classpath星号:星号.properties 而不是星号.properties,也不是classpath:*.properties(tm的我该怎么打2个星号或者一个星号进去, 思否默认星号是歪斜标记, 服了)一个星号和两个星号的区别classpath:*.properties 仅从以后工程类门路中读取classpath*:*.properties 从以后工程类门路和所有依赖的jar包中读取所有properties文件总结2

May 3, 2023 · 1 min · jiezi

关于springboot:SpringBoot定义优雅全局统一Restful-API-响应框架二

这里解决之前留下来的问题,当程序没有失常返回时候 就是程序因为运行时异样导致的后果,有些异样咱们可,能无奈提前预知,不能失常走到咱们return的R对象返回。这个时候该如何解决 在SpringBoot中,能够应用@ControllerAdvice注解来启用全局异样解决。通过应用@ControllerAdvice注解,能够捕捉应用程序中的所有异样,从而实现对立的异样解决。如果要自定义异样解决办法,能够应用@ExceptionHandler注解,并指定要捕捉的异样类型。这样就能够对指定的异样进行对立的解决。因而,通过@ControllerAdvice和@ExceptionHandler注解的组合,能够实现全局的异样解决。 代码示列 package cn.soboys.springbootrestfulapi.common.exception;import cn.soboys.springbootrestfulapi.common.resp.R;import cn.soboys.springbootrestfulapi.common.resp.ResultCodeEnum;import org.springframework.context.support.DefaultMessageSourceResolvable;import org.springframework.validation.BindException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.validation.ConstraintViolation;import javax.validation.ConstraintViolationException;import java.util.stream.Collectors;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/4/29 00:21 * @webSite https://github.com/coder-amiao * 对立异样处理器 */@RestControllerAdvicepublic class GlobalExceptionHandler { /** * 通用异样解决办法 **/ @ExceptionHandler(Exception.class) @ResponseBody public R error(Exception e) { e.printStackTrace(); return R.setResult(ResultCodeEnum.INTERNAL_SERVER_ERROR); } /** * 指定异样解决办法 **/ @ExceptionHandler(NullPointerException.class) @ResponseBody public R error(NullPointerException e) { e.printStackTrace(); return R.setResult(ResultCodeEnum.NULL_POINT); } /** * 解决Get申请中 应用@Valid 验证门路中申请实体校验失败后抛出的异样 */ @ExceptionHandler(BindException.class) @ResponseBody public R BindExceptionHandler(BindException e) { String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining()); return R.failure().code(ResultCodeEnum.PARAM_ERROR.getCode()).message(message); } /** * 解决Get申请中 应用@Validated 验证门路中 单个参数申请失败抛出异样 * @param e * @return */ @ExceptionHandler(ConstraintViolationException.class) public R ConstraintViolationExceptionHandler(ConstraintViolationException e) { String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining()); return R.failure().code(ResultCodeEnum.PARAM_ERROR.getCode()).message(message); } /** * 自定义异样解决办法 * * @param e * @return */ @ExceptionHandler(BusinessException.class) @ResponseBody public R error(BusinessException e) { e.printStackTrace(); return R.failure().message(e.getMessage()).code(e.getCode()); }}异样解决,可能缩小代码的反复度和复杂度,有利于代码的保护,并且可能疾速定位到BUG,大大提高咱们的开发效率。 ...

May 3, 2023 · 1 min · jiezi

关于springboot:SpringBoot核心配置全面总结

Spring Boot的外围配置文件用于配置Spring Boot程序,文件名字必须以application开始。这个既是底层源码的强制要求,也是SpringBoot的一种代码规约,有助于在开发层面利于代码标准治理。阐明:以下内容接着i后面的SpringBootCase我的项目进行演示。 1、application. properties外围文件格局:以键值对的形式进行配置,key=value 示例:name=xintu 咱们批改application.properties配置文件。比方批改默认tomcat端口号及我的项目高低文件根。 设置内嵌Tomcat端口号 server.port=8888 设置我的项目上下文根门路,这个在申请的时候须要用到 server.servlet.context-path=/springbootcase 配置结束之后,启动测试。 浏览器输出地址:http://localhost:8888/springbootcase/hello?name=lw , 页面验证后果如下。 2、 application.yml配置文件(举荐配置格调) yml 是一种 yaml 格局的配置文件,次要采纳肯定的空格、换行等格局排版进行配置。格局如下, key: 空格+value, 示意一对键值对。配置YNML时,须要留神以下4点: 1)以空格的缩进来管制层级关系。 2)只有是左对齐的一列数据,都是属于同一层级。 3)空格必须有。 4)属性和值对大小写敏感。server: port: 8888 # 设置内嵌Tomcat端口号 servlet: context-path: /SpringBootCase # 设置我的项目上下文根门路,这个在申请拜访的时候须要用到特点:与 application. properties 相比,yaml更能直观地被计算机辨认,而且容易被人类浏览。 yaml 相似于 xml,然而语法比xml 简洁很多,值与后面的冒号配置项必须要有一个空格, yml 后缀也能够应用 yaml 后缀。当两种格局配置文件同时存在,应用的是 .properties 配置文件,为了演示yml,能够先将其改名,从新运行SpringbootApplication,查看启动的端口及上下文根。 咱们在前面的学习过程中,均应用 .yml格局 。如果想改.properties模式也能够,依照本人喜爱的格调 或 团队约定即可。 3、SpringBoot多环境配置在理论开发的过程中,咱们的我的项目会经验很多的阶段,开发、测试、上线, 尤其时很大厂,在进行一些重要需要迭代时,还会包含预发、灰度等。每个阶段的配置会因利用所依赖的环境不同而不同,例如:数据库配置、缓存配置、依赖第三方配置等,那么这个时候为了不便配置在不同的环境之间切换,SpringBoot提供了多环境profile配置性能。 命名格局:application-环境标识.yml(或 .properties)。上面咱们为每个环境创立3个配置文件,别离命名为:application-dev.yml(开发环境)、application-dev.yml(测试环境)、application-dev.yml(生产环境)。 各配置文件内容如下, application-dev.yml开发环境server: port: 8881 # 设置内嵌Tomcat端口号 servlet: context-path: /springbootcase1 # 设置我的项目上下文根门路,这个在申请拜访的时候须要用到application-test.yml#测试环境server: port: 8883 # 设置内嵌Tomcat端口号 servlet: context-path: /springbootcase3 # 设置我的项目上下文根门路,这个在申请拜访的时候须要用到application-prod.yml#生产环境server: port: 8882 # 设置内嵌Tomcat端口号 servlet: context-path: /springbootcase2 # 设置我的项目上下文根门路,这个在申请拜访的时候须要用到4)总配置文件application.yml进行环境的激活 ...

May 3, 2023 · 2 min · jiezi

关于springboot:Springboot3微服务实战12306高性能售票系统无密

Spring Boot 3+微服务架构download:https://www.sisuoit.com/3813.html随着互联网的一直倒退和技术的不断更新,微服务架构成为了以后最具备前景的架构之一。作为一种基于分布式系统的架构格调,它能够对大型利用进行拆分,使得开发、测试、部署更加容易,并可能进步应用程序的可伸缩性和可维护性。 Spring Framework和Spring Boot作为Java畛域内最风行的框架之一,也逐步向微服务架构方向转变。在本文中,咱们将介绍如何应用最新版本的Spring Boot(即Spring Boot 3.0)构建微服务架构。咱们将从概念动手,逐渐介绍各个组件以及如何实现一个残缺的微服务架构。 微服务架构概述微服务架构是一种基于分布式系统的架构格调,其中应用程序被合成为一组较小的单元,每个单元都有独立的代码库和数据存储。这些单元之间通过轻量级的通信机制进行交互,例如RESTful API或消息传递。 微服务架构有多个长处。首先,因为应用程序被合成为小的单元,每个单元都能够独立开发、测试和部署。这意味着更快的开发和更快的上线速度。其次,因为每个单元都是独立的,因而应用程序具备更好的可伸缩性和可维护性。如果零碎中的某个单元产生故障,能够更容易地定位和修复问题,而不影响整个零碎。 微服务架构也有一些挑战。首先,因为应用程序被拆分为多个单元,因而须要对每个单元进行治理和监控。其次,通信机制可能会导致性能问题,因为每个单元都须要与其余单元进行通信。最初,因为每个单元都有本人的代码库和数据存储,因而数据一致性可能会成为一个问题。 Spring Boot 3+微服务架构组件Spring Boot 3+提供了许多组件来实现微服务架构,其中包含以下外围组件: Spring Cloud EurekaSpring Cloud Eureka是一个服务注册和发现的工具,它能够让应用程序在不同的服务器上运行,并通过相互发现彼此。它应用基于RESTful的通信协议,具备高可用性和可伸缩性。 Spring Cloud ConfigSpring Cloud Config是一个配置管理工具,它能够集中管理应用程序的配置信息,并将其存储在一个Git或SVN仓库中。这让应用程序的配置变得更加容易,同时也不便了配置的版本控制和回滚。 Spring Cloud RibbonSpring Cloud Ribbon是一个负载平衡工具,它能够将申请调配到多个服务实例之间,从而进步应用程序的可伸缩性和可用性。它反对多种负载平衡算法,并且能够与Eureka等服务注册和发现工具一起应用。 Spring Cloud FeignSpring Cloud Feign是一个申明式的REST客户端,它能够简化应用程序与其余服务之间的交互。通过定义接口并应用Feign注解,咱们能够轻松地发送HTTP申请和接管响应,而不须要编写大量的样板代码。 Spring Cloud HystrixSpring Cloud Hystrix是一个容错工具,它能够解决分布式系统中的故障和提早。它通过实现断路器模式来避免级联故障,并提供了监控和度量性能,以便疾速诊断和修复问题。 Spring Cloud SleuthSpring Cloud Sleuth是一个分布式跟踪工具,它能够帮忙咱们跟踪申请在微服务架构中的流传状况。它能够生成惟一的跟踪ID,并将其增加到申请头中,从而跟踪申请在整个零碎中的流动。 实现一个根本的微服务架构为了演示如何应用Spring Boot 3+构建微服务架构,这里咱们将创立一个蕴含两个微服务的示例应用程序:一个用于用户治理,另一个用于订单治理。 首先,咱们须要创立两个Spring Boot我的项目。关上终端并别离运行以下命令: 创立用户治理微服务项目spring init --dependencies=web,actuator,eureka,eureka-server,hystrix-dashboard,user-service user-service 创立订单治理微服务项目spring init --dependencies=web,actuator,eureka,eureka-server,hystrix-dashboard,feign,order-service order-service在下面的命令中,咱们应用了spring init命令来创立两个Spring Boot我的项目。其中,user-service我的项目蕴含了用户治理微服务所需的依赖项,而order-service我的项目则蕴含了订单治理微服务所需的依赖项。 接下来,咱们须要配置Eureka服务器和客户端。关上user-service和order-service我的项目的application.properties文件,增加以下配置: Eureka服务器配置eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ 应用程序名称spring.application.name=user-service # 对于订单治理微服务,将此改为order-service在下面的配置中,咱们配置了应用程序向Eureka服务器注册,并指定了默认的Eureka服务器地址。同时,咱们还为应用程序命名,以便其余微服务能够找到它。 接下来,咱们须要创立一个RESTful API来解决用户或订单相干的操作。 ...

May 2, 2023 · 1 min · jiezi

关于springboot:SpringBoot定义优雅全局统一Restful-API-响应框架

如果当初有一个Java我的项目,老板让你做我的项目组长,定义我的项目根底框架,零碎技术架构选型,你应该如何设计一个标准的对立的Restful API 响应框架呢 思考目前我的项目开发,都是基于前后端拆散模式开发的,基于后端模板引擎那一套,可能曾经不实用一些我的项目开发流程,和当下开发模式了,尤其在要写比拟大型项目,前后端我的项目拆分,团队共同开发那是必不可少的 目前的前后端开发大部分数据的传输格局都是json,因而定义一个对立标准的数据格式有利于前后端的交互与UI的展现。 返回的对立接口模式应该蕴含这些内容 是否响应胜利响应状态码状态码形容响应数据接口调用工夫其余标识符依照这些咱们能够定义对立的规范后果返回 响应枚举前三者能够定义为 success,code,message package cn.soboys.springbootrestfulapi.common.resp;import lombok.Data;import lombok.Getter;import org.springframework.web.bind.annotation.GetMapping;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/4/28 22:39 * @webSite https://github.com/coder-amiao * 响应后果枚举 */@Getterpublic enum ResultCodeEnum{ SUCCESS(true, 200, "胜利"), FAIL(false, 400, "申请失败"), NOT_FOUND(false, 404, "接口不存在"), FORBIDDEN(false, 403, "资源回绝拜访"), UNAUTHORIZED(false, 401, "未认证(签名谬误)"), INTERNAL_SERVER_ERROR(false, 500, "服务器外部谬误"), NULL_POINT(false, 200002, "空指针异样"), PARAM_ERROR(false, 200001, "参数谬误"); /** * 响应是否胜利 */ private Boolean success; /** * 响应状态码 */ private Integer code; /** * 响应信息 */ private String message; ResultCodeEnum(Boolean success, Integer code, String message) { this.success = success; this.code = code; this.message = message; }}对立后果类内部返回调用类对立的后果办法 success,failure 因而结构器公有内置静态方法,间接返回对象便于自定义对立后果信息,应用链式编程,返回对象类自身 return this响应数据为json格局,可定义为JsonObject或Map模式package cn.soboys.springbootrestfulapi.common.resp;import lombok.Data;import java.util.HashMap;import java.util.Map;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/4/28 22:47 * @webSite https://github.com/coder-amiao * 对立响应后果解决 应用链式编程 返回类自身 */@Datapublic class R { private Boolean success; private Integer code; private String message; /** * 接口申请工夫戳 */ private Long timestamp; private Map<String, Object> data = new HashMap<>(); private R setSuccess(Boolean success) { this.success = success; return this; } private R setMessage(String message) { this.message = message; return this; } private R setData(Map<String, Object> data) { this.data = data; return this; } private R setCode(Integer code) { this.code = code; return this; } private R() { } private R(Long timestamp) { this.timestamp = timestamp; } /** * 通用返回胜利 * * @return */ public static R success() { return new R(System.currentTimeMillis()) .setSuccess(ResultCodeEnum.SUCCESS.getSuccess()) .setCode(ResultCodeEnum.SUCCESS.getCode()) .setMessage(ResultCodeEnum.SUCCESS.getMessage()); } /** * 通用返回失败 * * @return */ public static R failure() { return new R(System.currentTimeMillis()) .setSuccess(ResultCodeEnum.FAIL.getSuccess()) .setCode(ResultCodeEnum.FAIL.getCode()) .setMessage(ResultCodeEnum.FAIL.getMessage()); } /** * 设置后果,形参为后果枚举 * * @param result * @return */ public static R setResult(ResultCodeEnum result) { return new R(System.currentTimeMillis()) .setSuccess(result.getSuccess()) .setCode(result.getCode()) .setMessage(result.getMessage()); } // 自定义返回数据 public R data(Map<String, Object> map) { return this.setData(map); } // 通用设置data public R data(String key, Object value) { this.data.put(key, value); return this; } // 自定义状态信息 public R message(String message) { return this.setMessage(message); } // 自定义状态码 public R code(Integer code) { return this.setCode(code); } // 自定义返回后果 public R success(Boolean success) { return this.setSuccess(success); }}管制层调用返回package cn.soboys.springbootrestfulapi.controller;import cn.soboys.springbootrestfulapi.common.resp.R;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;import java.util.Map;/** * @author 公众号 程序员三时 * @version 1.0 * @date 2023/4/28 23:58 * @webSite https://github.com/coder-amiao */@RestControllerpublic class IndexController { @GetMapping("/index") public R index() { Map m = new HashMap(); m.put("name", "Tom"); m.put("age", 25); m.put("sex", "男"); return R.success().data(m); } @GetMapping("/home") public R home() { Student s = new Student(); s.setUserName("Tom"); s.setBalance(2229891.0892); return R.success().data("user", s).message("查问用户详情信息"); } /** * 异样返回模仿 * * @return */ @GetMapping("/exception") public R exception() { Map m = null; m.put("name", "Jack"); return R.success().data("user", m).message("查问用户详情信息"); }} ...

May 2, 2023 · 2 min · jiezi

关于springboot:SpringBoot高频面试题

Springboot的长处内置servlet容器,不须要在服务器部署 tomcat。只须要将我的项目打成 jar 包,应用 java -jar xxx.jar一键式启动我的项目SpringBoot提供了starter,把罕用库聚合在一起,简化简单的环境配置,疾速搭建spring应用环境能够疾速创立独立运行的spring我的项目,集成支流框架准生产环境的运行利用监控SpringBoot 中的 starter 到底是什么 ?starter提供了一个自动化配置类,个别命名为 XXXAutoConfiguration ,在这个配置类中通过条件注解来决定一个配置是否失效(条件注解就是 Spring 中本来就有的),而后它还会提供一系列的默认配置,也容许开发者依据理论状况自定义相干配置,而后通过类型平安的属性注入将这些配置属性注入进来,新注入的属性会代替掉默认属性。正因为如此,很多第三方框架,咱们只须要引入依赖就能够间接应用了。 运行 SpringBoot 有哪几种形式?打包用命令或者者放到容器中运行用 Maven/Gradle 插件运行间接执行 main 办法运行SpringBoot 罕用的 Starter 有哪些?spring-boot-starter-web :提供 Spring MVC + 内嵌的 Tomcat 。spring-boot-starter-data-jpa :提供 Spring JPA + Hibernate 。spring-boot-starter-data-Redis :提供 Redis 。mybatis-spring-boot-starter :提供 MyBatis 。本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 Spring Boot 的外围注解是哪个?启动类下面的注解是@SpringBootApplication,它也是 Spring Boot 的外围注解,次要组合蕴含了以下 3 个注解: @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的性能。@EnableAutoConfiguration:关上主动配置的性能,也能够敞开某个主动配置的选项,如敞开数据源主动配置性能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。@ComponentScan:Spring组件扫描。主动配置原理SpringBoot实现主动配置原理图解: 在 application.properties 中设置属性 debug=true,能够在控制台查看已启用和未启用的主动配置。 @SpringBootApplication是@Configuration、@EnableAutoConfiguration和@ComponentScan的组合。 ...

May 1, 2023 · 3 min · jiezi

关于springboot:排查线上CPU飙升原因

线上资源cpu飙升是咱们工作中常见的问题,一篇文章搞定排查办法一、问题复现当初我有两个接口,代码如下 @RestControllerpublic class CPUCheck { @RequestMapping("/hello") public String helloWorld(){ return "hello World"; } @RequestMapping("/run") public void run(){ while (true){ } }}代码很简略 接口1“/hello” 返回“hello World”,接口2“/run” 进入死循环,这样就保障了拜访接口2cpu升高。 二、测试咱们将我的项目打包部署在服务器上,并启动测试接口 curl http://localhost:9901/thing-test/hello测试接口2,并查看cpu状况 curl http://localhost:9901/thing-test/run 三、排查通过top命令能够查看到有一个java过程占用cpu资源异样获取pid为32306通过命令查问tid 命令:ps -mp 【pid】 -o THREAD,tid,time实例:ps -mp 32306 -o THREAD,tid,time能够看到引起cpu异样的tid是32327因为当初的tid32327是十进制的,须要将其转化为十六进制 命令:printf "%x\n" 【十进制tid】实例:printf "%x\n" 32327依据pid 和 tid查问导致cpu飙升的代码 命令:jstack 【10进制pid】 | grep 【16进制tid】 -A 20实例:jstack 32306 | grep 7e47 -A 20END.....

April 27, 2023 · 1 min · jiezi

关于springboot:个人学习系列-SpringBoot整合devtools实现热部署

之前钻研过JRebel来实现代码热部署,可是前面发现会呈现各种激活生效的事件,所以当初看一下devtools部署。1. 前提Spring Boot 推出了Spring Boot devtool的工具来不便咱们更加疾速的开发和测试Spring Boot应用程序。 2. 开发环境springboot版本:3.0.6IDEA版本:2023.1 3. 原理spring-boot-devtools应用了两个类加载器ClassLoader,一个ClassLoader加载不会产生更改的类(第三方jar包),另一个ClassLoader(restart ClassLoader)加载会更改的类(自定义的类)。后盾启动一个文件监听线程(File Watcher),监测的目录中的文件产生变动时, 原来的restart ClassLoader被抛弃,将会从新加载新的restart ClassLoader。因为文件变动后,第三方jar包不再从新加载,只加载自定义的类,加载的类比拟少,所以重启比拟快。 4. 实现步骤4.1 在pom.xml中增加依赖<!-- devtools热部署依赖 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <!-- 避免将依赖传递到其余模块中 --> <optional>true</optional> <!-- 只在运行时起作用,打包时不打进去 --> <scope>runtime</scope></dependency>4.2 IDEA进行相干配置 这样就能够了,高兴的进行代码编译吧!

April 27, 2023 · 1 min · jiezi

关于springboot:如果不知道这4种缓存模式敢说懂缓存吗

概述在零碎架构中,缓存堪称提供零碎性能的最简略办法之一,略微有点开发教训的同学必然会与缓存打过交道,最起码也实际过。如果应用切当,缓存能够缩小响应工夫、缩小数据库负载以及节省成本。但如果缓存使用不当,则可能呈现一些莫名其妙的问题。在不同的场景下,所应用的缓存策略也是有变动的。如果在你的印象和教训中,缓存还只是简略的查问、更新操作,那么这篇文章真的值得你学习一下。在这里,为大家系统地解说4种缓存模式以及它们的应用场景、流程以及优缺点。缓存策略的抉择实质上来讲,缓存策略取决于数据和数据拜访模式。换句话说,数据是如何写和读的。例如: 零碎是写多读少的吗?(例如,基于工夫的日志)数据是否是只写入一次并被读取屡次?(例如,用户配置文件)返回的数据总是惟一的吗?(例如,搜寻查问) 抉择正确的缓存策略才是进步性能的要害。罕用的缓存策略有以下五种: Cache-Aside Pattern:旁路缓存模式Read Through Cache Pattern:读穿透模式Write Through Cache Pattern:写穿透模式 Write Behind Pattern:又叫Write Back,异步缓存写入模式 上述缓存策略的划分是基于对数据的读写流程来辨别的,有的缓存策略下是应用程序仅和缓存交互,有的缓存策略下应用程序同时与缓存和数据库进行交互。因为这个是策略划分比拟重要的一个维度,所以在后续流程学习时大家须要特地注意一下。Cache AsideCache Aside是最常见的缓存模式,应用程序可间接与缓存和数据库对话。Cache Aside可用来读操作和写操作。读操作的流程图: 读操作的流程: 应用程序接管到数据查问(读)申请; 应用程序所需查问的数据是否在缓存上: 如果存在(Cache hit),从缓存上查问出数据,间接返回;如果不存在(Cache miss),则从数据库中检索数据,并存入缓存中,返回后果数据; 这里咱们须要注意一个操作的边界,也就是数据库和缓存的操作均由应用程序间接进行操作。写操作的流程图: 这里的写操作,包含创立、更新和删除。在写操作的时候,Cache Aside模式是先更新数据库(增、删、改),而后间接删除缓存。Cache Aside模式能够说实用于大多数的场景,通常为了应答不同类型的数据,还能够有两种策略来加载缓存: 应用时加载缓存:当须要应用缓存数据时,从数据库中查问进去,第一次查问之后,后续申请从缓存中取得数据;预加载缓存:在我的项目启动时或启动后通过程序预加载缓存信息,比方”国家信息、货币信息、用户信息,新闻信息“等不是常常变更的数据。 Cache Aside实用于读多写少的场景,比方用户信息、新闻报道等,一旦写入缓存,简直不会进行批改。该模式的毛病是可能会呈现缓存和数据库双写不统一的状况。Cache Aside也是一个规范的模式,像Facebook便是采纳的这种模式。Read ThroughRead-Through和Cache-Aside很类似,不同点在于程序不须要关注从哪里读取数据(缓存还是数据库),它只须要从缓存中读数据。而缓存中的数据从哪里来是由缓存决定的。Cache Aside是由调用方负责把数据加载入缓存,而Read Through则用缓存服务本人来加载,从而对利用方是通明的。Read-Through的劣势是让程序代码变得更简洁。这里就波及到咱们下面所说的应用程序操作边界问题了,间接来看流程图: 在上述流程图中,重点关注一下虚线框内的操作,这部分操作不再由应用程序来解决,而是由缓存本人来解决。也就是说,当利用从缓存中查问某条数据时,如果数据不存在则由缓存来实现数据的加载,最初再由缓存返回数据后果给应用程序。Write Through在Cache Aside中,应用程序须要保护两个数据存储:一个缓存,一个数据库。这对于应用程序来说,有一些繁琐。Write-Through模式下,所有的写操作都通过缓存,每次向缓存中写数据时,缓存会把数据长久化到对应的数据库中去,且这两个操作在一个事务中实现。因而,只有两次都写胜利了才是最终写胜利了。害处是有写提早,益处是保障了数据的一致性。能够了解为,应用程序认为后端就是一个繁多的存储,而存储本身保护本人的Cache。因为程序只和缓存交互,编码会变得更加简略和整洁,当须要在多处复用雷同逻辑时这点就变得分外显著。 当应用Write-Through时,个别都配合应用Read-Through来应用。Write-Through的潜在应用场景是银行零碎。Write-Through实用状况有: 须要频繁读取雷同数据不能忍耐数据失落(绝对Write-Behind而言)和数据不统一 在应用Write-Through时要特地留神的是缓存的有效性治理,否则会导致大量的缓存占用内存资源。甚至无效的缓存数据被有效的缓存数据给革除掉。Write-BehindWrite-Behind和Write-Through在”程序只和缓存交互且只能通过缓存写数据“这方面很类似。不同点在于Write-Through会把数据立刻写入数据库中,而Write-Behind会在一段时间之后(或是被其余形式触发)把数据一起写入数据库,这个异步写操作是Write-Behind的最大特点。数据库写操作能够用不同的形式实现,其中一个形式就是收集所有的写操作并在某一时间点(比方数据库负载低的时候)批量写入。另一种形式就是合并几个写操作成为一个小批次操作,接着缓存收集写操作一起批量写入。异步写操作极大的升高了申请提早并加重了数据库的累赘。同时也放大了数据不统一的。比方有人此时间接从数据库中查问数据,然而更新的数据还未被写入数据库,此时查问到的数据就不是最新的数据。小结不同的缓存模式有不同的考量点和特色,依据应用程序需要场景的不同,须要灵便的抉择适配的缓存模式。在实际的过程中往往也是多种模式相结合来应用。

April 25, 2023 · 1 min · jiezi

关于springboot:SpringBoot22升级到279遇到的问题及解决方案总结

开始Spring Boot 最新版本曾经到了3.1.x版本,线上目前用的2.1版本官网曾经进行反对,目前打算先做肯定的技术预研,在不降级JDK的前提下,削减降级坡度,事后降级到2.7.10版本GA版本。 SpringBoot官网版本反对阐明:(写这边文章时从2.7.9变成了2.7.10) 官网文档:https://spring.io/projects/spring-boot#support 官网Github Release: https://github.com/spring-projects/spring-boot/releases/tag/v2.7.10 spring cloud 版本外面降级jar包,修复logger包的破绽,fastjson破绽也会随着这次降级一道修复 废话不多说,间接开始: 依赖解决与性能降级SpringBoot主包降级咱们将springboot主包从2.1.9.RELEASE 批改为2.7.10. <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.10</version> <relativePath/> </parent>SpringCloud组件降级目前Spring Cloud Alibaba 与cloud 基于spring boot 2.7.10的兼容版本 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.5</version></dependency><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2021.0.5.0</version></dependency>这时候发现SpringCloud被逼在2020版本移除了对Netflix OSS大部分组件的反对 Spring Cloud官网尤其着重指出ribbon、hystrix 和 zuul 从Spring Cloud 2020.0正式版公布后将不再被Spring Cloud反对。在目前最新的Spring Cloud 2020.0中仅仅剩下了Eureka。然而留给Eureka的工夫也不多了。其中ribbon 替换为SpringCloud LoadBalance 组件,收录在SpringCloud Commons 外面文档如下: 参考博客:https://docs.spring.io/spring-cloud-commons/docs/current/refe...应用上和ribbon没有什么不同,应用 @LoadBalanced 手动申明 RestTemplate Bean @ConditionalOnMissingBean(RestTemplate.class) @LoadBalanced @Bean public RestTemplate restTemplate(@Qualifier("myMappingJackson2HttpMessageConverter") MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter) { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(new CoreHttpRequestInterceptor()); //RestTemplate解决Date数据类型反序列化的问题,应用自定义的MappingJackson2HttpMessageConverter笼罩 restTemplate.getMessageConverters().add(5, mappingJackson2HttpMessageConverter); return restTemplate; }hystrix能够思考应用Spring Cloud Alibaba的Sentinel做熔断和流控 ...

April 21, 2023 · 2 min · jiezi

关于springboot:大公司为什么禁止SpringBoot项目使用Tomcat

前言在SpringBoot框架中,咱们应用最多的是Tomcat,这是SpringBoot默认的容器技术,而且是内嵌式的Tomcat。同时,SpringBoot也反对Undertow容器,咱们能够很不便的用Undertow替换Tomcat,而Undertow的性能和内存应用方面都优于Tomcat,那咱们如何应用Undertow技术呢?本文将为大家细细解说。 SpringBoot中的Tomcat容器SpringBoot能够说是目前最火的Java Web框架了。它将开发者从沉重的xml拯救了进去,让开发者在几分钟内就能够创立一个残缺的Web服务,极大的进步了开发者的工作效率。Web容器技术是Web我的项目必不可少的组成部分,因为任Web我的项目都要借助容器技术来运行起来。在SpringBoot框架中,咱们应用最多的是Tomcat,这是SpringBoot默认的容器技术,而且是内嵌式的Tomcat。举荐:最全面的Java面试网站 SpringBoot设置Undertow对于Tomcat技术,Java程序员应该都十分相熟,它是Web利用最罕用的容器技术。咱们最早的开发的我的项目根本都是部署在Tomcat下运行,那除了Tomcat容器,SpringBoot中咱们还能够应用什么容器技术呢?没错,就是题目中的Undertow容器技术。SrpingBoot曾经齐全继承了Undertow技术,咱们只须要引入Undertow的依赖即可,如下图所示。 配置好当前,咱们启动应用程序,发现容器曾经替换为Undertow。那咱们为什么须要替换Tomcat为Undertow技术呢? 本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 Tomcat与Undertow的优劣比照Tomcat是Apache基金下的一个轻量级的Servlet容器,反对Servlet和JSP。Tomcat具备Web服务器特有的性能,包含 Tomcat治理和管制平台、安全局治理和Tomcat阀等。Tomcat自身蕴含了HTTP服务器,因而也能够视作独自的Web服务器。然而,Tomcat和ApacheHTTP服务器不是一个货色,ApacheHTTP服务器是用C语言实现的HTTP Web服务器。Tomcat是完全免费的,深受开发者的青睐。 Undertow是Red Hat公司的开源产品, 它齐全采纳Java语言开发,是一款灵便的高性能Web服务器,反对阻塞IO和非阻塞IO。因为Undertow采纳Java语言开发,能够间接嵌入到Java我的项目中应用。同时, Undertow齐全反对Servlet和Web Socket,在高并发状况下体现十分杰出。 咱们在雷同机器配置下压测Tomcat和Undertow,失去的测试后果如下所示:QPS测试后果比照: Tomcat Undertow 内存应用比照: Tomcat Undertow 通过测试发现,在高并发零碎中,Tomcat相对来说比拟弱。在雷同的机器配置下,模仿相等的申请数,Undertow在性能和内存应用方面都是最优的。并且Undertow新版本默认应用长久连贯,这将会进一步提高它的并发吞吐能力。所以,如果是高并发的业务零碎,Undertow是最佳抉择。 最初SpingBoot中咱们既能够应用Tomcat作为Http服务,也能够用Undertow来代替。Undertow在高并发业务场景中,性能优于Tomcat。所以,如果咱们的零碎是高并发申请,无妨应用一下Undertow,你会发现你的零碎性能会失去很大的晋升。 好货色应该要分享进去!我把本人学习计算机多年以来的书籍分享进去了,汇总到一个计算机经典编程书籍仓库了,一共300多本,包含C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,能够star一下,下次找书间接在下面搜寻,仓库继续更新中~ Github地址

April 17, 2023 · 1 min · jiezi

关于springboot:一文搞懂Session和JWT登录认证

前言目前在开发的小组结课我的项目中用到了JWT认证,简略分享一下,并看看与Session认证的异同。 登录认证(Authentication)的概念非常简单,就是通过肯定伎俩对用户的身份进行确认。 咱们都晓得 HTTP 是无状态的,服务器接管的每一次申请,对它来说都是 “新来的”,并不知道客户端来过。 举个例子: 客户端A: 我是A, 给我一瓶水。服务端B: 好,给你。客户端A: 再给我来个面包。服务端B: 啥,你是谁? 即每一个申请对服务器来说都是新的。 咱们不可能每次操作都让用户输出用户名和明码,那么咱们如何让服务器记住咱们登录过了呢? 那就是凭证。即每次申请都给服务器一个凭证通知服务器我是谁。 当初个别应用比拟多的认证形式有四种: SessionTokenSSO单点登录OAtuth登录上面就来说说比拟罕用的前两种。 SessionCookie + Session最常见的就是 Cookie + Session 认证。 Session,是一种有状态的会话管理机制,其目标就是为了解决HTTP无状态申请带来的问题。 当用户登录认证申请通过时,服务端会将用户的信息存储起来,并生成一个 SessionId 发送给前端,前端将这个 SessionId 保存起来。之后前端再发送申请时都携带 SessionId,服务器端再依据这个 SessionId 来查看该用户有没有登录过。 这个 SessionId, 个别是保留在Cookie中。 如果用户第一次拜访某个服务器时,服务器响应数据时会在响应头的 Set-Cookie 标识里将Session Id 返回给浏览器,浏览器就将标识中的数据存在Cookie中。 上面咱们来简略写个 demo 测试一下: 初始化一个spring boot 我的项目,并且代码如下: demo咱们只须要在用户登录的时候将用户信息存在HttpSession中 @RestControllerpublic class UserController { @PostMapping("login") public String login(@RequestBody User user, HttpSession session) { if ("admin".equals(user.getUsername()) && "admin".equals(user.getPassword())) { // 登录胜利 写入Session session.setAttribute("sessionId", user); return "login success"; } return "username or password incorrect"; } @GetMapping("/logout") public String logout(HttpSession session) { // 登记 删除Session session.removeAttribute("sessionId"); return "logout success"; } public String api(HttpSession session) { // 用户操作 判断是否登录 User user = (User) session.getAttribute("sessionId"); if (user == null) { return "please login"; } return "return data"; }}上面咱们向 login 地址 申请,并查看响应。 能够看到,用户登录时服务端会返回 Set-Cookie 字段。这些工作 Servlet帮咱们做好了 ...

April 15, 2023 · 4 min · jiezi

关于springboot:Sprintboot-pom项目间接依赖的包的版本与预期不符

问题Sprintboot pom我的项目间接依赖的包的版本与预期不符,间接依赖的版本应该为3.0.4,理论拿的却是2.1.0 场景sprintboot我的项目A 版本2.1.5.Releasekafka的封装依赖包B,版本1.0.0,依赖于kafka版本3.0.4 我的项目A引入B后,kafka版本变成了2.1.0 起因在pom.xml里定义了 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>相当于引入了spring-boot-starter-parent.pom <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.5.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent>相当于引入了spring-boot-dependencies.pom ...<properties> ... <kafka.version>2.0.1</kafka.version> ...</properties><dependencyManagement> <dependencies> ... <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>${kafka.version}</version> </dependency> ... </dependencies></dependencyManagement>查看sprint官网 sprintboot对应kafka-clients版本 间接依赖的包的版本优先级没有parent里申明的高 解决办法降级springboot版本到2.6.x以上pom.xml里指定kafka版本为3.0.4

April 14, 2023 · 1 min · jiezi

关于springboot:简单使用spring-cloud-服务注册做一个请求转发中心

背景上篇文章 记录多我的项目共用一个公众号逻辑批改, 实现了多个我的项目共用一个公众号。 然而也存在几点问题,比方: 两头服务器拦挡了微信的申请,尽管不便了我的项目不再须要写微信受权的代码,但如果当前须要再拓展新的微信申请,就须要再去两头服务器写api须要搭建前台,手动保护各个我的项目的地址和key。咱们能够让两头服务器只是简略地转发申请,不再拦挡,解决第一点问题。 同时利用 服务发现与注册 解决第二个问题。 用服务注册的益处就是,咱们不须要再手动地保护我的项目信息、各个我的项目的ip,只须要让新来的我的项目向服务中心注册一下就好了。 服务发现与注册服务注册是指向服务注册核心注册一个服务实例,服务提供者将本人的服务信息(如IP地址等)告知服务注册核心。 服务发现是指当服务消费者须要生产另外一个服务时, 服务注册核心可能告知服务消费者它所要生产服务的实例信息(如服务名、IP 地址等)。 通常状况下,一个服务既是服务提供者,也是服务消费者。 所以,如下图形式,每个我的项目都向注册核心注册,就不须要建表保护各个我的项目的ip地址了。 常见的注册核心可能实现服务注册的组件很多,比方ZooKeeper、Eureka、Consul、Nacos等。 这里选用比拟常见的 Eureka。 EurekaEureka是Netflix开发的服务发现框架,SpringCloud将它集成在本人的子项目spring-cloud-netflix中, 实现SpringCloud的服务发现性能。 上图简要形容了Eureka的根本架构,由3个角色组成: Eureka Server 提供服务注册和发现Service Provider 服务提供方 将本身服务注册到Eureka,从而使服务生产方可能找到Service Consumer 服务生产方 从Eureka获取注册服务列表,从而可能生产服务Eureka基本概念Register——服务注册当 Eureka Client 向 Eureka Server 注册时,Eureka Client 提供本身的元数据,比方 IP 地址、 端口、运行状况指标的 Url、主页地址等信息。 Renew——服务续约  Eureka Client 在默认的状况下会每隔 30 秒发送一次心跳来进行服务续约。通过服务续约 来告知 Eureka Server 该 Eureka Client 依然可用,没有呈现故障。失常状况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的心跳,Eureka Server 会将 Eureka Client 实例从注册列表中删除。留神:官网倡议不要更改服务续约的间隔时间。 ...

April 8, 2023 · 3 min · jiezi

关于springboot:JVM频繁GC内存溢出排查

前言GC(Garbage collection)频繁和堆内存溢出起因简略来说是对象占用堆空间难以回收,新对象无奈调配触发GC或者间接导致内存溢出,最终过程完结。排查思路是先查看过程各种类型对象占用空间大小和比例,锁定占用空间较多的对象后再剖析相干的程序是否有使用不当的中央。下文的侧重点是通过多种形式查看堆内存散布。例子程序先编译(javac FrequentFullGCSample.java)例子程序,执行上面的指令来创立JVM过程。指定-Xms2M -Xmx2M来限度堆内存大小为 2兆,作为例子程序够用了;为了不便演示咱们再加上这两个选项:-XX:+PrintCommandLineFlags打印有变动的JVM选项值;-XX:+PrintGCDetails打印垃圾回收的详细信息。java -Xms2M -Xmx2M -XX:+PrintCommandLineFlags -XX:+PrintGCDetails FrequentFullGCSample复制代码import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.TimeUnit;public class FrequentFullGCSample {    private static final Queue<Object> QUEUE = new LinkedList<>();    public static void main(String[] args) throws InterruptedException {        while (true) {            QUEUE.offer(new Object());            TimeUnit.MILLISECONDS.sleep(3);       }   }}复制代码从控制台日志能够看到首先输入了局部有变动的JVM选项值:初始堆(-XX:InitialHeapSize)和最大堆(-XX:MaxHeapSize)大小都为2097152字节(B),也就是2兆(M);应用了类指针压缩(-XX:+UseCompressedClassPointers)和对象指针压缩(-XX:+UseCompressedOops)。在前面咱们能够看到输入的GC日志信息,对象先调配在年老代,空间占满开始频繁YGC(Young garbage collection)。 通过几代回收之后,对象分代年龄增长转移到老年代,老年代空间逐步占满开始频繁Full GC。 因为例子程序新创建的对象都是强援用类型,不能定为垃圾,无奈回收。通过频繁的Full GC无果后新对象无奈调配到空间,报错内存溢出(java.lang.OutOfMemoryError)。从前面打印的各个分代的内存应用状况能够看出年老代(def new generation)和老年代(tenured generation)占用比例靠近100%。 ...

April 7, 2023 · 1 min · jiezi

关于springboot:Spring-BootNacosgRPC一个区别于-OpenFeign-的微服务通信方案

gRPC 的基础知识后面跟小伙伴们分享了很多了,明天再写一篇给这个小小的系列收个尾。 咱们后面介绍的都是 gRPC 的根本用法,最终目标当然是心愿可能在 Spring Boot 中用上这个货色,置信大部分小伙伴对于微服务的通信计划如 OpenFeign、Dubbo、音讯驱动都有所理解,然而对于这三种计划之外的其余计划,可能听的多用的少,明天咱们就来实际一下 gRPC 这种计划。 顺便说一下我为什么会想到写 gRPC 教程呢,是因为之前我想给小伙伴们总结一下常见的各种微服务通信计划。整顿到 gRPC 的时候发现我还没写过 gRPC 相干的教程,因而就有了一个小系列。1. 依赖抉择Spring Boot 整合 gRPC,官网其实并没有提供相应的依赖,不过目前有一个比拟风行的第三方库能够应用: https://github.com/yidongnan/grpc-spring-boot-starter接下来松哥就联合这个库,来和小伙伴们演示一下 Spring Boot+Nacos+gRPC 的用法。 可能有小伙伴也会见到一些其余的第三方库,这个其实都能够,只有稳固牢靠就行,本文就以下面这个库为例来和小伙伴们介绍。 2. 筹备工作这里我采纳了 Nacos 来做服务注册核心,应用的 Nacos 版本是 2.0.2 这个版本。Nacos 简略装置一下就行了,为了省事,数据长久化啥的能够先不配置。也就是 Nacos 下载解压之后,间接执行如下命令单体运行就行了: sh startup.sh -m standalone这块没啥好说的,松哥在 vhr 系列里也有相干的视频教程,这里就不啰嗦了。 3. 代码实际首先咱们来看看咱们的我的项目构造: ├─grpc-api│ └─src│ └─main│ └─proto├─grpc-client│ └─src│ ├─main│ │ ├─java│ │ └─resources│ └─test└─grpc-server └─src ├─main │ ├─java │ └─resources └─test首先有一个公共的模块 grpc-api,这个模块用来放咱们的公共代码和依赖,包含 Protocol Buffers 文件也放在这里。 grpc-client 和 grpc-server 就不必多说了,别离是咱们的客户端和服务端。 ...

April 6, 2023 · 3 min · jiezi

关于springboot:Did-you-forget-to-include-springcloudstarterloadbalancer原因探究

前提:本案例是基于spring boot 2.7.5,spring cloud 3.1.6,其余版本可能会有些差异! 对于“Did you forget to include spring-cloud-starter-loadbalancer?”报错的起因,网上有一大堆博客供大家参考,这里我给大家提供一种新的参考。 先说论断: 报“Did you forget to include spring-cloud-starter-loadbalancer”的起因之一是可能没有引入"spring-cloud-loadbalancer" pom依赖。spring boot 启动时执行org.springframework.cloud.openfeign.FeignClientFactoryBean.loadBalance()时,getOptional()范畴为null,而后抛出异样“Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?”; protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) { //返回为null Client client = getOptional(context, Client.class); if (client != null) { builder.client(client); applyBuildCustomizers(context, builder); Targeter targeter = get(context, Targeter.class); return targeter.target(this, builder, context, target); } //到这里抛出异样 throw new IllegalStateException( "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?"); }也就是说,DefaultListableBeanFactory外面没有类型为“feign.Client”的bean;上面的图是以后我的项目里所有“feign.Client”的实现类: ...

April 4, 2023 · 1 min · jiezi

关于springboot:记一次springboot通过jackson渲染到前端出现大写字母变成小写问题

前言最近业务部门接手了外包供应商的我的项目过去本人运维,该部门的小伙伴发现了一个问题,比方后端的DTO有个属性名为nPrice的字段,通过json渲染到前端后,变成nprice,而预期的字段是要为nPrice。于是他们就找到咱们部门,心愿咱们能帮忙解决一下这个问题,本文就聊聊如何解决问题,至于为什么会呈现这个问题,前面留个彩蛋 解法注: 本文的json都是通过springboot默认的jackson进行渲染解析,因而本文的解法都是针对jackson 办法一:在属性字段上加@JsonProperty注解示例 @JsonProperty(value = "nPropriceFactory") private BigDecimal nPropriceFactory;因为业务接手的我的项目的字段的属性大量都是首字母小写,第二个字母大写的模式,比方nHelloWorld,因而业务部门的小伙伴,感觉一个个加太麻烦了,有没有更简洁点方法。于是就有了第二种办法 办法二:通过自定义com.fasterxml.jackson.databind.PropertyNamingStrategy策略具体逻辑形如如下 public class CustomPropertyNamingStrategy extends PropertyNamingStrategy { @Override public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { if (isSpecialPropertyName(defaultName)) { //将属性的get办法去除get,而后首字母转小写 return StringUtils.uncapitalize(method.getName().substring(3)); } return super.nameForGetterMethod(config,method,defaultName); } @Override public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { if (isSpecialPropertyName(defaultName)) { //将属性的set办法去除set,而后首字母转小写 return StringUtils.uncapitalize(method.getName().substring(3)); } return super.nameForSetterMethod(config,method,defaultName); } }在application.yml做如下配置 spring: jackson: property-naming-strategy: com.github.lybgeek.jackson.CustomPropertyNamingStrategy这样就能够解决了,不过业务部门的研发,基本上都是被惯坏的小孩,为了让他们更不便的应用,咱们就更近一步,也不要在yml进行配置了,让他们间接引入jar就好。于是咱们做了如下操作 public final class EnvUtils { private EnvUtils(){} private static final String JACKSON_PROPERTY_NAMING_STRATEGY_KEY = "spring.jackson.property-naming-strategy"; public static void postProcessEnvironment(ConfigurableEnvironment environment){ String isCustomJsonFormatEnaled = environment.getProperty(CUSTOM_JSON_FORMAT_ENABLE_KEY,"true"); if("true".equalsIgnoreCase(isCustomJsonFormatEnaled)){ setCustomJacksonPropertyNamingStrategy(environment); } } private static void setCustomJacksonPropertyNamingStrategy(ConfigurableEnvironment environment) { MutablePropertySources propertySources = environment.getPropertySources(); Map<String, Object> mapPropertySource = new HashMap<>(); mapPropertySource.put(JACKSON_PROPERTY_NAMING_STRATEGY_KEY, CustomPropertyNamingStrategy.class.getName()); PropertySource propertySource = new MapPropertySource("custom-json-format-properties",mapPropertySource); propertySources.addFirst(propertySource); }}public class CustomJacksonFormatEnvironmentApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { ConfigurableEnvironment environment = applicationContext.getEnvironment(); EnvUtils.postProcessEnvironment(environment); }}在resouce下新建META-INF/spring.factories,并指定如下内容 ...

April 4, 2023 · 1 min · jiezi

关于springboot:SpringBoot打包成exe别再用exe4j了使用JDK自带工具

SpringBoot打包成exe(别再用exe4j了,应用JDK自带工具)搜到大部分打包exe的文章都是应用exe4j打包 步骤贼多,装置麻烦,打包麻烦免费软件,公司应用会吃律师函JDK14以上能够应用JDK自带的jpackage打包 JDK自带,一行命令搞定生成的程序包含java环境,用户不须要装置java实测环境JDK:17.0.6步骤创立一个Springboot我的项目,开发代码应用"mvn package"打包成jar 在我的项目下生产target目录,且蕴含打包成的jar(例如:spring-1.0.jar)要确认这个jar能应用"java -jar *.jar"运行关上命令行(CMD/Powershell)进入我的项目根目录成exe应用jpackage打包,如下jpackage --type app-image --name spring --input target --main-jar spring-1.0.jar --win-console --dest dist参数作用示例阐明--type打包类型app-image可选:"app-image", "exe", "msi",这里应用app-image,抉择另外两个选项须要装置WiX--name利用名称spring打包后的名称,如"sping.exe"--input输出目录target该目录所有文件打包到利用目录中--main-jar利用主jarspring-1.0.jar--input目录里的jar程序--win-console运行时启动控制台--win-console关上应用程序时,关上控制台。如果不启用在后盾运行,敞开只能从工作管理器中结束任务--dest输入目录dist输入到该目录,不要和--input同个目录,否则会有限循环复制目录更多其余参数查看JPackage指令将可执行Jar包打包成EXE运行程序和MSI安装程序输入目录dist spring app // 我的项目代码,和target目录基本一致 ...文件略runtime // 运行环境,用户能够不装置java ...文件略spring.exe // 点击该exe即可运行spring.icotarget ...目录略spring-1.0.jarspring-1.0.jar.original阐明能够将spring目录压缩成zip发给用户应用 目录里蕴含了runtime,用户电脑不须要装置java打包前:153MB打包后(zip):71.8MB总结在不得不开发客户端时,很多人抉择JavaFX开发,但大家大部分应用spring全家桶开发用这种形式,能够持续应用spring开发 持续前后端拆散开发前端代码框架(如:Ant D)打包后是动态文件,可间接放入resources目录应用jpackage打包成exe发送给用户间接关上应用 用户在浏览器就能够拜访能够优化成启动程序时主动关上url@Slf4j@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); // 应用默认浏览器关上 try { Runtime.getRuntime().exec(String.format("cmd /c start %s", "http://localhost:8080/index.html")); } catch (Exception e) { log.warn("关上客户端主页失败", e); } }}参考资料JPackage指令将可执行Jar包打包成EXE运行程序和MSI安装程序 该文章说必须装置WiX和.NetFramework。但我实测时app-image类型不须要(有可能是因为JDK版本)

March 31, 2023 · 1 min · jiezi

关于springboot:Springboot3微服务实战12306高性能售票系统无mi

残缺落地“高并发,高可用,高性能” 整体解决方案。大厂超大型我的项目架构设计与实战经验,带你从架构设计到具体场景计划落地,真正驾驭超高并发场景下的各种疑难问题. download:https://www.sisuoit.com/3813.html 第一步:搭建微服务架构搭建微服务架构通常包含以下步骤: 划分服务边界:将本来的单体利用拆分成多个服务,每个服务只负责本人的业务逻辑。配置服务注册核心:所有的微服务都注册到服务注册核心,以便于服务发现和负载平衡。配置服务网关:微服务之间的通信通过服务网关来实现,服务网关能够提供负载平衡、平安认证等性能。配置配置核心:所有的微服务都从配置核心获取配置信息,以便于动静调整配置。 第二步:编写微服务代码编写微服务代码通常包含以下步骤: 创立微服务项目:应用 Spring Boot 初始化一个新的微服务项目。配置数据库连贯:配置数据库连贯信息,以便于微服务能够拜访数据库。编写业务逻辑:依据微服务的性能需要,编写业务逻辑代码。集成服务注册核心:将微服务注册到服务注册核心,以便于其余微服务能够发现和调用该微服务。集成服务网关:将微服务集成到服务网关中,以便于微服务之间的通信能够通过服务网关来实现。 第三步:部署微服务部署微服务通常包含以下步骤: 打包微服务:应用 Maven 或 Gradle 打包微服务项目,生成可执行的 Jar 包。配置运行环境:配置微服务的运行环境,包含 Java 运行环境、数据库等。启动微服务:应用命令行或脚本启动微服务,以便于微服务能够运行在指定的端口和地址上。 第四步:测试微服务测试微服务通常包含以下步骤: 编写测试代码:编写测试代码,测试微服务的性能是否合乎需要。运行测试:运行测试代码,验证微服务的性能是否失常。 第五步:保护微服务保护微服务通常包含以下步骤: 监控微服务:监控微服务的运行状态,包含 CPU 使用率、内存使用率、申请响应工夫等指标。日志治理:治理微服务的日志,以便于排查问题和剖析零碎运行状况。定期降级:定期降级微服务的依赖库和框架,以便于放弃零碎的稳定性和安全性。

March 30, 2023 · 1 min · jiezi

关于springboot:常见分布式理论CAPBASE和一致性协议

一、CAP实践与BASE实践:1、什么是 CAP 实践:C:Consistency 一致性:指强一致性,分布式系统中的所有节点在同一时刻具备同样的值、都是最新的数据正本,一致性保障了不论向哪台服务器写入数据,其余的服务器能实时同步数据A:Availability 可用性:局部结点宕机不影响整个集群对外提供服务,每次向未故障的节点发送申请,服务节点总能保障在无限的工夫内解决实现并进行响应,从用户角度来看就是不会呈现零碎操作失败或者拜访超时等问题,然而零碎外部可能会呈现网络提早等问题P:Partition Tolerance 分区容错性:因为网络的问题盘根错节,如果某个节点因为网络等问题造成数据不统一,或者数据提早很久才同步过去,尽管会影响局部节点数据的时效性,然而服务节点仍然是可用的,分布式系统要能容忍这种状况的,也就是说,只管网络上有局部音讯失落,但零碎依然可持续工作。分布式系统中,CAP是无奈同时满足的,只能满足CAP中的两种,因而在设计分布式架构时,必须做出取舍,而对于分布式系统,分区容忍性是根本要求,必须要满足,否则就失去了价值。因为是节点宕机和网络故障大概率事件,很难防止,而当呈现这种状况时,不可能同时放弃一致性和可用性,所以设计分布式系统,就是在一致性和可用性之间取一个均衡。 那为什么说在P满足的状况下,为什么说CA不能同时满足呢?咱们来通过假如看一看,如果CA同时满足会怎么样: (1)假如当初要求满足C(一致性),那么就是说所有的节点在某一刻提供的数据都必须统一,咱们晓得在P的状况,是不可能保障的,要保障的话,就只能把其余节点全副干掉,比方禁止读写,那这其实就是和A是相悖的(某些节点尽管提早,然而节点自身可用) (2)假如当初要求满足A(可用性),那么就是说只有节点自身没什么问题,就能够对外提供服务,哪怕有点数据提早,很显著这必定是和C相悖的。 2、一致性的类别:CAP 是分布式事务处理的实践根底,在分布式事务的最终解决方案中个别抉择就义一致性来换取可用性和分区容错性,但这里的 “就义一致性” 并不是齐全放弃数据的一致性,而是放弃强一致性而换取弱一致性。一致性个别能够分为以下三种: (1)强一致性:在任意时刻,所有节点中的数据是一样的,零碎中的某个数据被胜利更新后,后续任何对该数据的读取操作都将失去更新后的值。比方传统数据库的事务个性 ACID,就是谋求强一致性模型。 一个集群须要对外部提供强一致性,就务必会损耗可用性,只有集群外部某一台服务器的数据产生了扭转,那么就须要期待集群内其余服务器的数据同步实现后,能力失常的对外提供服务。(2)弱一致性:零碎中的某个数据被更新后,后续对该数据的读取操作可能失去更新后的值,也可能是更改前的值,但即便过了不统一工夫窗口后,后续对该数据的读取也不肯定是最新值。 (3)最终一致性:是弱一致性的非凡模式,尽管不保障在任意时刻任意节点上的同一份数据都是雷同的,但通过一段时间后,所有服务节点间的数据最终会达到统一的状态 弱一致性即便过了不统一工夫窗口,后续的读取也不肯定能保障统一,而最终一致性过了不统一窗口后,后续的读取肯定保障统一。3、什么是 BASE 实践:BASE 实践是指,Basically Available(根本可用)、Soft-state( 软状态)、Eventual Consistency(最终一致性),是基于CAP定理演变而来,是对CAP中一致性和可用性衡量的后果。核心思想是即便无奈做到强一致性,但每个业务依据本身的特点,采纳适当的形式来使零碎达到最终一致性。 BA 根本可用:指分布式系统在呈现故障的时候,容许损失局部可用性,保障外围可用。但不等价于不可用。比方:搜索引擎0.5秒返回查问后果,但因为故障,2秒响应查问后果;网页拜访过大时,局部用户提供降级服务等。软状态:软状态是指容许零碎存在中间状态,并且该中间状态不会影响零碎整体可用性,即容许零碎在不同节点间正本同步的时候存在延时。最终一致性:零碎中的所有数据正本通过肯定工夫后,最终可能达到统一的状态,不须要实时保证系统数据的强一致性。很多时候咱们并不要求数据的强一致性,而 BASE 通过就义强一致性来取得更好的可用性,所以 BASE 实践的适用性更宽泛,比方更适宜面向的是大型高可用可扩大的分布式系统 柔性事务和刚性事务:柔性事务满足BASE实践(根本可用,最终统一),刚性事务满足ACID实践。二、一致性协定:1、Gossip协定:参考文章:https://juejin.cn/post/7023918632216297479集群往往是由多个节点独特组成的,当一个节点退出集群或者一个节点从集群中下线的时候,都须要让集群中其余的节点晓得,这样能力将数据信息分享给新节点而疏忽下线节点。 如上图,A、B、C 节点之间能够相互传递音讯,然而D节点在下线之后会被播送通知其余存活节点。这样的播送协定就是明天要说Gossip协定,Gossip协定也叫Epidemic协定(流行病协定),当一个音讯到来时,通过Gossip协定就能够像病毒一样感化全副集群节点。Gossip的过程是由一个种子节点发动的,当一个种子节点有信息须要同步到网络中的其余节点时,它会随机的抉择四周几个节点散播音讯,收到音讯的节点也会反复该过程,直至最终网络中所有的节点都收到了音讯。这个过程可能须要肯定的工夫,所以不能保障某个工夫点所有的节点都有该条音讯,然而实践上最终所有节点都会收到音讯,因而它是一个最终一致性协定。 Gossip协定的特点: (1)Gossip协定是周期性散播音讯,每隔一段时间流传一次(2)被感化的节点,每次能够持续散播N个节点(3)每次散播音讯时,都会抉择尚未发送过的节点进行散播,不会向发送的节点散播(4)同一个节点可能会收到反复的音讯,因为可能同时多个节点正好向它散播(5)集群是去中心化的,节点之间都是平等的(6)音讯的散播不必等接管节点的 ack,即音讯可能会失落,然而最终应该会被感化上面咱们来看个例子: ① 种子节点是A② A节点抉择B、C节点进行散播③ C散播到D,B散播D和E,能够发现D收到两次④ D散播到F,最终整个网络都同步到了音讯Gossip有点相似图的广度优先遍历算法,个别用于网络拓扑构造信息的分享和保护,比方 Redis 集群中节点的运行状态就是应用 Gossip 协定进行传递的。 2、Raft一致性协定:参考文章:https://baijiahao.baidu.com/s?id=1693824822611080380&wfr=spid...分布式协定的难点之一就是数据的一致性,当由多个节点组成的集群中只有一个节点收到数据,咱们就算胜利的话,危险太大,当要求所有节点都收到数据才响应胜利,性能又太差,所以个别会在数据的平安和性能之间做个折中,只有保障绝大部分节点同步数据胜利,咱们就算胜利。比拟出名的一致性算法有Raft算法,被广泛应用于许多中间件中,接下来咱们就看看Raft算法是实现分布式系统的不同节点间的数据一致性的,也就是说客户端发送申请到任何一个节点都能收到统一的返回,当一个节点出故障后,其余节点依然能以已有的数据失常进行。 首先介绍下在Raft算法中,几种状况下每个节点对应的角色: (1)Leader节点:同大多数分布式中的Leader节点一样,所有数据的变更都须要先通过Leader (2)Follower节点:Leader节点的追随者,负责复制数据并且在选举时候投票的节点 (3)Candidate候选节点:参加选举的节点,就是Follower节点参加选举时会切换的角色 Raft算法将一致性问题合成为两个的子问题,Leader选举 + 数据日志的复制: 2.1、Leader 选举:零碎在刚开始的时候,所有节点都是Follower节点,这时都有机会参加选举,将本人变成Candidate,变成Candidate的节点会先投本人1票,同时通知其它节点,让它们来投票,当拿到超过半数以上的投票时,以后Candidate就会变成Leader节点。然而如果每个Follower节点都变成Candidate那么就会陷入有限的死循环,于是每个Follower都一个定时器,并且定时器的工夫是随机的,当某个Follower的定时器工夫走完之后,会确认以后是否存在Leader节点,如果不存在再把本人变成Candidate。 ① 因为A节点的定时器工夫最短(10ms),所以A会成为Candidate。② A投本人一票,并通知B、C来投票,B、C也投出本人的批准票后,A就会变成Leader节点,同时会记录是第M任。这个M是做版本校验的,比方一个编号是10的节点,收到了一个编号是9的节点的投票申请,那么就会回绝这个申请。在Leader节点选举进去当前,Leader节点会一直的发送心跳给其它Follower节点证实本人是活着的,其余Follower节点在收到心跳后会清空本人的定时器,并回复给Leader,因为此时没必要触发选举了。 如果Leader节点在某一刻挂了,那么Follower节点就不会收到心跳,因而在定时器到来时就会触发新一轮的选举,流程还是一样。然而如果凑巧两个Follower都变成了Candidate,并且都失去了同样的票数,那么此时就会陷入僵局,为了突破僵局,这时每个Candidate都会随机推延一段时间再次申请投票,当然个别状况下,就是先来先得,优先跑完定时器的Candidate实践成为Leader的概率更大。 选举流程大抵如上,接下来咱们来看看数据日志的复制。 2.2、数据日志的复制:当Leader节点收到客户端Client的申请变更时,会把变更记录到log中,而后Leader会将这个变更随着下一次的心跳告诉给Follower节点,收到音讯的Follower节点把变更同样写入日志中,而后回复Leader节点,当Leader收到大多数的回复后,就把变更写入本人的存储空间,同时回复client,并通知Follower利用此log。至此,集群就变更达成了共识。 (1)失常状况下的日志复制: ...

March 30, 2023 · 1 min · jiezi

关于springboot:分享一个修改了xml文件再也不用重启的项目mybatisxmlrealod

自我18年应用 Mybaits 以来,开发环境中如果批改了 xml 文件后,只有重启我的项目能力失效,如果小我的项目重启还好,然而对于一个重启须要十几分钟的大型项目来说,这就十分耗时了。开发人员因为批改了xml 文件大量内容,比方增加一个逗号、查问减少一个字段或者批改一个 bug 等,就须要重启整个我的项目,这就十分苦楚了。 所以在这里给大家举荐一个实现了 Mybatis xml文件热加载的我的项目,mybatis-xmlreload-spring-boot-starter。它可能帮忙咱们在Spring Boot + Mybatis的开发环境中批改 xml 后,不须要重启我的项目就能让批改过后 xml 文件立刻失效,实现热加载性能。这里给出我的项目地址: https://github.com/wayn111/mybatis-xmlreload-spring-boot-starter 欢送大家关注,点个starps:mybatis-xmlreload-spring-boot-starter目前 3.0.3.m1 版本实现了 xml 文件批改已有内容,比方批改 sql 语句、增加查问字段、增加查问条件等,能够实现热加载性能。然而对于 xml 文件增加 insert|update|delete|select 标签等内容后,是无奈实现热加载的。家喻户晓,在 Idea 环境进行 Java 开发,在办法内批改办法内容是能够热加载的。然而增加新办法、增加办法参数,批改办法参数,批改办法返回值等都是无奈间接热加载的。 一、mybatis-xmlreload-spring-boot-starter应用mybatis-xmlreload-spring-boot-starter原理: 批改 xml 文件的加载逻辑。在一般的 mybatis-spring 我的项目中,默认只会加载我的项目编译过后的 xml 文件,也就是 target 目录下的 xml 文件。然而在mybatis-xmlreload-spring-boot-starter中,批改了这一点,它会加载我的项目 resources 目录下的 xml 文件,这样用户对于 resources 目录下 xml 文件的批改操作是能够立刻触发热加载的。通过 io.methvin.directory-watcher 我的项目来监听 xml 文件的批改操作,它底层是通过 java.nio 的WatchService 来实现,当咱们监听了整个 resources 目录后,xml 文件的批改会立马触发 MODIFY 事件。通过 mybatis-spring 我的项目原生的 xmlMapperBuilder.parse() 办法从新加载解析批改过后的 xml 文件来保障我的项目对于 Mybatis 的兼容性解决。二、技术原理mybatis-xmlreload-spring-boot-starter代码构造如下:外围代码在MybatisXmlReload类中,执行逻辑: ...

March 26, 2023 · 3 min · jiezi

关于springboot:SpringBoot集成SpringBootAdmin实现监控

成果展现 客户端maven援用        <parent>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-parent</artifactId>            <version>2.0.0.RELEASE</version>        </parent>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-actuator</artifactId>        </dependency>        <dependency>            <groupId>de.codecentric</groupId>            <artifactId>spring-boot-admin-starter-client</artifactId>            <version>2.0.0</version>        </dependency> 配置文件management: endpoints:   web:     exposure:       include: '*' endpoint:   health:     show-details: always平安爱护public class ActuatorAuthFilter implements Filter, Ordered {    private AuthService authService = SpringBootBeanUtil.getBean(AuthService.class);    @Override    public void init(FilterConfig filterConfig) throws ServletException {   }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        boolean authPass = false;        HttpServletRequest req = (HttpServletRequest) request;        String system = req.getHeader("system");        String token = req.getHeader("token");        if ( !StringUtil.isEmpty(system) && !StringUtil.isEmpty(token)) {            if(system.equals("haopanwatch") && token.equals("7e447e5d38d323b847edf2b4895eb242")){                authPass = true;           }       }        if (authPass) {            chain.doFilter(request, response);       } else {            Result result = Result.errorResult().setMsg("NoAuthAccess").setCode(SystemErrorCodeEnum.ErrorCode.TokenAuthError.get_value());            response.getWriter().println(JSON.toJSON(result));       }   }    @Override    public void destroy() {   }    @Override    public int getOrder() {        return 11;   }}治理端maven援用    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.2.0.RELEASE</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>de.codecentric</groupId>            <artifactId>spring-boot-admin-starter-server</artifactId>            <version>2.2.0</version>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-security</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>            <exclusions>                <exclusion>                    <groupId>org.springframework.boot</groupId>                    <artifactId>spring-boot-starter-tomcat</artifactId>                </exclusion>            </exclusions>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-jetty</artifactId>        </dependency>    </dependencies>配置文件server.port=9550spring.application.name=springboot-admin-server#配置一个账号和明码spring.security.user.name=adminspring.security.user.password=abcd@1234启动注解@SpringBootApplication@EnableAdminServerpublic class HaopanWatchApplication {    public static void main(String[] args) {        SpringApplication.run(HaopanWatchApplication.class, args);   }    @Bean    public ApplicationRunner applicationRunner() {        return applicationArguments -> {            System.out.println("haopanwatch启动胜利!");       };   }}平安爱护@Configurationpublic class SecuritySecureConfig extends WebSecurityConfigurerAdapter {    //我的项目利用门路    private final String adminContextPath;    public SecuritySecureConfig(AdminServerProperties adminServerProperties) {        this.adminContextPath = adminServerProperties.getContextPath();   }    @Override    protected void configure(HttpSecurity http) throws Exception {        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();        successHandler.setTargetUrlParameter("redirectTo");        successHandler.setDefaultTargetUrl(adminContextPath + "/");        http.authorizeRequests()                //无需登录即可拜访               .antMatchers(adminContextPath + "/assets/**").permitAll()               .antMatchers(adminContextPath + "/login").permitAll()               .anyRequest().authenticated()               .and()                //登录和登出门路               .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()               .logout().logoutUrl(adminContextPath + "/logout").and()                //开启http basic反对,admin-client注册时须要应用               .httpBasic().and()               .csrf()                //开启基于cookie的csrf爱护               .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())                //疏忽这些门路的csrf爱护以便admin-client注册               .ignoringAntMatchers(                        adminContextPath + "/instances",                        adminContextPath + "/actuator/**"               );   }}客户端认证@Componentpublic class HttpHeadersProviderConfig implements HttpHeadersProvider {    @Override    public HttpHeaders getHeaders(Instance instance) {        HttpHeaders httpHeaders = new HttpHeaders();        //设置约定好的申请头参数        httpHeaders.add("token", "7e447e5d38d323b847edf2b4895eb242");        httpHeaders.add("system", "haopanwatch");        return httpHeaders;   }}

March 25, 2023 · 4 min · jiezi

关于springboot:面试1v1实景模拟Java数据类型面试你踩过的坑还少吗赶紧收藏吧

明天和大家聊一下最最最根底的吧,尽管简略,但坑无处不在,会则坚固,不会牢记,面试不能惨死于这些最根底的知识点上~ 老面:什么是根底类型与援用类型?有什么区别?笑小枫:根底类型只示意简略的字符或数字,援用类型能够是任何简单的数据结构。 区别: 存储形式不同,根本类型是存储在栈内存;援用类型变量是寄存在堆内存中,栈中寄存的是变量寄存的内存地址。传递形式不同,根本变量类型是值传递;援用变量类型是援用传递。老面:String是根底的数据类型吗?笑小枫:不是,是援用类型。String数据存储是private final char value[];所以String类是不可变的,对String类的任何扭转,都是返回一个新的String类对象。 老面:JAVA有几种根底数据类型?对应的包装类是什么?笑小枫:八种 根本数据类型:int,double,long,float,short,byte,char,boolean 对应的封装类型是:Integer,Double,Long,Float,Short,Byte,Character,Boolean 老面:什么是主动装箱与拆箱?笑小枫: 装箱:将根本类型用它们对应的援用类型包装起来; 拆箱:将包装类型转换为根本数据类型。 老面:int和Integer哪个会占用更多的内存?笑小枫:Integer对象会占用更多的内存。Integer是一个对象,须要存储对象的信息。然而int是一个原始类型的数据,所以占用的空间更少。 32 位机器下,Integer占用的内存状况如下: 老面:i64位JVM中,int的长度是多少位?笑小枫:Java中,int类型变量的长度是一个固定值,与平台无关,都是32位。意思就是说,在32位和64位的Java虚拟机中,int类型的长度是雷同的。 老面:i怎么将byte转换为String?笑小枫:能够应用String接管byte[]参数的结构器来进行转换,须要留神的点是要应用的正确的编码,否则会应用平台默认编码,这个编码可能跟原来的编码雷同,也可能不同。 老面:i咱们能将int强制转换为byte类型的变量吗?笑小枫:是的,咱们能够做强制转换,然而Java中int是32位的,而byte是8位的,所以,如果强制转化时,int类型的高24位将会被抛弃,byte类型的范畴是从-128到127。 老面:ibyte类型127+1等于多少?笑小枫:如果后果是byte类型,答案是:-128。 如果后果转为int类型,答案是:128。 解析: byte的范畴是-128~127。 字节长度为8位,最右边的是符号位,而127的二进制为01111111,所以执行+1操作时,01111111变为10000000。 大家晓得,计算机中存储正数,存的是补码的兴衰。右边第一位为符号位。 那么正数的补码转换成十进制如下: 一个数如果为正,则它的原码、反码、补码雷同;一个负数的补码,将其转化为十进制,能够间接转换。 已知一个正数的补码,将其转换为十进制数,步骤如下: 先对各位取反;将其转换为十进制数;加上负号,再减去1;例如10000000,最高位是1,是正数,对各位取反得01111111,转换为十进制就是127,加上负号得-127,再减去1得-128; 老面:ifloat 和 double 的区别是什么?笑小枫: 内存中占有的字节数不同单精度浮点数在内存中占有4个字节; 双精度浮点数在内存中占有8个字节; 有效数字位数不同单精度浮点数有效数字8位; 双精度浮点数有效数字16位; 数值取值范畴不同单精度浮点数的示意范畴:-3.40E+38~3.40E+38 双精度浮点数的示意范畴:-1.79E+308~-1.79E+308 在程序中处理速度不同一般来说,CPU解决单精度浮点数的速度比双精度浮点数的速度快 如果不申明,默认小数是double类型,如果想用float,要进行强转; 老面:i能在不进行强制转换的状况下将double值赋值给long类型的变量吗?笑小枫:不行,不能在没有强制类型转换的前提下将一个double值赋值给long类型的变量,因为double类型的范畴比long类型更广,所以必须要进行强制转换。 老面:i3*0.1==0.3将会返回什么?笑小枫:返回false,因为浮点数不能齐全准确的示意进去,个别会损失精度。 老面:ifloat f = 3.4;是否正确?笑小枫:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因而须要强制类型转换floatf=(float)3.4;或者写成floatf=3.4F;。 老面:ishort s1 = 1; s1 = s1+1;有错吗?short s1=1; s1+=1;有错吗?笑小枫:对于short s1=1; s1=s1+1;因为1是int类型,因而s1+1运算后果也是int型,须要强制转换类型能力赋值给short型;所以编译会报错。 而short s1=1; s1+=1;能够正确编译,因为s1+=1;相当于s1=(short)(s1+1);其中有隐含的强制类型转换。 老面:你们我的项目中金额是应用的什么类型?笑小枫:Java代码中应用java.math.BigDecimal;Mysql数据库中应用decimal 。 ...

March 24, 2023 · 1 min · jiezi

关于springboot:SpringBoot接入微信JSSDK看这篇妥妥的

先给猴急的客官上干货代码 GitHub接入微信JSSDK GitHub地址 Gitee接入微信JSSDK GitHub地址 前言事件的起因是因为疫情重大,领导要求做一个专题页,可能尽可能帮忙所须要的人。于是乎本狗与共事挑灯奋战,加班加点赶工进去。部署上线实现,用微信内置浏览器分享后,现实状态应该是这样的,如下图⬇️ 然而,后果却不是现实的这样,默默地留下了没有技术的泪水,如下图⬇️居然没有关键字和展现图片,在本菜狗的不懈努力下,终于抵赖技术不行,去求教了大佬,得出如下论断。 1.微信内置浏览器分享若须要自定义展现形容及右侧封面图,必须接入微信JSSDK,并且肯定须要有配合本站的微信公众号(appId和appSecret)才可自定义分享,切记小程序(appId和appSecret)的不能够2.非微信分享,如QQ浏览器,UC浏览器等各大厂商,会依据本身定义获取HTML页面中的TDK(title,description,keyword),举例UC浏览器分享⬇️所以,对接微信JSSDK,势在必行! Tip史上最具体的接入微信JSSDK菜鸟教程,本文全面的记录了接入微信JSSDK的步骤,具体的代码及遇到的坑,并且展现公布最终成果,并将代码公布GitHub。随篇幅较长,但史上最全。大佬勿喷,新手入门,亲测可用!!! 本文试用人群须要接入微信JSSDK却看不懂文档的同学看懂文档然而实操不知如何下手的同学下了手然而出错不晓得如何调试批改的同学胜利接入过然而想重温具体流程的同学本文指标实战进行H5网站微信自定义分享实战进行H5网站调取相册选取图片放松心态,缓缓来看 注释官网文档任何平台接入,官网文档是标杆,虽有些关键点一笔带过,咱们也要通读有个印象,点击微信官网文档打开文档,如下⬇️ 总览1.x是接入关键步骤,需认真品读,与接入无关2.x - 12.x 具体接口接入,须要对接时具体参考13.x 须要留神下,api_ticket 微信长期票据,与接入无关16-22 均是附录,可查阅谬误列表对应含意,及接口菜单列表等形容 实操步骤应用IDEA工具,新建SpringBoot我的项目,我的项目名为springboot-wexin,目录构造如下AjaxJson.java - 自定义接口返回前台数据格式的封装类 /** * Copyright &copy; 2005-2020 <a href="http://www.jhmis.com/">jhmis</a> All rights reserved. */package net.javadog.springbootwexin.common;import com.fasterxml.jackson.annotation.JsonIgnore;import java.util.LinkedHashMap;import java.util.List;/** * $.ajax后须要承受的JSON * */public class AjaxJson { private boolean success = true;// 是否胜利 private String errorCode = "-1";//错误代码 private String msg = "操作胜利";// 提示信息 private Long count; //返回表格记录数量 private List<?> data; //返回表格数据 private LinkedHashMap<String, Object> body = new LinkedHashMap<String, Object>();//封装json的map public static AjaxJson ok(){ AjaxJson j = new AjaxJson(); return j; } public static AjaxJson ok(String msg){ AjaxJson j = new AjaxJson(); j.setMsg(msg); return j; } public static AjaxJson ok(String msg, Object object){ AjaxJson j = new AjaxJson(); j.setMsg(msg); j.setResult(object); return j; } public static AjaxJson ok(Object object){ AjaxJson j = new AjaxJson(); j.setResult(object); return j; } public static AjaxJson fail(String errorMsg){ AjaxJson j = new AjaxJson(); j.setSuccess(false); j.setErrorCode("999");//默认错误码 j.setMsg(errorMsg); return j; } public static AjaxJson fail(String errorCode,String errorMsg){ AjaxJson j = new AjaxJson(); j.setSuccess(false); j.setErrorCode(errorCode); j.setMsg(errorMsg); return j; } //返回不分页的layui表数据 public static AjaxJson layuiTable(List<?> list){ AjaxJson j = new AjaxJson(); j.setSuccess(true); j.setCount(Long.valueOf(list.size())); j.setData(list); return j; } public LinkedHashMap<String, Object> getBody() { return body; } public void setBody(LinkedHashMap<String, Object> body) { this.body = body; } public void put(String key, Object value){//向json中增加属性,在js中拜访,请调用data.map.key body.put(key, value); } public void remove(String key){ body.remove(key); } /** * 间接设置result内容 * @param result */ public void setResult(Object result){ body.put("result", result); } @JsonIgnore//返回对象时疏忽此属性 public Object getResult(){ return body.get("result"); } public String getMsg() { return msg; } public void setMsg(String msg) {//向json中增加属性,在js中拜访,请调用data.msg this.msg = msg; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getErrorCode() { return errorCode; } public Long getCount() { return count; } public void setCount(Long count) { this.count = count; } public List<?> getData() { return data; } public void setData(List<?> data) { this.data = data; }}WxInitController.java - 微信初始化接入Controller控制器 ...

March 22, 2023 · 6 min · jiezi