-
今天主要分享一下在使用idea 2020.3版本开发maven项目的时候,一直出现有效件index, 有时候是scaning indexing, 有时候是update indexing, indexing的时候,idea基本上就没办法操作了,连跳入到类或方法里都跳不了。不厌其烦。于是开始在网上找解决方法: 得到的90%及以上的结果,都是让我点击: File-invalid cache/Restart, ,简直了,看到这我就想骂人,一看就是天下文章一大抄,应该根本就没有验证过,我试了一点也不管用。这样的作者 和文章真的是误导人。于是我就开始自己找方法,在stackoverflow上,有一个解决方案,说是在设置里,把下面红框千面的勾选去掉,试了,也不管用后来仔细观察了一下,每次它indexing都是在index jdk或者是 maven仓库,然后我就抱着试试看的态度,在设置里直接搜索index,果然又发现。把对应的jdk和maven改为不下载,使用本地索引。完美解决。补充: 其实做了如上的设置后,indexing的情况还是时有发生,只不过频率降低了一些,但是其实还是没有从根本上解决问题。后来无奈体验了各个版本的idea,发现在升级到了2021.3.2以后的版本,该问题再也没有出现过。所以大家如果一直被这个问题困扰,建议升级一下。
-
1.日志库2.JSON解析库3.单元测试库4.通用库5.HTTP 库6.XML 解析库7.Excel 阅读库8.字节码库9.数据库连接池库10.消息库11.PDF 库12.日期和时间库13.集合库14.电子邮件 API15.HTML 解析库16.密码库17.嵌入式 SQL 数据库库18.JDBC 故障排除库19.序列化库20.网络库优秀且经验丰富的 Java 开发人员的特点之一是对 API 的广泛了解,包括 JDK 和第三方库。如何使用现有的 API 进行开发,而不是为常见的东西编写新的代码。是提升开发效率必选之路。一般来说,我会为日常项目提供有用的库,包括 Log4j 等日志库、Jackson 等 JSON 解析库以及 JUnit 和 Mockito 等单元测试 API。如果您需要在项目中使用它们,则可以在项目的类路径中包含这些库的 JAR 以开始使用它们,也可以使用Maven进行依赖管理。对 Java 程序员有用的开源库下面是收集的一些有用的第三方库,Java 开发人员可以在他们的应用程序中使用它们来完成很多有用的任务。为了使用这些库,Java 开发人员应该熟悉这一点,这就是本文的重点。如果您有一个想法,那么您可以研究该库并使用它。1. 日志库日志库非常常见,因为您在每个项目中都需要它们。它们对于服务器端应用程序来说是最重要的,因为日志只放置在您可以看到应用程序正在发生什么的地方。尽管 JDK 附带了自己的日志库,但仍有更好的替代方案可用,例如 Log4j、SLF4j 和 LogBack。Java 开发人员应该熟悉日志库的优缺点,并知道为什么使用 SLF4j 比普通的 Log4j 更好。2. JSON解析库在当今的 Web 服务和物联网世界中,JSON 已成为将信息从客户端传输到服务器的首选协议。它们已取代 XML,成为以独立于平台的方式传输信息的首选方式。不幸的是,JDK 没有JSON 库。但是,有许多优秀的第三方库可以让您解析和创建 JSON 消息,例如 Jackson 和 Gson。Java Web 开发人员应该至少熟悉这些库中的一个。3. 单元测试库单元测试是将普通开发人员与优秀开发人员区分开来的最重要的事情。程序员经常得到不编写单元测试的借口,但避免单元测试的最常见借口是缺乏流行单元测试库的经验和知识,包括 JUnit、Mockito 和 PowerMock。图片4. 通用库Java 开发人员可以使用一些优秀的通用第三方库,例如 Apache Commons 和 Google Guava。我总是在我的项目中包含这些库,因为它们简化了很多任务。重新发明轮子是没有意义的。我们应该更喜欢使用久经考验的库,而不是时不时地编写我们自己的例程。图片Java 开发人员最好熟悉 Google Guava 和 Apache Commons 库。5. HTTP 库我不喜欢 JDK 的一件事是它们缺乏对 HTTP 的支持。虽然您可以使用包中的类建立 HTTP 连接 http://java.net,但使用开源第三方库(如 Apache HttpClient 和 HttpCore)并不容易或无缝。图片尽管 JDK 9 带来了对 HTTP 2.0 的支持以及对 HTTP 的更好支持,但我强烈建议所有 Java 开发人员熟悉流行的 HTTP 客户端库,包括 HttpClient 和 HttpCore。6. XML 解析库有许多 XML 解析库,包括 Xerces、JAXB、JAXP、Dom4j 和 Xstream。Xerces2 是 Apache Xerces 系列中的下一代高性能、完全兼容的 XML 解析器。这个新版本的 Xerces 引入了 Xerces Native Interface (XNI),这是一个用于构建解析器组件和配置的完整框架,它非常模块化且易于编程。图片Apache Xerces2 解析器是 XNI 的参考实现,但其他解析器组件、配置和解析器可以使用 Xerces Native Interface 编写。Dom4j 是另一个用于 Java 应用程序的灵活 XML 框架。7. Excel 阅读库信不信由你——所有现实世界的应用程序都必须以某种形式与 Microsoft Office 交互。许多应用程序需要提供在 Excel 中导出数据的功能,如果您必须从 Java 应用程序中执行相同操作,则需要 Apache POI API。这是一个非常丰富的库,允许您 从 Java 程序读取和写入 XLS 文件。您可以查看该链接以获取在核心 Java 应用程序中读取 Excel 文件的工作示例。8. 字节码库如果您正在编写生成代码或与字节码交互的框架或库,那么您需要一个字节码库。它们允许您读取和修改应用程序生成的字节码。Java 世界中一些流行的字节码库是 javassist 和 Cglib Nodep。图片Javassist(JAVA 编程助手)使 Java 字节码操作变得非常简单。它是一个用于在 Java 中编辑字节码的类库。ASM 是另一个有用的字节码编辑库。9. 数据库连接池库如果您从 Java 应用程序与数据库进行交互,但不使用数据库连接池库,那么,您会丢失一些东西。推荐程序员摸鱼地址:https://www.yoodb.com/slack-off/home.html由于在运行时创建数据库连接需要时间并且使请求处理速度变慢,因此始终建议使用数据库连接库。一些流行的是 Commons Pool 和 DBCP。在 Web 应用程序中,它的 Web 服务器通常提供这些功能,但在核心 Java 应用程序中,您需要将这些连接池库包含到您的类路径中才能使用数据库连接池。10. 消息库与日志记录和数据库连接类似,消息传递也是许多实际 Java 应用程序的共同特征。Java 提供 JMS 或 Java 消息传递服务,它不是 JDK 的一部分。对于此组件,您需要包含一个单独的 jms.jar图片同样,如果您使用第三方消息传递协议,例如 Tibco RV,那么您需要 tibrv.jar 在应用程序类路径中使用第三方 JAR 。11. PDF 库与 Microsoft Excel 类似,PDF 库是另一种普遍存在的格式。如果您需要在应用程序中支持 PDF 功能,例如 在 PDF 文件中导出数据,您可以使用 iText 和 Apache FOP 库。两者都提供有用的 PDF 相关功能,但 iText 更丰富更好。图片12. 日期和时间库在 Java 8 之前,JDK 的数据和时间库有很多缺陷,因为它们不是线程安全的、不可变的和容易出错的。许多 Java 开发人员依靠 JodaTime 来实现他们的日期和时间要求。从 JDK 8 开始,没有理由使用 Joda,因为您可以在 JDK 8 的新日期和时间 API中获得所有这些功能,但是如果您使用的是较旧的 Java 版本,那么 JodaTime 是一个值得学习的库。图片13. 集合库尽管 JDK 拥有丰富的集合库,但也有一些第三方库提供了更多选项,例如 Apache Commons 集合、Goldman Sachs 集合、Google 集合和 Trove。Trove 库特别有用,因为它为 Java 提供了高速的常规和原始集合。图片FastUtil 是另一个类似的 API。它通过提供特定类型的映射、集合、列表和优先级队列来扩展 Java 集合框架,这些映射、集合、列表和优先级队列具有较小的内存占用、快速访问和插入;它还提供大(64 位)数组、集合和列表,以及用于二进制和文本文件的快速、实用的 I/O 类。14. 电子邮件 APIjavax.mail 和 Apache Commons Email 都提供了用于从 Java 发送电子邮件的 API 。它建立在 JavaMail API 之上,旨在简化它。图片15. HTML 解析库与JSON和XML类似,HMTL 是我们许多人必须处理的另一种常见格式。值得庆幸的是,我们有 JSoup,它极大地简化了在 Java 应用程序中使用 HTML。您可以使用JSoup不仅解析 HTML,还可以创建 HTML 文档图片它提供了一个非常方便的 API 用于提取和操作数据,使用最好的DOM、CSS 和类似 jquery 的方法。JSoup 实现了 WHATWG HTML5 规范并将HTML解析为与现代浏览器相同的 DOM。16.密码库Apache Commons Codec 包包含各种格式的简单编码器和解码器,例如Base64和 Hexadecimal。除了这些广泛使用的编码器和解码器之外,编解码器包还维护了一组语音编码实用程序。图片17. 嵌入式 SQL 数据库库我真的很喜欢像 H2 这样的内存数据库,你可以将它嵌入到你的 Java 应用程序中。它们非常适合测试您的 SQL 脚本和运行需要数据库的单元测试。但是,H2 不是唯一的 DB,您还可以选择 Apache Derby 和 HSQL。图片18. JDBC 故障排除库有一些很好的 JDBC 扩展库可以让调试更容易,比如 P6spy。这是一个库,可以无缝拦截和记录数据库数据,而无需更改应用程序的代码。您可以使用它们来记录 SQL 查询及其时间。例如,如果您在代码中使用PreparedStatment和CallableStatement,这些库可以记录带有参数的准确调用以及执行所需的时间。图片19. 序列化库Google 协议缓冲区是一种以高效且可扩展的格式对结构化数据进行编码的方法。它是Java 序列化的更丰富和更好的替代方案。我强烈建议有经验的 Java 开发人员学习 Google Protobuf。图片20. 网络库一些有用的网络库是 Netty 和 Apache MINA。如果您正在编写需要执行低级网络任务的应用程序,请考虑使用这些库。图片以上就是今天小编分享给大家的一些工作中常用的库,了解并熟练的运用他们,不仅可以大大提高你的开发效率,也可以学习优秀代码的设计,提高自己的编码能力。
-
1 背景我们有个业务,会调用其他部门提供的一个基于http的服务,日调用量在千万级别。使用了httpclient来完成业务。之前因为qps上不去,就看了一下业务代码,并做了一些优化,记录在这里。先对比前后:优化之前,平均执行时间是250ms;优化之后,平均执行时间是80ms,降低了三分之二的消耗,容器不再动不动就报警线程耗尽了,清爽~2 分析项目的原实现比较粗略,就是每次请求时初始化一个httpclient,生成一个httpPost对象,执行,然后从返回结果取出entity,保存成一个字符串,最后显式关闭response和client。我们一点点分析和优化:2.1 httpclient反复创建开销httpclient是一个线程安全的类,没有必要由每个线程在每次使用时创建,全局保留一个即可。2.2 反复创建tcp连接的开销tcp的三次握手与四次挥手两大裹脚布过程,对于高频次的请求来说,消耗实在太大。试想如果每次请求我们需要花费5ms用于协商过程,那么对于qps为100的单系统,1秒钟我们就要花500ms用于握手和挥手。又不是高级领导,我们程序员就不要搞这么大做派了,改成keep alive方式以实现连接复用!2.3 重复缓存entity的开销原本的逻辑里,使用了如下代码:HttpEntityentity=httpResponse.getEntity();String response = EntityUtils.toString(entity);这里我们相当于额外复制了一份content到一个字符串里,而原本的httpResponse仍然保留了一份content,需要被consume掉,在高并发且content非常大的情况下,会消耗大量内存。并且,我们需要显式的关闭连接,ugly。3 实现按上面的分析,我们主要要做三件事:一是单例的client,二是缓存的保活连接,三是更好的处理返回结果。一就不说了,来说说二。提到连接缓存,很容易联想到数据库连接池。httpclient4提供了一个PoolingHttpClientConnectionManager 作为连接池。接下来我们通过以下步骤来优化:3.1 定义一个keep alive strategy关于keep-alive,本文不展开说明,只提一点,是否使用keep-alive要根据业务情况来定,它并不是灵丹妙药。还有一点,keep-alive和time_wait/close_wait之间也有不少故事。在本业务场景里,我们相当于有少数固定客户端,长时间极高频次的访问服务器,启用keep-alive非常合适再多提一嘴,http的keep-alive 和tcp的KEEPALIVE不是一个东西。回到正文,定义一个strategy如下:ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { @Override public long getKeepAliveDuration(HttpResponse response, HttpContext context) { HeaderElementIterator it = new BasicHeaderElementIterator (response.headerIterator(HTTP.CONN_KEEP_ALIVE)); while (it.hasNext()) { HeaderElement he = it.nextElement(); String param = he.getName(); String value = he.getValue(); if (value != null && param.equalsIgnoreCase ("timeout")) { return Long.parseLong(value) * 1000; } } return 60 * 1000;//如果没有约定,则默认定义时长为60s }};3.2 配置一个PoolingHttpClientConnectionManagerPoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();connectionManager.setMaxTotal(500);connectionManager.setDefaultMaxPerRoute(50);//例如默认每路由最高50并发,具体依据业务来定也可以针对每个路由设置并发数。3.3 生成httpclienthttpClient = HttpClients.custom() .setConnectionManager(connectionManager) .setKeepAliveStrategy(kaStrategy) .setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build()) .build();注意:使用setStaleConnectionCheckEnabled方法来逐出已被关闭的链接不被推荐。更好的方式是手动启用一个线程,定时运行closeExpiredConnections 和closeIdleConnections方法,如下所示。public static class IdleConnectionMonitorThread extends Thread { private final HttpClientConnectionManager connMgr; private volatile boolean shutdown; public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) { super(); this.connMgr = connMgr; } @Override public void run() { try { while (!shutdown) { synchronized (this) { wait(5000); // Close expired connections connMgr.closeExpiredConnections(); // Optionally, close connections // that have been idle longer than 30 sec connMgr.closeIdleConnections(30, TimeUnit.SECONDS); } } } catch (InterruptedException ex) { // terminate } } public void shutdown() { shutdown = true; synchronized (this) { notifyAll(); } } }3.4 使用httpclient执行method时降低开销这里要注意的是,不要关闭connection。推荐程序员摸鱼地址:https://www.yoodb.com/slack-off/home.html一种可行的获取内容的方式类似于,把entity里的东西复制一份:res = EntityUtils.toString(response.getEntity(),"UTF-8");EntityUtils.consume(response1.getEntity());但是,更推荐的方式是定义一个ResponseHandler,方便你我他,不再自己catch异常和关闭流。在此我们可以看一下相关的源码:public <T> T execute(final HttpHost target, final HttpRequest request, final ResponseHandler<? extends T> responseHandler, final HttpContext context) throws IOException, ClientProtocolException { Args.notNull(responseHandler, "Response handler"); final HttpResponse response = execute(target, request, context); final T result; try { result = responseHandler.handleResponse(response); } catch (final Exception t) { final HttpEntity entity = response.getEntity(); try { EntityUtils.consume(entity); } catch (final Exception t2) { // Log this exception. The original exception is more // important and will be thrown to the caller. this.log.warn("Error consuming content after an exception.", t2); } if (t instanceof RuntimeException) { throw (RuntimeException) t; } if (t instanceof IOException) { throw (IOException) t; } throw new UndeclaredThrowableException(t); } // Handling the response was successful. Ensure that the content has // been fully consumed. final HttpEntity entity = response.getEntity(); EntityUtils.consume(entity);//看这里看这里 return result;}可以看到,如果我们使用resultHandler执行execute方法,会最终自动调用consume方法,而这个consume方法如下所示:public static void consume(final HttpEntity entity) throws IOException { if (entity == null) { return; } if (entity.isStreaming()) { final InputStream instream = entity.getContent(); if (instream != null) { instream.close(); } }}可以看到最终它关闭了输入流。4 其他通过以上步骤,基本就完成了一个支持高并发的httpclient的写法,下面是一些额外的配置和提醒:4.1 httpclient的一些超时配置CONNECTION_TIMEOUT是连接超时时间,SO_TIMEOUT是socket超时时间,这两者是不同的。连接超时时间是发起请求前的等待时间;socket超时时间是等待数据的超时时间。HttpParams params = new BasicHttpParams();//设置连接超时时间Integer CONNECTION_TIMEOUT = 2 * 1000; //设置请求超时2秒钟 根据业务调整Integer SO_TIMEOUT = 2 * 1000; //设置等待数据超时时间2秒钟 根据业务调整 //定义了当从ClientConnectionManager中检索ManagedClientConnection实例时使用的毫秒级的超时时间//这个参数期望得到一个java.lang.Long类型的值。如果这个参数没有被设置,默认等于CONNECTION_TIMEOUT,因此一定要设置。Long CONN_MANAGER_TIMEOUT = 500L; //在httpclient4.2.3中我记得它被改成了一个对象导致直接用long会报错,后来又改回来了 params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, CONNECTION_TIMEOUT);params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SO_TIMEOUT);params.setLongParameter(ClientPNames.CONN_MANAGER_TIMEOUT, CONN_MANAGER_TIMEOUT);//在提交请求之前 测试连接是否可用params.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true); //另外设置http client的重试次数,默认是3次;当前是禁用掉(如果项目量不到,这个默认即可)httpClient.setHttpRequestRetryHandler(newDefaultHttpRequestRetryHandler(0,false));4.2 如果配置了nginx的话,nginx也要设置面向两端的keep-alive现在的业务里,没有nginx的情况反而比较稀少。nginx默认和client端打开长连接而和server端使用短链接。注意client端的keepalive_timeout和keepalive_requests参数,以及upstream端的keepalive参数设置,这三个参数的意义在此也不再赘述。以上就是我的全部设置。通过这些设置,成功地将原本每次请求250ms的耗时降低到了80左右,效果显著。JAR包如下:<!-- httpclient --><dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version></dependency>代码如下://Basic认证private static final CredentialsProvider credsProvider = new BasicCredentialsProvider();//httpClientprivate static final CloseableHttpClient httpclient;//httpGet方法private static final HttpGet httpget;//private static final RequestConfig reqestConfig;//响应处理器private static final ResponseHandler<String> responseHandler;//jackson解析工具private static final ObjectMapper mapper = new ObjectMapper(); static { System.setProperty("http.maxConnections","50"); System.setProperty("http.keepAlive", "true"); //设置basic校验 credsProvider.setCredentials( new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM), new UsernamePasswordCredentials("", "")); //创建http客户端 httpclient = HttpClients.custom() .useSystemProperties() .setRetryHandler(new DefaultHttpRequestRetryHandler(3,true)) .setDefaultCredentialsProvider(credsProvider) .build(); //初始化httpGet httpget = new HttpGet(); //初始化HTTP请求配置 reqestConfig = RequestConfig.custom() .setContentCompressionEnabled(true) .setSocketTimeout(100) .setAuthenticationEnabled(true) .setConnectionRequestTimeout(100) .setConnectTimeout(100).build(); httpget.setConfig(reqestConfig); //初始化response解析器 responseHandler = new BasicResponseHandler();}/* * 功能:返回响应 * @author zhangdaquan * @param [url] * @return org.apache.http.client.methods.CloseableHttpResponse * @exception */public static String getResponse(String url) throws IOException { HttpGet get = new HttpGet(url); String response = httpclient.execute(get,responseHandler); return response;} /* * 功能:发送http请求,并用net.sf.json工具解析 * @author zhangdaquan * @param [url] * @return org.json.JSONObject * @exception */public static JSONObject getUrl(String url) throws Exception{ try { httpget.setURI(URI.create(url)); String response = httpclient.execute(httpget,responseHandler); JSONObject json = JSONObject.fromObject(response); return json; } catch (IOException e) { e.printStackTrace(); } return null;} /* * 功能:发送http请求,并用jackson工具解析 * @author zhangdaquan * @param [url] * @return com.fasterxml.jackson.databind.JsonNode * @exception */public static JsonNode getUrl2(String url){ try { httpget.setURI(URI.create(url)); String response = httpclient.execute(httpget,responseHandler); JsonNode node = mapper.readTree(response); return node; } catch (IOException e) { e.printStackTrace(); } return null;}/* * 功能:发送http请求,并用fastjson工具解析 * @author zhangdaquan * @param [url] * @return com.fasterxml.jackson.databind.JsonNode * @exception */public static com.alibaba.fastjson.JSONObject getUrl3(String url){ try { httpget.setURI(URI.create(url)); String response = httpclient.execute(httpget,responseHandler); com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(response); return jsonObject; } catch (IOException e) { e.printStackTrace(); } return null;}
-
(1) 什么是MVC? MVC是一种设计思想,根据职责不同将程序中的组件分成以下3个部分。 V(View视图):负责与用户交互。将数据展现,或者是接收数据 M(Model模型):负责业务处理。业务模型,数据模型 C(Controller控制器):负责协同模型和视图工作。视图有请求调用模型处理,模型处理完毕调用视图响应。(2)为什么使用MVC? MVC是一个非常优秀的设计思想,基于该思想架构程序,可以提高程序的结构灵活性,便于日后维护、扩展和升级。注意:下面内容助于理解:1) 一个模型可以被多个视图共享模型只负责输出数据,不关心数据的表现形式,同一仹数据,可以使用多个不同的视图展现给用户。模型只负责处理数据,不关心是谁在调用,可以使用多种不同的界面来调用模型。2) 方便测试 模型一般使用java 类来开发,在开发完成之后,可以立即测试。如果业务逻辑直接写在servlet里面,则需要部署在服务器上面才能测试,比较麻烦。3) 组件复用 控制器可以做成一个通用的模块。4) 代码好维护,利于分工协作。 按照 mvc 的思想,可以对程序迚行分层,一般划分成表示层(包括 v,c)、业务层(m中的业务逻辑部分)、持久层(m中的数据访问逻辑部分)。下一层的代码发生改变,只要接口不变,不会影响到上一层的代码。mvc的缺点1) 采用 mvc 以后,会增加代码量,相应的开发周期以及开发的成本会相应增加。2) 使用 mvc,需要良好的设计。如果设计不当,会增加开发的难度。在表示层Servlet中调用业务层代码的接口,当业务层发生改变时不影响Servelt ;在业务层Service中调用DAO的接口,DAO发生改变不影响Service和其上层 结论一般来说,如果一个程序需要良好的架构,需要良好的代码的可维护性及可扩展性,需要使用mvc思想来架构。反之,则不必使用。
-
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。AJAX编程步骤?1) 获得 XmlHttpRequest对象2) 使用 XmlHttpRequest向服务器发请求。 a.发送get请求: /* open(请求方式,请求地址,同步/异步) * 请求方式: get/post * 请求地址:如果是get请求,请求参数添加到地址之后。 * 比如 check_user.do?username=zs * 同步/异步:true 表示异步。*/xhr.open('get','check_user.do',true); b. 发送 post 请求:xhr.open('post','check_username.do',true); //#必须添加一个消息头content-type xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");3). 在服务器端,处理请求。4).在监听器当中,处理服务器返回的响应。xhr.onreadystatechange=function(){ //编写相应的处理代码 if(xhr.readyState == 4){ //只有 readyState 等亍 4,xhr 才完整地接收到了服务器返回的数据。 //获得文本数据 var txt = xhr.responseText; //获得一个xml dom对象。 var xml = xhr.responseXML; //dom操作、更新页面 } };5.xhr.send(null)AJAX技术的优点? 1.页面无刷新 2.不打断用户的操作,用户的体验好 3.按需获取数据,浏览器和服务器之间数据的传输量减少 4.是一个标准技术,不需要下载任何的插件 5.可以利用客户端(浏览器)的计算能力
-
前言本篇文章体验华为云问答机器人API调用总结的文章,包含遇到的问题,如认鉴权等。一、开通使用来到华为云“免费体验中心”——>找到“对话机器人服务”——>开通免费体验在控制台找到对话机器人服务,可以看到机器人ID等信息。新建语料在问答机器人列表中,单击“机器人管理”。在“问答机器人”页面左侧导航栏中选择“知识库 > 问答管理”,在问答管理页面执行如下操作。在问答管理中单击按钮新建问题分类,例如“IT问题”。在问答管理中单击“新建”创建问答语料对话体验在页面右上角单击“对话体验”,展开对话窗口。在窗口中,输入“蓝屏了怎么办”,查看是否可以获得准确答案。您可以根据业务实际情况进行提问,当机器人无法回答时,建议根据实际情况补充语料或补充扩展问。下面我们在现在的对话机器人基础上实现问答接口调用二、API调用这里选择java API调用和PostMan调用endpoint是你的开通服务的终端节点:cbs-ext.cn-north-4.myhuaweicloud.comproject_id:项目idqabot_id:机器人idPOST:POST https://{endpoint}/v1/{project_id}/qabots/{qabot_id}/chat Request Header: Content-Type: application/json X-Auth-Token: 认证鉴权的信息 Request Body: { "question": "桌面云打不开了" } Java语言:import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; public class CBSDemo { public void cbsDemo() { try { //endpoint、projectId、qabot_id需要替换成实际信息。 URL url = new URL("https://{endpoint}/v1/{project_id}/qabots/{qabot_id}/chat"); String token = "用户获取得到的实际token值"; HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoInput(true); connection.setDoOutput(true); connection.addRequestProperty("Content-Type", "application/json"); connection.addRequestProperty("X-Auth-Token", token); //输入参数 String body = "{\"question\": \"用户问\"}"; OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); osw.append(body); osw.flush(); InputStream is = connection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); while (br.ready()) { System.out.println(br.readLine()); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { CBSDemo CBSDemo = new CBSDemo(); CBSDemo.cbsDemo(); } } 现在Token的值大家还不知道,继续往下看。三、认证鉴权问题这里遇到的问题就是认证鉴权问题,说一下:华为云的这个token获取,出现错误返回的概率很大,解决和原因下面我会讲解。这里介绍Token认证:通过Token认证通用请求POST: https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens { "auth": { "identity": { "methods": [ "password" ], "password": { "user": { "name": "***", "password": "***", "domain": { "name": "***" } } } }, "scope": { "project": { "name": "cn-north-4" } } } }上面的***都是需要替换的,替换成你的。Token获取控制台找到“我的凭证”:将上面图片的账号名填在下面:POST: https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens { "auth": { "identity": { "methods": [ "password" ], "password": { "user": { "name": "***", "password": "自己的密码,如果自己以前没印象用过这个,很大概率是你的华为云账号的密码", "domain": { "name": "账号名" } } } }, "scope": { "project": { "name": "cn-north-4" } } } } 这里还有个name的值没有填,但也是很多开发者出现错误返回的原因:当你的统一认证的用户组只有admin时是不行的,这个具体原因我不太清楚,主要是华为云控制台自带的初始admin用户组是不行的,你需要自己创建一个新的用户组,创建一个新的用户添加到新创建的用户组就可,大致流程如下:这时,上面的name就是haoze了,具体是你创建的用户名。然后用PostMan工具发送请求得到返回的token:没有PostMan的可以使用华为云控制台的API Explorer工具总结以上就是华为对话机器人服务的体验讲解以及问题解决。
-
使用 Swagger 你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面官网: swagger.io/ Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的增强解决方案 使用方式 1. 导入坐标 <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> </dependency> 2. 在配置类中加入 knife4j 相关配置 /** * 通过knife4j生成接口文档 * @return */ @Bean public Docket docket() { ApiInfo apiInfo = new ApiInfoBuilder() .title("苍穹外卖项目接口文档") .version("2.0") .description("苍穹外卖项目接口文档") .build(); Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) .paths(PathSelectors.any()) .build(); return docket; } 3. 设置静态资源映射,否则接口文档页面无法访问 /** * 设置静态资源映射 * @param registry */ protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } 常用注解 查看效果 启动项目后访问如下地址: localhost:8080/doc.html 成功 附完整配置类代码: package com.sky.config;import com.sky.interceptor.JwtTokenAdminInterceptor;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;/** * 配置类,注册web层相关组件 */@Configuration@Slf4jpublic class WebMvcConfiguration extends WebMvcConfigurationSupport { @Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor; /** * 注册自定义拦截器 * * @param registry */ protected void addInterceptors(InterceptorRegistry registry) { log.info("开始注册自定义拦截器..."); registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns("/admin/**") .excludePathPatterns("/admin/employee/login"); } /** * 通过knife4j生成接口文档 * @return */ @Bean public Docket docket() { log.info("准备生成接口文档..."); ApiInfo apiInfo = new ApiInfoBuilder() .title("苍穹外卖项目接口文档") .version("2.0") .description("苍穹外卖项目接口文档") .build(); Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) .paths(PathSelectors.any()) .build(); return docket; } /** * 设置静态资源映射 * @param registry */ protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info("开始设置静态资源映射..."); registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); }} 转载自https://learnku.com/articles/85427
-
大家应该都知道,按照出现的顺序,spring全家桶大概包含了spring、springmvc、springboot以及springcloud,从开胃小菜spring到满汉全席springcloud,spring全家桶可谓Java工程师的必备大餐,那么,我们不妨先来看看,spring全家桶是如何从光杆司令spring发展到如今的庞大家族的。 想要精通Spring的你,不妨来翻一翻这份大神整理出来的367页PDF,我想这应该是对“Spring家族”最完美的诠释了。 Key1:攻克Spring5 ①Spring-手绘脑图 (基本概念+AOP+事务管理+IOC+MVC+Spring类等) ②Spring5高级编程 ③Spring源码解析 第一部分:核心实现(Spring整体架构和环境搭建+容器的基本实现+默认标签的解析+自定义标签的解析+bean的加载+容器的功能扩展+AOP) 第二部分:企业应用(数据库连接JDBC+整合MyBatis+事务+SpringMVC+远程服务+Spring消息) ④Spring源码笔记 (Spring概述+核心思想+手写实现IOC和AOP+SpringIOC应用+SpringIOC源码深度剖析+SpringAOP应用+SpringAOP源码深度剖析) ⑤Spring面试题(高级应用篇) 什么是Spring 框架?Spring 框架有哪些主要模块? 使用 Spring 框架能带来哪些好处? 什么是控制反转(IOC)?什么是依赖注入? 请解释下 Spring 框架中的 IoC? BeanFactory 和 ApplicationContext 有什么区别? Spring 有几种配置方式? 如何用基于 XML 配置的方式配置 Spring? 如何用基于 Java 配置的方式配置 Spring? 怎样用注解的方式配置 Spring? 请解释 Spring Bean 的生命周期? Spring Bean 的作用域之间有什么区别? 什么是 Spring inner beans? Spring 框架中的单例 Beans 是线程安全的么? 请举例说明如何在 Spring 中注入一个 Java Collection? 如何向 Spring Bean 中注入一个 Java.util.Properties? 请解释 Spring Bean 的自动装配? 请解释一下自动装配模式的区别? 如何开启基于注解的自动装配? 请举例解释@Required 注解? 请举例解释@Autowired 注解? 请举例说明@Qualifier 注解? 构造方法注入和设值注入有什么区别? Spring 框架中有哪些不同类型的事件? FileSystemResource 和 ClassPathResource 有何区别? Spring 框架中都用到了哪些设计模式? 开发中主要使用 Spring 的什么技术 ? 简述 AOP 和 IOC 概念 AOP 在 Spring 中如何配置 Bean ? IOC 容器对 Bean 的生命周期 答案: Key2:攻克Spring Boot ①Spring Boot-手绘脑图 ②Spring Boot实战 (入门+开发的第一个应用程序+自定义配置+测试+Groovy与Spring Boot CLI+在Spring Boot中使用Grails+深入Actuator+部署Spring Boot应用程序) ③Spring Boot 学习笔记-核心部分 (Spring Boot入门+配置文件+日志+Web开发+Docker+SpringBoot与数据访问+启动配置原理+自定义starter) ④Spring Boot面试题(高级应用篇) 什么是 Spring Boot? Spring Boot 有哪些优点? 什么是 JavaConfig? 如何重新加载 Spring Boot 上的更改,而无需重新启动服务器? Spring Boot 中的监视器是什么? 如何在 Spring Boot 中禁用 Actuator 端点安全性? 如何在自定义端口上运行 Spring Boot 应用程序? YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。 如何实现 Spring Boot 应用程序的安全性? 如何集成 Spring Boot 和 ActiveMQ? 如何使用 Spring Boot 实现分页和排序? 什么是 Swagger?你用 Spring Boot 实现了它吗? 什么是 Spring Profiles? 什么是 Spring Batch? 什么是 FreeMarker 模板? 如何使用 Spring Boot 实现异常处理? 您使用了哪些 starter maven 依赖项? 什么是 CSRF 攻击? 什么是 WebSockets? 什么是 AOP? 什么是 Apache Kafka? 我们如何监视所有 Spring Boot 微服务? 答案: Key3:攻克Spring MVC ①Spring MVC-手绘脑图 ②Spring MVC源码分析与实践 (Spring框架+模型2和MVC模式+SpringMVC介绍+基于注解的控制器+数据绑定和表单标签库+转换器和格式化+验证器+表达式语言+JSTL+国际化+上传文件+下载文件+应用测试) ③Spring MVC学习笔记 ④Spring MVC面试题(高级应用篇) 什么是 SpringMVC? 说说Spring MVC 的优点 SpringMVC 工作原理 SpringMVC 流程 SpringMvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决? 如果你也用过 struts2.简单介绍下 springMVC 和 struts2 的区别有哪些? SpingMVC 中的控制器的注解一般用哪个,有没有别的注解可以替代? @RequestMapping 注解用在类上面有什么作用? 怎么样把某个请求映射到特定的方法上面? 如果在拦截请求中,我想拦截 get 方式提交的方法,怎么配置? 怎么样在方法里面得到 Request,或者 Session? 我想在拦截的方法里面得到从前台传入的参数,怎么得到? 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象? SpringMVC 中函数的返回值是什么? SpringMVC 怎么样设定重定向和转发的? SpringMVC 用什么对象从后台向前台传递数据的? SpringMVC 中有个类把视图和数据都合并的一起的,叫什么? 怎么样把 ModelMap 里面的数据放入 Session 里面? SpringMVC 怎么和 AJAX 相互调用的? 当一个方法向 AJAX 返回特殊对象,比如 Object,List 等,需要做什么处理? SpringMVC 里面拦截器是怎么写的? 讲下 SpringMVC 的执行流程 面试: Key4:攻克Spring Cloud ①Spring Cloud-手绘脑图 ②Spring Cloud参考指南 ③Spring Cloud学习笔记 第一篇:基础服务篇(微服务与SpringCloud+服务发现+配置中心+客户端负载均衡+熔断器+Zuul+网关新选择+调用链追踪+加密管理+公共子项目) 第二篇:任务与消息篇(消息驱动+消息总线+批处理) 第三篇:微服务实战篇(利用Docker进行编排与整合) ④Spring Cloud面试题(高级应用篇) 什么是 Spring Cloud? 使用 Spring Cloud 有什么优势? 服务注册和发现是什么意思?Spring Cloud 如何实现? 负载平衡的意义什么? 什么是 Hystrix?它如何实现容错? 什么是 Hystrix 断路器?我们需要它吗? 什么是 Netflix Feign?它的优点是什么? 什么是 Spring Cloud Bus?我们需要它吗? ———————————————— 原文链接:https://blog.csdn.net/weixin_66896902/article/details/126464926
-
1、spring是一个容器、生态、框架 Spring框架为开发提供了一系列的解决方案,比如利用控制反转的核心特性,并通过依赖注入实现控制反转来实现管理对象生命周期容器化,利用面向切面编程进行声明式的事务管理,整合多种持久化技术管理数据访问,提供大量优秀的Web框架方便开发等等。Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上特定Java注解来配置对象,开发者可以通过依赖查找或依赖注入来获得对象。Spring框架具有面向切面编程(AOP)框架,SpringAOP框架基于代理模式,同时运行时可配置;AOP框架主要针对模块之间的交叉关注点进行模块化。Spring框架下的事务管理、远程访问等功能均可以通过使用SpringAOP技术实现。 spring首先是一个框架,在我们整个开发流程中,所有的框架生产几乎全都依赖于spring,spring帮我们起到了一个IOC容器的作用,用来承载整体的bean对象,帮我们进行了对象的创建到销毁的整个生命周期的管理。在使用spring的时候可以使用配置文件也可以使用注解的方式来进行相关实现,在程序启动后,把配置文件或者注解定义好的那些bean对象转换成beanDefination,要完成整个beanDefination的解析到加载的过程,获得完整的对象之后,下一步要对beanDefination进行实例化操作,在进行实例化的时候最简单的方式是使用反射的方式来创建对象,当对象创建完成之后,之后要实现Aware、BeanPostProcessor接口的一些操作,初始化对象的一些操作 1.1IOC容器(存放bean对象) IOC(Inversion of Control): IOC容器控制管理bean对象,实现解耦。 控制翻转,其根本是依赖注入(Dependecy Injection),不会直接创建对象,只是把对象声明出来,在代码 中不直接与对象和服务进行连接,但是在配置文件中描述了哪一项组件需要哪一项服务,容器将他们组合起来。在一般的IOC场景中容器创建了所有的对象,并设置了必要的属性将他们联系在一起,等到需要使用的时候才把他们声明出来,使用注解就更方便了,容器会自动根据注 解把对象组合起来。 是我们在使用spring中最重要的一个方面,spring容器里面放的是一个一个的bean对象,spring在启动时通过BeanDefinitionReader读取XML配置文件或者注解(bean的定义信息)获取bean对象: 下图说明: BeanDefinitionReader将配置文件信息解析成BeanDefinition(有$占位符), BeanFactoryPostProcessor将此信息在解析成完整的BeanDefinition对象(将信息传入,去掉$占位符) 1 2 3 1.1.2 bean生命周期(复杂) 1)Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化,在堆开辟新空间,使用反射实现对象的实例化 2)Bean实例化后对将Bean的引入和值注入到Bean的属性中 3)如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法 4)如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入 5)如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。 6)如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。 7)如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用 8)如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。 9)此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。 10)如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。 参考文档:https://www.cnblogs.com/javazhiyin/p/10905294.html 1.1.3 bean生命周期(简单): 实例化 Instantiation 属性赋值 Populate 初始化 Initialization 销毁 Destruction 1)实例化(Instantiation) //实例化是指Bean 从Bean到Object Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 2)属性赋值(Populate) 3)初始化(Initialization) 初始化前: org.springFrameWork.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization 初始化中: org.springFrameWork.bean.InitializingBean#afterPropertiesSet 初始化后:org.springFrameWork.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization 4)销毁 参考文档:https://www.jianshu.com/p/1dec08d290c1 1.2 AOP面向切面编程 AOP:面向切面编程,底层实现是动态代理(JDK、CGlib) web层级设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面。编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。 将方法注入到接口调用的某个地方(切点)。 1.2.1 相关概念: 1)Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。 2)Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。 3)Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。 4)Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。 5)Target(目标对象):织入 Advice 的目标对象.。 6)Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程 参考文档:https://blog.csdn.net/q982151756/article/details/80513340 1.3 JdbcTemplate JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。 在JdbcTemplate中执行SQL语句的方法大致分为3类: 1)execute:可以执行所有SQL语句,一般用于执行DDL语句。 2)update:用于执行INSERT、UPDATE、DELETE等DML语句。 3)queryXxx:用于DQL数据查询语句。 1.4 事物 1.4.1、事物的特性 1.4.1.1、原子性(Atomicity): 事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。 1.4.1.2、一致性(Consistency): 一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。 1.4.1.3、隔离性(Isolation): 可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。 1.4.1.4、持久性(Durability): 一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。 1.4.2、spring事物配置方式 1)编程式事物管理:是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。 2)声明式事物管理:建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。 声明式事务管理要优于编程式事务管理:声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。 1.4.3、事物的隔离级别 参考文档:https://www.cnblogs.com/mseddl/p/11577846.html 1.5 循环依赖 循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。 Spring中循环依赖场景有: (1)构造器的循环依赖 (2)field属性的循环依赖。 1.5.1、检测是否存在循环依赖 Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了。 1.5.2、spring解决循环依赖 Spring为了解决单例的循环依赖问题,使用了三级缓存。 这三级缓存分别指: singletonFactories : 单例对象工厂的cache earlySingletonObjects :提前暴光的单例对象的Cache singletonObjects:单例对象的cache。 参考文档:https://blog.csdn.net/u010853261/article/details/77940767 2、SpringMVC 2.1、springMVC简介 M:model,模型层,模型就是数据 V:view,网页、jsp,显示数据 C:controller,控制层,控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。 Spring MVC主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。 他的两个核心是两个核心: 1)处理器映射:选择使用哪个控制器来处理请求 2)视图解析器:选择结果应该如何渲染 2.1.1、运行原理 (1) Http请求:客户端请求提交到DispatcherServlet。 (2) 寻找处理器:由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller。 (3) 调用处理器:DispatcherServlet将请求提交到Controller。 (4)调用业务处理和返回结果:Controller调用业务逻辑处理后,返回ModelAndView。 (5)处理视图映射并返回模型: DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图。 (6) Http响应:视图负责将结果显示到客户端。 2.1.2、SpringMVC接口解释 (1)DispatcherServlet接口: Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。 (2)HandlerMapping接口: 能够完成客户请求到Controller映射。 (3)Controller接口: 需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。 Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。 从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。 (4)ViewResolver接口: Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。 2.1.3、DispatcherServlet: 是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项: (1)截获符合特定格式的URL请求。 (2)初始化DispatcherServlet上下文对应WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。 (3)初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。 参考文档:https://blog.csdn.net/jianyuerensheng/article/details/51258942 3、springBoot 3.1springboot简介 用来简化spring初始搭建的过程,将配置文件转换成注解的形式,方便迅速。Spring Boot 提供了大量开箱即用(out-of-the-box)的依赖模块,例如 spring-boot-starter-redis、spring-boot-starter-data-mongodb 和 spring-boot-starter-data-elasticsearch 等。这些依赖模块为 Spring Boot 应用提供了大量的自动配置,使得 Spring Boot 应用只需要非常少量的配置甚至零配置,便可以运行起来。 3.2、特点 1)独立运行的 Spring 项目 Spring Boot 可以以 jar 包的形式独立运行,Spring Boot 项目只需通过命令“ java–jar xx.jar” 即可运行。 2) 内嵌 Servlet 容器 Spring Boot 使用嵌入式的 Servlet 容器(例如 Tomcat、Jetty 或者 Undertow 等),应用无需打成 WAR 包 。 3) 提供 starter 简化 Maven 配置 Spring Boot 提供了一系列的“starter”项目对象模型(POMS)来简化 Maven 配置。 4) 提供了大量的自动配置 Spring Boot 提供了大量的默认自动配置,来简化项目的开发,开发人员也通过配置文件修改默认配置。 5) 自带应用监控 Spring Boot 可以对正在运行的项目提供监控。 6) 无代码生成和 xml 配置 Spring Boot 不需要任何 xml 配置即可实现 Spring 的所有配置。 参考文档:http://c.biancheng.net/spring_boot/overview.html 4、springCloud Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。Spring Cloud 并不重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开发成本。换句话说:Spring Cloud 提供了构建分布式系统所需的“全家桶”。 4.1、优点: 1)集大成者,Spring Cloud 包含了微服务架构的方方面面。 2)约定优于配置,基于注解,没有配置文件。 3)轻量级组件,Spring Cloud 整合的组件大多比较轻量级,且都是各自领域的佼佼者。 4)开发简便,Spring Cloud 对各个组件进行了大量的封装,从而简化了开发。 5)开发灵活,Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件。 4.2、Spring Cloud 模块的相关介绍: Eureka:服务注册中心,用于服务管理。 Ribbon:基于客户端的负载均衡组件,默认的负载策略是轮询。 Hystrix:容错框架,能够防止服务的雪崩效应。 Feign:Web 服务客户端,能够简化 HTTP 接口的调用。 Zuul:核心是过滤器,API 网关,提供路由转发、请求过滤等功能,是一个基于 JVM 路由和服务端的负载均衡器。 Config:分布式配置管理。 Sleuth:服务跟踪。 Stream:构建消息驱动的微服务应用程序的框架。 Bus:消息代理的集群消息总线。 4.2.1、 服务治理 Eureka 和 Zookeeper 区别: Eureka 是基于 AP 原则构建的,而 ZooKeeper 是基于 CP 原则构建的。 注: 在分布式系统领域有个著名的 CAP 定理,即 C 为数据一致性;A 为服务可用性;P 为服务对网络分区故障的容错性。这三个特性在任何分布式系统中都不能同时满足,最多同时满足两个。 服务治理就是服务的自动化管理,其核心是服务的自动注册与发现 1)服务注册:服务实例将自身服务信息注册到注册中心 2)服务发现:服务实例通过注册中心,获取注册到其中的服务实例的信息,通过这些信息去请求题目提供的服务 3)服务剔除:服务注册中心将出问题的服务自动剔除可使用服务列表,使其不会被调用 参考文档:http://c.biancheng.net/spring_cloud/ 5、SSM Java 企业开发框架 SSM,即 Spring、SpringMVC、MyBatis 。 Spring框架:是一个轻量级 Java 开发框架,主要是为了解决企业应用开发的复杂性而创建的。 SpringMVC框架:SpringMVC 分离了 控制器、模型对象、分派器,让我们更容易进行开发定制 MyBatis框架:是一个 Java 持久层框架,用于操作数据库,消除了几乎所有的 JDBC 代码,使用简单的 XML 或 注解即可完成数据库操作。 ———————————————— 原文链接:https://blog.csdn.net/weixin_47268011/article/details/118188608
-
1.1 系统架构演变随着互联网的发展,网站应用的规模也在不断的扩大,进而导致系统架构也在不断的进行变化。系统架构大体经历了下面几个过程: 单体应用架构—>垂直应用架构—>分布式架构—>SOA架构—>微服务架构,当然还有悄然兴起的Service Mesh(服务网格化)。接下来我们就来了解一下每种系统架构是什么样子的, 以及各有什么优缺点。1.1.1 单体应用架构web项目,然后部署到一台tomcat服务器上优点:项目架构简单,小型项目的话, 开发成本低项目部署在一个节点上, 维护方便缺点:全部功能集成在一个工程中,对于大型项目来讲不易开发和维护项目模块之间紧密耦合,单点容错率低无法针对不同模块进行针对性优化和水平扩展1.1.2 垂直应用架构所谓的垂直应用架构,就是将原来的一个应用拆成互不相干的几个应用,以提升效率。这样拆分完毕之后,一旦某个应用用户访问量变大,只需要增加对应应用节点就可以了,而无需增加其他节点。优点:系统拆分实现了流量分担,解决了并发问题,而且可以针对不同模块进行优化和水扩展一个系统的问题不会影响到其他系统,提高容错率缺点:系统之间相互独立, 无法进行相互调用系统之间相互独立, 会有重复的开发任务1.1.3 分布式架构分布式系统架构,它把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。优点:抽取公共的功能为服务层,提高代码复用性缺点:系统间耦合度变高,调用关系错综复杂,难以维护1.1.4 SOA架构增加一个调度中心对集群进行实时管理。此时,用于资源调度和治理中心(SOA Service OrientedArchitecture,面向服务的架构)是关键。优点:使用注册中心解决了服务间调用关系的自动调节缺点:服务间会有依赖关系,一旦某个环节出错会影响较大( 服务雪崩 )服务关心复杂,运维、测试部署困难1.1.5 微服务架构微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步,它更加强调服务的"彻底拆分"。优点:服务原子化拆分,独立打包、部署和升级,保证每个微服务清晰的任务划分,利于扩展微服务之间采用Restful等轻量级http协议相互调用缺点:分布式系统开发的技术成本高(容错、分布式事务等)1.2 微服务架构介绍微服务架构, 简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。1.2.1 微服务架构的常见问题一旦采用微服务系统架构,就势必会遇到这样几个问题:这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?(restful rpc)这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错? (链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。常见的微服务组件及发展趋势1.2.2 微服务架构的常见概念1.2.2.1 服务治理服务治理就是进行服务的自动化管理,其核心是服务的自动注册与发现。服务注册:服务实例将自身服务信息注册到注册中心。服务发现:服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。服务剔除:服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。1.2.2.2 服务调用在微服务架构中,通常存在多个服务之间的远程调用的需求。目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。(Representational State Transfer)这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协议RPC(Remote Promote Call)一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式、序列化方式和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。区别与联系比较项 RESTful RPC通讯协议 HTTP 一般使用TCP性能 略低 较高灵活度 高 低应用 微服务架构 SOA架构1.2.2.3 服务网关随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:客户端需要调用不同的url地址,增加难度在一定的场景下,存在跨域请求的问题每个微服务都需要进行单独的身份认证针对这些问题,API网关顺势而生。API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。1.2.2.4 服务容错在微服务当中,一个请求经常会涉及到调用几个服务,如果其中某个服务不可用,没有做服务容错的话,极有可能会造成一连串的服务不可用,这就是雪崩效应。我们没法预防雪崩效应的发生,只能尽可能去做好容错。服务容错的三个核心思想是:不被外界环境影响不被上游请求压垮不被下游响应拖垮1.2.2.5 链路追踪随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪1.2.3 微服务架构的常见解决方案1.2.3.1 ServiceCombApache ServiceComb,前身是华为云的微服务引擎 CSE (Cloud Service Engine) 云服务,是全球首个Apache微服务顶级项目。它提供了一站式的微服务开源解决方案,致力于帮助企业、用户和开发者将企业应用轻松微服务化上云,并实现对微服务应用的高效运维管理。1.2.3.2 SpringCloudSpring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。SpringCloud提供的全生态的分布式组件支持,netflex系列服务注册发现:Eureka(其他选择: Consul,Zookeeper,Nacos,Etcd)负载均衡:Robbin(声明式调用:Fegin)断路器:Hystrix网关:Zuul2,Spring Cloud Gateway配置中心:Spring Cloud Config监控:Spring Boot Admin,Spring Boot Actuator链路跟踪:Spring Cloud Sleuth三、组件介绍1、Eureka(1)体系划分Eureka是SpringCloud官方推荐的服务注册发现组件。Eureka的角色和Dubbo中Zookeeper的角色类似,体系划分如下,业务上可以分为:服务注册中心、服务提供者、服务消费者。代码逻辑上分为:Eureka Server 和 Eureka Client。(2)结构原理两台Eureka服务注册中心构成的服务注册中心的主从复制集群;然后服务提供者向注册中心进行注册、续约、下线服务等;服务消费者向Eureka注册中心拉去服务列表并维护在本地;然后服务消费者根据从Eureka服务注册中心获取的服务列表选取一个服务提供者进行消费服务。(3)Eureka 集群(三节点,两两注册)从图中可以看出 Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的(Eureka保证AP,Zookeeper强调CP)。2、Robbin(1)客户端的软负载Robbin是springcloud的LB调用组件,提供客户端的软件负载均衡。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。Robbin 提供的客户端软负载,是SpringCloud微服务的典型特征之一。(2)负载均衡策略轮询(RoundRobin),以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。随机(Random),随机选择状态为UP的Server。加权响应时间(WeightedResponseTime),根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。区域感知轮询(ZoneAvoidanceRule),复合判断server所在区域的性能和server的可用性选择server。(3)核心组件Ribbon的核心组件(均为接口类型)有以下几个,ServerList,用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。ServerListFilter,仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。IRule,选择一个最终的服务地址作为LB结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。3、FeginFegin是一个声明式Http端调用,集成了Robbin的负载均衡功能,同时声明式调用更加方便(只需要简单的注解即可)。简单的可以理解为:Spring Cloud Feign 的出现使得Eureka和Ribbon的使用更加简单。(1)Fegin接口示例a、启动类 @EnableFeignClients 注解@SpringBootApplication@EnableEurekaClient@EnableFeignClients // 启用fegin声明式调用public class FeginComsumerApplication {public static void main(String[] args) {SpringApplication.run(FeginComsumerApplication.class, args);}}b、声明一个调用的Feign接口,@Service@FeignClient(name = "name-service")public interface NameService {@RequestMapping(value = "/getName", method = RequestMethod.GET)public String getName();}c、服务端提供接口实现@RequestMapping(value = "/getName", method = RequestMethod.GET) public String getName(){return "hello world";}d、fegin声明是调用@Autowiredprivate NameServiceClient feginNameServiceClient;@RequestMapping(value = "/getName", method= RequestMethod.GET)public String getName(){return feginNameServiceClient.getName();}(2)Fegin 的类加载流程通过主类上的EnableFeignClients 注解开启FeignClient;根据Feign 的规则实现接口,并加上FeignClient注解,供调用的地方注入调用;程序启动后,会扫描所有FeignClient 注解的类,并将这些信息注入到IOC 容器中;当b中接口被调用时,通过jdk代理,以及反射(Spring处理注解的方式),来生成具体的RequestTemplateRequestTemplate 生成ReqestRequest 交给httpclient处理,这里的httpclient 可以是OkHttp,也可以是HttpUrlConnection 或者HttpClient最后Client被封装到LoadBalanceClient类,这个类结合Ribbon 实现负载均衡。(3)Fegin的原理4、HystrixHystrix 是springcloud生态的断路器(隔离、限流、降级),主要是用来预防服务雪崩的现象,剔除掉分布式系统中某些挂掉或请求过慢的服务节点。Hystrix 是一个帮助解决分布式系统中超时处理和容错的类库, 拥有保护系统的能力。(1)隔离、限流、降级Hystrix断路器有两种隔离策略:信号量隔离(默认)和线程池隔离。信号量模式从始至终都只有请求线程自身,是同步调用模式,不支持超时调用,不支持直接熔断,由于没有线程的切换,开销非常小。线程池模式可以支持异步调用,支持超时调用,支持直接熔断,存在线程切换,开销大。信号量隔离:常用于获取共享资源的场景中,比如计算机连接了两个打印机,那么初始的信号量就是2,被某个进程或线程获取后减1,信号量为0后,需要获取的线程或进程进入资源等待状态。Hystrix的处理有些不同,其不等待,直接返回失败。线程池隔离:采用的就是jdk的线程池,其默认选用不使用阻塞队列的线程池,例如线程池大小为10,如果某时刻10个线程均被使用,那么新的请求将不会进入等待队列,而是直接返回失败,起到限流的作用。此外,其还引入了一个断路器机制,当断路器处于打开状态时,直接返回失败或进入降级流程。断路器打开和关闭的触发流程为:当总的请求数达到可阈值HystrixCommandProperties.circuitBreakerRequestVolumeThreshold(),或总的请求失败百分比达到了阈值HystrixCommandProperties.circuitBreakerErrorThresholdPercentage(),这时将断路器的状态由关闭设置为打开。当断路器打开时,所有的请求均被短路,在经过指定休眠时间窗口后,让下一个请求通过(断路器被认为是半开状态)。如果请求失败,断路器进入打开状态,并进入新的休眠窗口;否则进入关闭状态。(2)Hystrix 的整体处理流程流程如上图所示,Hystrix框架通过命令模式来实现方法粒度上的服务保障,主要涉及HystrixCommand和HystrixObservableCommand类,前者提供同步的execute和异步的queue方法,后者提供立即执行observe和延迟执行toObservable的回调方法。此外,实际项目中通常不会使用Hystrix集成的本地缓存。5、Spring Cloud GatewaySpring Cloud Gateway 是springcloud全新推出的第二代微服务网关,用来替代Zuul。gateway实现了服务转发、熔断、限流、权限校验等功能,有测评显示,性能比Zuul要好不少。(1)相关概念Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。(2)请求流程spring cloud gateway处理request请求的流程如下图,我们先看gateway的构成:一个netty server,一个netty client,Route(包含Predicate和Filter)。在gateway中最重要的应该是Route(Netty Server和Client已经封装好了),它由RouteLocatorBuilder构建,内部包含Predicate和Filter。流程:即在最前端,启动一个netty server(默认端口为8080)接受请求,然后通过Routes(每个Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))处理后通过Netty Client发给响应的微服务。(3)yml配置server.port: 8082spring:application:name: gatewaycloud:gateway:routes:- id: path_routeuri: http://localhost:8000order: 0predicates:- Path=/foo/**filters:- StripPrefix=1上面给出了一个根据请求路径来匹配目标uri的例子,如果请求的路径为/foo/bar,则目标uri为 http://localhost:8000/bar。如果上面例子中没有加一个StripPrefix=1过滤器,则目标uri 为http://localhost:8000/foo/bar,StripPrefix过滤器是去掉一个路径。6、Spring Boot AdminSpring Boot Admin 是springcloud提供的监控组件,用于管理和监控SpringBoot各个微服务。Admin通过注册中心(如Eureka)来监控各个节点的状态。可以结合 Spring Boot Actuator 使用,常用的监控数据有,显示健康状况显示详细信息,例如JVM和内存指标micrometer.io指标数据源指标缓存指标查看jvm系统和环境属性监控 server端需要 @EnableAdminServer 注解,client端只需要配置好yaml文件就好了,admin会通过注册中心获取各个服务节点的状态。management:endpoints:web:exposure:include: '*'endpoint:health:show-details: ALWAYS7、Spring Cloud ConfigSpring Cloud Config 是springcloud的分布式配置中心组件。分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。SpringCloudConfig分为服务端(Config Server)和客户端(Config Client),服务端负责将git(svn)中存储的配置文件发布成REST接口,客户端可以从服务端REST接口获取配置。但客户端并不能主动感知到配置的变化,从而主动去获取新的配置, 它需要每个客户端通过POST方法触发各自的/refresh,SpringCloudBus就通过一个轻量级消息代理连接分布式系统的节点。Config Server用于配置属性的存储,存储的位置可以为Git仓库、SVN仓库、本地文件等,Config Client用于服务属性的读取。spring cloud config是将配置保存在git/svn上,依赖git每次push后,触发webhook回调,最终触发spring cloud bus(消息总线),然后由消息总线通知相关的应用。1.2.3.3 SpringCloud AlibabaSpring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。SpringCloud Alibaba介绍Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式 应用服务。依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。1.3.1 主要功能服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有Worker(schedulerx-client)上执行。阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。组件Sentinel: 把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。Nacos: 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。RocketMQ: 一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。Dubbo: Apache Dubbo™ 是一款高性能 Java RPC 框架。Seata: 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。Alibaba Cloud ACM: 一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。具体技术点(约定>配置>编码)maven:3.6.0这样做的好处就是: 如果有多个子项目都引用同一样的依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样想升级或切换到另一个版本时,只需在顶层父容器里更新,而不需要一个一个子项目的修改l;另外如果某个子项目需要另外的一个版本,只需声明version版本数据库:MySQL 5.7持久层: SpingData Jpa其他: SpringCloud Alibaba 技术栈安全框架:Spring Security Spring Cloud Oauth2分布式任务调度:elastic-job持久层框架:MyBatis、通用Mapper4、Mybatis_PageHelper数据库连接池日志管理:Logback 前端框架:Vue全家桶以及相关组件三方服务: 邮件服务、阿里云短信服务、七牛云文件服务、钉钉机器人服务、高德地图API————————————————原文链接:https://blog.csdn.net/liuerchong/article/details/108374777
-
一、云原生应用 SpringCloud是对Springboot使用的分布式解决方案,适合分布式、中大型的项目架构开发,现在也逐渐成为Java服务端的主流框架。使用Spring Cloud开发的应用程序非常适合在Docker和PaaS(比如Pivotal Cloud Foundry)上部署,所以又叫做云原生应用(Cloud Native Application)。云原生可以简单地理解为面向云环境的软件架构。 springcloud 微服务架构, 1、优点 服务拆分粒度更细,有利于资源重复利用,有利于提高开发效率 可以更精准的制定优化服务方案,提高系统的可维护性 微服务架构采用去中心化思想,服务之间采用Restful等轻量级通讯,比ESB更轻量 适于互联网时代,产品迭代周期更短 2、缺点 微服务过多,治理成本高,不利于维护系统 分布式系统开发的成本高(容错,分布式事务等)对团队挑战大 二、全家桶 SpringCloud提供的全生态的分布式组件支持, 服务注册发现:Eureka(其他选择: Consul,Zookeeper,Nacos,Etcd) 负载均衡:Robbin(声明式调用:Fegin) 断路器:Hystrix 网关:Zuul2,Spring Cloud Gateway 配置中心:Spring Cloud Config 监控:Spring Boot Admin,Spring Boot Actuator 链路跟踪:Spring Cloud Sleuth 三、组件介绍 1、Eureka (1)体系划分 Eureka是SpringCloud官方推荐的服务注册发现组件。Eureka的角色和Dubbo中Zookeeper的角色类似,体系划分如下, 业务上可以分为:服务注册中心、服务提供者、服务消费者。 代码逻辑上分为:Eureka Server 和 Eureka Client。 (2)结构原理 看图说话, 两台Eureka服务注册中心构成的服务注册中心的主从复制集群; 然后服务提供者向注册中心进行注册、续约、下线服务等; 服务消费者向Eureka注册中心拉去服务列表并维护在本地; 然后服务消费者根据从Eureka服务注册中心获取的服务列表选取一个服务提供者进行消费服务。 (3)Eureka 集群(三节点,两两注册) 从图中可以看出 Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。 如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。 Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的(Eureka保证AP,Zookeeper强调CP)。 2、Robbin (1)客户端的软负载 Robbin是springcloud的LB调用组件,提供客户端的软件负载均衡。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。 Robbin 提供的客户端软负载,是SpringCloud微服务的典型特征之一。 (2)负载均衡策略 轮询(RoundRobin),以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。 随机(Random),随机选择状态为UP的Server。 加权响应时间(WeightedResponseTime),根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 区域感知轮询(ZoneAvoidanceRule),复合判断server所在区域的性能和server的可用性选择server。 (3)核心组件 Ribbon的核心组件(均为接口类型)有以下几个, ServerList,用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。 ServerListFilter,仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。 IRule,选择一个最终的服务地址作为LB结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。 Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。 3、Fegin Fegin是一个声明式Http端调用,集成了Robbin的负载均衡功能,同时声明式调用更加方便(只需要简单的注解即可)。简单的可以理解为:Spring Cloud Feign 的出现使得Eureka和Ribbon的使用更加简单。 (1)Fegin接口示例 a、启动类@EnableFeignClients 注解 @SpringBootApplication @EnableEurekaClient @EnableFeignClients // 启用fegin声明式调用 public class FeginComsumerApplication { public static void main(String[] args) { SpringApplication.run(FeginComsumerApplication.class, args); } } b、声明一个调用的Feign接口, @Service @FeignClient(name = "name-service") public interface NameService { @RequestMapping(value = "/getName", method = RequestMethod.GET) public String getName(); } c、服务端提供接口实现 @RequestMapping(value = "/getName", method = RequestMethod.GET) public String getName(){ return "hello world"; } d、fegin声明是调用 @Autowired private NameServiceClient feginNameServiceClient; @RequestMapping(value = "/getName", method= RequestMethod.GET) public String getName(){ return feginNameServiceClient.getName(); } (2)Fegin 的类加载流程 通过主类上的EnableFeignClients 注解开启FeignClient; 根据Feign 的规则实现接口,并加上FeignClient注解,供调用的地方注入调用; 程序启动后,会扫描所有FeignClient 注解的类,并将这些信息注入到IOC 容器中; 当b中接口被调用时,通过jdk代理,以及反射(Spring处理注解的方式),来生成具体的RequestTemplate RequestTemplate 生成Reqest Request 交给httpclient处理,这里的httpclient 可以是OkHttp,也可以是HttpUrlConnection 或者HttpClient 最后Client被封装到LoadBalanceClient类,这个类结合Ribbon 实现负载均衡。 (3)Fegin的原理 4、Hystrix Hystrix 是springcloud生态的断路器(隔离、限流、降级),主要是用来预防服务雪崩的现象,剔除掉分布式系统中某些挂掉或请求过慢的服务节点。Hystrix是一个帮助解决分布式系统中超时处理和容错的类库, 拥有保护系统的能力。 (1)隔离、限流、降级 Hystrix断路器有两种隔离策略:信号量隔离(默认)和线程池隔离。 信号量模式从始至终都只有请求线程自身,是同步调用模式,不支持超时调用,不支持直接熔断,由于没有线程的切换,开销非常小。 线程池模式可以支持异步调用,支持超时调用,支持直接熔断,存在线程切换,开销大。 信号量隔离:常用于获取共享资源的场景中,比如计算机连接了两个打印机,那么初始的信号量就是2,被某个进程或线程获取后减1,信号量为0后,需要获取的线程或进程进入资源等待状态。Hystrix的处理有些不同,其不等待,直接返回失败。 线程池隔离:采用的就是jdk的线程池,其默认选用不使用阻塞队列的线程池,例如线程池大小为10,如果某时刻10个线程均被使用,那么新的请求将不会进入等待队列,而是直接返回失败,起到限流的作用。 此外,其还引入了一个断路器机制,当断路器处于打开状态时,直接返回失败或进入降级流程。断路器打开和关闭的触发流程为:当总的请求数达到可阈值HystrixCommandProperties.circuitBreakerRequestVolumeThreshold(),或总的请求失败百分比达到了阈值HystrixCommandProperties.circuitBreakerErrorThresholdPercentage(),这时将断路器的状态由关闭设置为打开。当断路器打开时,所有的请求均被短路,在经过指定休眠时间窗口后,让下一个请求通过(断路器被认为是半开状态)。如果请求失败,断路器进入打开状态,并进入新的休眠窗口;否则进入关闭状态。 (2)Hystrix 的整体处理流程 流程如上图所示,Hystrix框架通过命令模式来实现方法粒度上的服务保障,主要涉及HystrixCommand和HystrixObservableCommand类,前者提供同步的execute和异步的queue方法,后者提供立即执行observe和延迟执行toObservable的回调方法。此外,实际项目中通常不会使用Hystrix集成的本地缓存。 5、Spring Cloud Gateway Spring Cloud Gateway 是springcloud全新推出的第二代微服务网关,用来替代Zuul。gateway实现了服务转发、熔断、限流、权限校验等功能,有测评显示,性能比Zuul要好不少。 (1)相关概念 Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。 Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。 Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。 (2)请求流程 spring cloud gateway处理request请求的流程如下图, 我们先看gateway的构成:一个netty server,一个netty client,Route(包含Predicate和Filter)。在gateway中最重要的应该是Route(Netty Server和Client已经封装好了),它由RouteLocatorBuilder构建,内部包含Predicate和Filter。 **流程:**即在最前端,启动一个netty server(默认端口为8080)接受请求,然后通过Routes(每个Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))处理后通过Netty Client发给响应的微服务。 (3)yml配置 server.port: 8082 spring: application: name: gateway cloud: gateway: routes: - id: path_route uri: http://localhost:8000 order: 0 predicates: - Path=/foo/** filters: - StripPrefix=1 上面给出了一个根据请求路径来匹配目标uri的例子,如果请求的路径为/foo/bar,则目标uri为http://localhost:8000/bar。如果上面例子中没有加一个StripPrefix=1过滤器,则目标uri 为http://localhost:8000/foo/bar,StripPrefix过滤器是去掉一个路径。 6、Spring Boot Admin Spring Boot Admin 是springcloud提供的监控组件,用于管理和监控SpringBoot各个微服务。Admin通过注册中心(如Eureka)来监控各个节点的状态。可以结合Spring Boot Actuator 使用,常用的监控数据有, 显示健康状况 显示详细信息,例如 JVM和内存指标 micrometer.io指标 数据源指标 缓存指标 查看jvm系统和环境属性 监控 server端需要 @EnableAdminServer 注解,client端只需要配置好yaml文件就好了,admin会通过注册中心获取各个服务节点的状态。 management: endpoints: web: exposure: include: '*' endpoint: health: show-details: ALWAYS 7、Spring Cloud Config Spring Cloud Config 是springcloud的分布式配置中心组件。 分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。 SpringCloudConfig分为服务端(Config Server)和客户端(Config Client),服务端负责将git(svn)中存储的配置文件发布成REST接口,客户端可以从服务端REST接口获取配置。但客户端并不能主动感知到配置的变化,从而主动去获取新的配置, 它需要每个客户端通过POST方法触发各自的/refresh,SpringCloudBus就通过一个轻量级消息代理连接分布式系统的节点。 Config Server用于配置属性的存储,存储的位置可以为Git仓库、SVN仓库、本地文件等,Config Client用于服务属性的读取。 spring cloud config是将配置保存在git/svn上,依赖git每次push后,触发webhook回调,最终触发spring cloud bus(消息总线),然后由消息总线通知相关的应用。 ———————————————— 原文链接:https://blog.csdn.net/m0_67401660/article/details/124465286
-
容器功能 1.1 组件添加 法一: @Configuration /** * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的 * 2、配置类本身也是组件 * 3、proxyBeanMethods:代理bean的方法 (这是SpringBoot2对SpringBoot很大的不同) * Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】 * Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】 * 组件依赖必须使用Full模式默认。其他默认是否Lite模式 * * * */ @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { /** * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象 * @return */ @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 public User user01(){ User zhangsan = new User("zhangsan", 18); //user组件依赖了Pet组件 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom") //给容器中添加组件。以方法名作为组件的id。 public Pet tomcatPet(){ return new Pet("tomcat"); } } 法二:@Bean、@Component、@Controller、@Service、@Repository 法一的方法新一些,这个方法老一些,这个方法是将注解标于要添加到bean中的那些类的上面。而法一是统一在MyConfig类中添加组件。 将注解t注解在一个类上,表示将此类标记为Spring容器中的一个Bean。 Spring为Controller-Service-Dao的分层模型分别提供了@Controller、@Service、@Repository注解,除此之外的组件使用@Component注解 其他注解1: @ComponentScan、@Import @ComponentScan 的作用就是根据定义的扫描路径(否则扫描路径是主配置类的同级或下级目录),把符合扫描规则的类装配到spring容器中 @import的好处是可以引入外部类(非自己定义的类) * 4、@Import({User.class, DBHelper.class}) * 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名 * * * */ @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { } 其他注解2: @Configuration (这个注解重要) 该注解放在配置类上表示,当容器中满足条件时,配置类中的组件才生效; 放在配置方法上的时候,表示的意思是当满足条件的时候配置方法才生效; 1.2 原生配置文件引入 @ImportResource 指以.xml结尾的配置文件,通过@ImportResource导入后SpringBoot进行解析,完成对应的组件注册 位置:在主配置类的上方。主要是为了兼容第三方,注入IOC。 @ImportResource("classpath:beans.xml") public class MyConfig {} 1.3 配置绑定 @ConfigurationProperties (常见) 场景例子:我们习惯将经常爱变化的东西写在.properties配置文件中,比如与数据库相关的信息(连接池、URL等)配置到配置文件中,为了方便我们会将配置文件中的内容解析到JavaBean中。 配置绑定:两种方式 @Component + @ConfigurationProperties(prefix=“mycar”)声明在要绑定的类的上方 @ConfigurationProperties(prefix=“mycar”)声明在要绑定的类的上方;在配置类的上方声明@EnableConfigurationProperties(Car.class),开启对应类的配置绑定功能,并把Car这个组件自动注入到容器中; /** * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能,所以先用@Component将Car绑定到容器中 */ @Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; private Integer price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; } }` //一般使用这种方式 @EnableConfigurationProperties(Car.class) // 开启 Car 的属性配置并自动注入到容器中 public class MyConfiguration { @ConfigurationProperties(prefix = "mycar") ———————————————— 原文链接:https://blog.csdn.net/qq_44901346/article/details/119703806
-
一、容器功能 1、组件添加 (1)主要注解 @Configuration 告诉SpringBoot这是一个配置类 == 配置文件 注意:spring5.2以后@Configuration多了一个属性proxyBeanMethods,默认为true @Configuration(proxyBeanMethods = true) proxyBeanMethods:代理bean的方法 Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象 Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】 组件依赖必须使用Full模式默认。其他默认是否Lite模式 ● Full模式与Lite模式 ○ 最佳实战 ■ 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断 ■ 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式 @Bean 给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 配置类里面使用@Bean标注在方法上给容器注册组件,默认是单实例的 配置类本身也是组件 (2) 基本使用 bean包: Pet类: /** * 宠物 */ public class Pet { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Pet(String name) { this.name = name; } public Pet() { } @Override public String toString() { return "Pet{" + "name='" + name + '\'' + '}'; } } User类: /* 用户 */ public class User { private String name; private Integer age; public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } } config包: MyConfig类 @Configuration(proxyBeanMethods = false)//告诉Spring这是一个配置类 public class MyConfig { @Bean//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 public User user01(){ return new User("zhangsan",18); } @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat"); } } controller包: MainApplication类 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com") public class MainApplication { public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //3、从容器中获取组件 MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。 //保持组件单实例 User user = bean.user01(); User user1 = bean.user01(); System.out.println("组件为:"+(user == user1)); } } 结果 (3)补充 @Import 给容器导入一个组件 必须写在容器中的组件上 * @Import({User.class, DBHelper.class}) * 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名 * * * */ @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { } @Configuration测试代码如下 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com") public class MainApplication { public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //3、从容器中获取组件 MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。 //保持组件单实例 User user = bean.user01(); User user1 = bean.user01(); System.out.println("组件为:"+(user == user1)); //5、获取组件 String[] beanNamesForType = run.getBeanNamesForType(User.class); System.out.println("======"); for (String s : beanNamesForType) { System.out.println(s); } DBHelper bean1 = run.getBean(DBHelper.class); System.out.println(bean1); } } @Conditional 条件装配:满足Conditional指定的条件,则进行组件注入 ConditionalOnBean:当容器中存在指定的bean组件时才干某些事情 ConditionalOnMissingBean:当容器中不存在指定的bean组件时才干某些事情 ConditionalOnClass:当容器中有某个类时才干某些事情 ConditionalOnResource:当项目的类路径存在某个资源时,才干什么事 =====================测试条件装配========================== @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 //@ConditionalOnBean(name = "tom") @ConditionalOnMissingBean(name = "tom") public class MyConfig { @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 public User user01(){ User zhangsan = new User("zhangsan", 18); //user组件依赖了Pet组件 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom22") public Pet tomcatPet(){ return new Pet("tomcat"); } } 测试: public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } boolean tom = run.containsBean("tom"); System.out.println("容器中Tom组件:"+tom); boolean user01 = run.containsBean("user01"); System.out.println("容器中user01组件:"+user01); boolean tom22 = run.containsBean("tom22"); System.out.println("容器中tom22组件:"+tom22); } 2、原生配置文件引入(xml文件引入) @ImportResource 导入资源 @ImportResource("classpath:beans.xml")//导入spring的配置文件 @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false)//告诉Spring这是一个配置类 @ConditionalOnMissingBean(name = "tom") public class MyConfig { ======================beans.xml========================= <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="haha" class="com.atguigu.boot.bean.User"> <property name="name" value="zhangsan"></property> <property name="age" value="18"></property> </bean> <bean id="hehe" class="com.atguigu.boot.bean.Pet"> <property name="name" value="tomcat"></property> </bean> </beans> 测试 ======================测试================= boolean haha = run.containsBean("haha"); boolean hehe = run.containsBean("hehe"); System.out.println("haha:"+haha);//true System.out.println("hehe:"+hehe);//true 3.配置绑定 如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用; (1)@Component + @ConfigurationProperties properties文件 /** * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能 */ @Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; private Integer price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; } } (2)@EnableConfigurationProperties + @ConfigurationProperties @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 @ConditionalOnMissingBean(name = "tom") @ImportResource("classpath:beans.xml") //@EnableConfigurationProperties(Car.class) //1、开启Car配置绑定功能 //2、把这个Car这个组件自动注册到容器中 ———————————————— 原文链接:https://blog.csdn.net/spade_Kwo/article/details/121778319
-
一.Spring 注入组件的注解 @Component、@Controller、 @Service、@Repository 说明: 这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件 二.@Configuration 在 SpringBoot, 通过 @Configuration 创建配置类来注入组件 1.代码演示 1.1JavaBean--》Monster.java ublic class Monster { private Integer id; private String name; private Integer age; private String skill; public Monster(Integer id, String name, Integer age, String skill) { this.id = id; this.name = name; this.age = age; this.skill = skill; } public Monster() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSkill() { return skill; } public void setSkill(String skill) { this.skill = skill; } @Override public String toString() { return "Monster{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", skill='" + skill + '\'' + '}'; } } 1.2配置类 /** * @author 海绵hong * @version 1.0 * <p> * 解读 * 1. @Configuration 标识这是一个配置类, 等价于配置文件 * 2. 程序员可以通过@Bean 注解注入bean对象到容器 * 3. 当一个类被 @Configuration 标识,该类-Bean 也会注入容器 */ @Configuration public class BeanConfig { /** * 解读 * 1. @Bean : 给容器添加组件, 就是Monster bean * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id * 3. Monster : 注入类型, 注入bean的类型是Monster * 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息 * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw * 6. 默认是单例注入 * 7. 通过 @Scope("prototype") 可以每次返回新的对象,就多例. */ //@Bean(name = "monster_nmw") @Bean //@Scope("prototype") public Monster monster01() { return new Monster(200, "牛魔王", 500, "疯魔拳"); } } 1.3执行代码 //启动springboot应用程序/项目 ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args); // ===演示 @Configuration start ==== Monster monster01 = ioc.getBean("monster01", Monster.class); Monster monster02 = ioc.getBean("monster01", Monster.class); System.out.println("monster01--" + monster01 + " " + monster01.hashCode()); System.out.println("monster02--" + monster02 + " " + monster02.hashCode()); //===演示 @Configuration end ==== 2.@Configuration 注意事项和细节 1. 配置类本身也是组件, 因此也可以获取 , 测试 修改 MainApp.java public static void main(String[] args) { ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args); //解读 //1. ioc.getBean("monster01", Monster.class) 是从 BeanConfig 配置类/容器获取 bean 实例 //2. 默认是单列模式, 所以 monster01 == monster02 //获取 BeanConfig 配置类的组件/bean 实例 Monster monster01 = ioc.getBean("monster01", Monster.class); System.out.println(monster01); Monster monster02 = ioc.getBean("monster01", Monster.class); System.out.println(monster01 == monster02); //解读 //配置类本身也是组件, 因此也可以获取 BeanConfig beanConfig = ioc.getBean(BeanConfig.class); System.out.println("beanConfig= " + beanConfig); } 2. SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 (全模式)和 Lite 模式(简化模式) 1. proxyBeanMethods:代理bean的方法 (1) Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】 (2) Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式】 (3) 特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效 (4) 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模 (5) Lite模 也称为轻量级模式,因为不检测依赖关系,运行速度快 @Configuration(proxyBeanMethods = false) public class BeanConfig { //===演示@Configuration(proxyBeanMethods = xxx) start //1. 先得到BeanConfig组件 BeanConfig beanConfig = ioc.getBean(BeanConfig.class); Monster monster_01 = beanConfig.monster01(); Monster monster_02 = beanConfig.monster01(); System.out.println("monster_01-" + monster_01 + " " + monster_01.hashCode()); System.out.println("monster_02-" + monster_02 + " " + monster_02.hashCode()); //特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法 //1. 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效 Monster monster01 = ioc.getBean("monster01", Monster.class); Monster monster02 = ioc.getBean("monster01", Monster.class); System.out.println("monster01-" + monster01 + " " + monster01.hashCode()); System.out.println("monster02-" + monster02 + " " + monster02.hashCode()); //===演示@Configuration(proxyBeanMethods = xxx) end 3. 配置类可以有多个 , 就和 Spring 可以有多个 ioc 配置文件是一个道理 三.@Import 在 SpringBoot, 通过 @Import 来注入组件(和@Configuration一样都是注入bean) 1.创建两个JavaBean类 Cat+Dog 2.注入类 /** * 解读 * 1. @Import 代码 可以看到,可以指定 class的数组, 可以注入指定类型的Bean * public @interface Import { * * Class<?>[] value()} * * 2. 通过@Import 方式注入了组件, 默认组件名字/id就是对应类型的全类名 */ @Import({Dog.class, Cat.class}) 3.测试注解的使用 //启动springboot应用程序/项目 ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args); //===测试@Import 使用 start Dog dogBean = ioc.getBean(Dog.class); Cat catBean = ioc.getBean(Cat.class); System.out.println("dogBean--" + dogBean); System.out.println("catBean--" + catBean); //===测试@Import 使用 end 四.@Conditional 1.@Conditional 介绍 1. 条件装配:满足 Conditional 指定的条件,则进行组件注入 2. @Conditional 是一个根注解,下面有很多扩展注解 2.应用实例 1. 要求 : 演示在 SpringBoot, 如何通过 @ConditionalOnBean 来注入组件 2. 只有在容器中有 name = monster_nmw 组件时,才注入 dog01, 代码如图 @Bean /** * 解读 * 1. @ConditionalOnBean(name = "monster_nmw") 表示 * 2. 当容器中有一个Bean , 名字是monster_nmw (类型不做约束), 就注入dog01这个Dog bean * 3. 如果没有 名字是monster_nmw Bean 就不注入dog01这个Dog bean * 4. 还有很多其它的条件约束注解,小伙伴可以自己测试 * * 5. @ConditionalOnMissingBean(name = "monster_nmw") 表示在容器中, * 没有 名字/id 为 monster_nmw 才注入dog01这个Bean * * 6. @ConditionalOnBean(name = "monster_nmw") 也可以放在配置类 * 表示对该配置类的所有要注入的组件,都进行条件约束. * */ @ConditionalOnBean(name = "monster_nmw") //@ConditionalOnMissingBean(name = "monster_nmw") public Dog dog01() { return new Dog(); } 五.@ImportResource 1.作用: 原生配置文件引入 , 也就是可以直接导入 Spring 传统的 beans.xml ,可以认 为是 SpringBoot 对 Spring 容器文件的兼容 .(原来依靠借口或者类来导入,现在可以使用该注解进行判断) 2.@ImportResource 应用实例 @Configuration //导入beans.xml - 就可以获取到beans.xml 中配置bean @ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})//配置两个bean文件 public class BeanConfig3 { } //===测试@Import 使用 start Dog dogBean = ioc.getBean(Dog.class); Cat catBean = ioc.getBean(Cat.class); System.out.println("dogBean--" + dogBean); System.out.println("catBean--" + catBean); //===测试@Import 使用 end 六.配置绑定 一句话:使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容, 并且把它封装到 JavaBean 中 1.代码演示 #设置Furn的属性k-v #前面的 furn01 是用于指定/区别不同的绑定对象, 这样可以再绑定Furn bean属性值时 #通过furn01 前缀进行区分 #furn01.id 中的id 就是你要绑定的 Furn bean的属性名 furn01.id=100 furn01.name=TV furn01.price=1000.9 @Component @ConfigurationProperties(prefix = "furn01") public class Furn { private Integer id; private String name; private Double price; } 会读取核心配置文件的信息,然后放入容器 2.配置绑定还有第 2 种方式 注意 : 注销 @Component 需 要 在 BeanConfig.java( 说 明 : 也 可 以 是 其 它 配 置 类 ) 配 置 @EnableConfigurationProperties ( Furn . class ), 否则会提示错误 //@EnableConfigurationProperties(Furn.class)解读 //1、开启 Furn 配置绑定功能 //2、把 Furn 组件自动注册到容器中 @EnableConfigurationProperties(Furn.class) public class BeanConfig { } 海绵的思路(可能错误): 将@Component注解标识掉之后,就不会去读取到容器中,但是在控制器中@EnableConfigurationProperties(Furn.class)被添加,那么底层应该就是这样一个思路:将这个启用配置属性明确配置那个类的信息,然后在那个对应的JavaBean类中有@ConfigurationProperties(prefix = "furn01")这个配置就可以读取到,并且直接将这个信息发送到了控制器中,所有在之后添加了那个注解之后便没有报错 3.注意事项和细节 1. 如果 application.properties 有中文 , 需要转成 unicode 编码写入 , 否则出现乱码 #设置属性 k-v furn01.id=100 furn01.name=soft_chair\u6c99\u53d1!! furn01.price=45678.9 2. 使用 @ConfigurationProperties (prefix = "furn01" ) 会提示如下信息 , 但是不会影响使用 3. 解决 @ConfigurationProperties(prefix = "furn01") 提示信息, 在 pom.xml 增加依赖, 即可 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> ———————————————— 原文链接:https://blog.csdn.net/weixin_54107527/article/details/127870247
-
一、Spring容器是什么,有什么作用? Spring容器是Spring核心部分,Spring容器的主要作用是帮java程序员处理大量繁琐的任务。使得程序员只需要用代码实现自己所关注的事情。 程序员是不用创建对象的,也不用创建对象的关联。只需要从配置的信息中告诉Spring容器。 而且他还能管理对象的全生命周期。 例如: 我们知道权限和用户服务是有关联的。我们只需要提供给Spring容器这四个类的代码,用注解或配置文件告诉Spring这四个服务之间的关联,关系。 Spring在启动时就会创建好这些对象,并且建立他们之间的关联,我们可以从Spring中拿到这些对象,很方便的使用他。 二 、写配置信息的方法 xml 缺点:无法检查错误。 Java代码 注解 使用java代码 和 注解 的优点:我们可以使用很多工具来测试发现错误。 但是 还是会有很多配置要我们去写 这时候可以用Springboot Springboot优点:大量采用默认配置,帮助开发者高效的构建Spring应用。 如何用注释告诉Spring容器? 1.注解(这四个注解功能都一样,知识帮助开发者区分用途) @component{"boss_setter"}普通对象 @controller{""}处理http的response,request对象 表示是一个控制器对象 @Service{" "}服务层的对象 @Repository数据存储层的对象 三、Spring容器 BeanFactory ApplicationContext 两者区别: ApplicationContext是BeanFactory的派生容器。 Application在BeanFactory原有功能的基础上还有面向实际的 高级功能 国际化接口 ,MessageSource,ResourceLoader(可以去加载外面资源的接口),ApplicationEvent的publish这样一些 应用事件发布接口。 最大的区别是 ApplicationContext在启动时就把所有的对象都创建对象。 ———————————————— 原文链接:https://blog.csdn.net/Victor_e/article/details/126528788
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签