日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

玩轉(zhuǎn)SpringBoot—Starter組件

來源: 責(zé)編: 時(shí)間:2023-10-10 18:30:54 258觀看
導(dǎo)讀學(xué)習(xí)目標(biāo)明確starter組件到底是什么?是做什么的?自己實(shí)現(xiàn)一個(gè)starter組件Spring Boot提供的Starter組件和第三方Starter組件Spring -Boot-Web-Starter如何自動(dòng)讓應(yīng)用部署到Tomcat容器的第1章 starter組件簡(jiǎn)介starter組

glj28資訊網(wǎng)——每日最新資訊28at.com

學(xué)習(xí)目標(biāo)

  • 明確starter組件到底是什么?是做什么的?
  • 自己實(shí)現(xiàn)一個(gè)starter組件
  • Spring Boot提供的Starter組件和第三方Starter組件
  • Spring -Boot-Web-Starter如何自動(dòng)讓應(yīng)用部署到Tomcat容器的

第1章 starter組件簡(jiǎn)介

starter組件是SpringBoot的一個(gè)核心特性,Starter組件的出現(xiàn)極大簡(jiǎn)化了項(xiàng)目開發(fā),例如在項(xiàng)目中使用的pom.xm文件下配置:glj28資訊網(wǎng)——每日最新資訊28at.com

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency>

SpringBoot就會(huì)自動(dòng)關(guān)聯(lián)web開發(fā)相關(guān)的依賴,如tomcat以及spring-webmvc等,進(jìn)而對(duì)web開發(fā)進(jìn)行支持,同時(shí)相關(guān)技術(shù)也將實(shí)現(xiàn)自動(dòng)配置,避免了繁瑣的配置文件。glj28資訊網(wǎng)——每日最新資訊28at.com

Starter組件使開發(fā)者不需要關(guān)注各種依賴庫(kù)的處理,不需要具體的配置信息,由SpringBoot自動(dòng)完成class類發(fā)現(xiàn)并加載需要的Bean。glj28資訊網(wǎng)——每日最新資訊28at.com

利用starter實(shí)現(xiàn)自動(dòng)化配置需要兩個(gè)條件:Maven依賴、配置文件,Maven依賴實(shí)質(zhì)上就是導(dǎo)入jar包,SpringBoot啟動(dòng)的時(shí)候會(huì)找到Starter組件jar包中的
resources/META-INF/spring.factories文件,根據(jù)spring.factories文件中的配置,找到需要自動(dòng)配置的類。
glj28資訊網(wǎng)——每日最新資訊28at.com

starter組件理解總結(jié):glj28資訊網(wǎng)——每日最新資訊28at.com

  • 每個(gè)不同的starter組件實(shí)際上完成自身的功能邏輯,然后對(duì)外提供一個(gè)bean對(duì)象讓別人調(diào)用
  • 對(duì)外提供的bean通過自動(dòng)裝配原理注入到提供方的IoC容器中

第2章 手寫starter組件

要實(shí)現(xiàn)一個(gè)自己的starter組件其實(shí)也很簡(jiǎn)單,要完成一個(gè)starter組件的編寫,首先要明確,我們要做的事有哪些:glj28資訊網(wǎng)——每日最新資訊28at.com

  • 通過配置類提供對(duì)外服務(wù)的bean對(duì)象
  • 按照自動(dòng)裝配原理完成spring.factories的編寫
  • starter自動(dòng)屬性配置

接下來我們就來手寫一個(gè)starter組件,流程如下:glj28資訊網(wǎng)——每日最新資訊28at.com

創(chuàng)建一個(gè)springboot項(xiàng)目redisson-spring-boot-starter

引入依賴:glj28資訊網(wǎng)——每日最新資訊28at.com

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>com.gupao.redisson</groupId>  <artifactId>redisson-spring-boot-starter</artifactId>  <version>1.0-SNAPSHOT</version>  <name>redisson-spring-boot-starter</name>  <!-- FIXME change it to the project's website -->  <url>http://www.example.com</url>  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <maven.compiler.source>1.8</maven.compiler.source>    <maven.compiler.target>1.8</maven.compiler.target>  </properties>  <dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.11</version>      <scope>test</scope>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter</artifactId>      <version>2.3.2.RELEASE</version>      <optional>true</optional>    </dependency>    <dependency>      <groupId>org.redisson</groupId>      <artifactId>redisson</artifactId>      <version>3.16.1</version>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-configuration-processor</artifactId>      <version>2.3.2.RELEASE</version>    </dependency>  </dependencies>  <build>    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->      <plugins>        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->        <plugin>          <artifactId>maven-clean-plugin</artifactId>          <version>3.1.0</version>        </plugin>        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->        <plugin>          <artifactId>maven-resources-plugin</artifactId>          <version>3.0.2</version>        </plugin>        <plugin>          <artifactId>maven-compiler-plugin</artifactId>          <version>3.8.0</version>        </plugin>        <plugin>          <artifactId>maven-surefire-plugin</artifactId>          <version>2.22.1</version>        </plugin>        <plugin>          <artifactId>maven-jar-plugin</artifactId>          <version>3.0.2</version>        </plugin>        <plugin>          <artifactId>maven-install-plugin</artifactId>          <version>2.5.2</version>        </plugin>        <plugin>          <artifactId>maven-deploy-plugin</artifactId>          <version>2.8.2</version>        </plugin>        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->        <plugin>          <artifactId>maven-site-plugin</artifactId>          <version>3.7.1</version>        </plugin>        <plugin>          <artifactId>maven-project-info-reports-plugin</artifactId>          <version>3.0.0</version>        </plugin>      </plugins>    </pluginManagement>  </build></project>

創(chuàng)建要注入的bean類和接口

package com.gupao.redisson;/** * @author Eclipse_2019 * @create 2022/6/11 9:58 */public interface Humen {    String dancing();}package com.gupao.redisson;import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.springframework.util.StringUtils;import java.util.Properties;/** * @author Eclipse_2019 * @create 2022/1/14 22:55 */public class Girl implements Humen{    public static Girl create(String name){        return new Girl(name);    }    private String name;    public Girl(String name) {        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String dancing() {        return name+"喜歡跳舞";    }}

創(chuàng)建屬性類

package com.gupao.redisson;import org.springframework.boot.context.properties.ConfigurationProperties;/** * @author Eclipse_2019 * @create 2021/8/11 11:28 */@ConfigurationProperties(prefix = "gp.girl")public class GirlProperties {    private String name = "wentai";    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

創(chuàng)建配置類

package com.gupao.redisson;import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.redisson.config.SingleServerConfig;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author Eclipse_2019 * @create 2021/8/11 11:05 */@ConditionalOnClass(Girl.class)//條件裝配@EnableConfigurationProperties(GirlProperties.class)@Configurationpublic class GirlAutoConfiguration {    @Bean    Humen humen(GirlProperties girlProperties){        return Girl.create(girlProperties.getName());    }}

實(shí)現(xiàn)自動(dòng)裝配流程,在META-INF目錄下創(chuàng)建spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=/  com.gupao.redisson.RedissonAutoConfiguration,/  com.gupao.redisson.GirlAutoConfiguration

在META-INF創(chuàng)建屬性默認(rèn)規(guī)范文件additional-spring-configuration-metadata.json

{  "properties": [    {      "name": "gp.redisson.host",      "type": "java.lang.String",      "description": "Redis的服務(wù)器地址",      "defaultValue": "localhost"    },    {      "name": "gp.redisson.port",      "type": "java.lang.Integer",      "description": "Redis的服務(wù)器端口",      "defaultValue": 6379    },    {      "name": "gp.redisson.pwd",      "type": "java.lang.String",      "description": "Redis的服務(wù)器密碼",      "defaultValue": "jingtian"    },    {      "name": "gp.redisson.datasource",      "type": "java.lang.Integer",      "description": "Redis的服務(wù)器庫(kù)",      "defaultValue": 0    },    {      "name": "gp.girl.name",      "type": "java.lang.String",      "description": "默認(rèn)女孩名",      "defaultValue": "wentai"    }  ]}

打包發(fā)布

測(cè)試

通過上面我們實(shí)現(xiàn)自己的starter組件案例來看,starter組件的實(shí)現(xiàn)其實(shí)邏輯并不復(fù)雜,核心思想就是在META-INF目錄下創(chuàng)建spring.factories文件,然后配置自定義的配置類。只要按照這個(gè)邏輯配置,都可以做到自動(dòng)注入到IoC容器中去,OK,那我們現(xiàn)在來看看我們的spring-boot-starter-data-redis這個(gè)starter組件,你會(huì)發(fā)現(xiàn),這個(gè)組件里面居然沒有spring.factories文件,為什么呢?沒有這個(gè)文件,它是怎么自動(dòng)裝配的呢?glj28資訊網(wǎng)——每日最新資訊28at.com

第3章 自身與第三方維護(hù)

其實(shí)針對(duì)springboot的starter組件分為兩類。glj28資訊網(wǎng)——每日最新資訊28at.com

springboot自身維護(hù)的starter組件

@ConditionalOnBean(僅僅在當(dāng)前上下文中存在某個(gè)對(duì)象時(shí),才會(huì)實(shí)例化一個(gè)Bean)
@ConditionalOnClass(某個(gè)class位于類路徑上,才會(huì)實(shí)例化一個(gè)Bean)
@ConditionalOnExpression(當(dāng)表達(dá)式為true的時(shí)候,才會(huì)實(shí)例化一個(gè)Bean)
@ConditionalOnMissingBean(僅僅在當(dāng)前上下文中不存在某個(gè)對(duì)象時(shí),才會(huì)實(shí)例化一個(gè)Bean)
@ConditionalOnMissingClass(某個(gè)class類路徑上不存在的時(shí)候,才會(huì)實(shí)例化一個(gè)Bean)
@
ConditionalOnNotWebApplication(不是web應(yīng)用)
glj28資訊網(wǎng)——每日最新資訊28at.com

所有的starter組件自身不帶spring.factories文件,集中在spring都是-boot-autoconfigure包下的EnableAutoConfigurationglj28資訊網(wǎng)——每日最新資訊28at.com

springboot裝配這些配置類是需要條件的,不可能所有的configuration都注入,假設(shè)我沒用到redis的話就不會(huì)引包,這樣就根據(jù)@ConditionalOnClass(RedisOperations.class)在class path下找不到RedisOperation類,這樣就不會(huì)加載該配置類glj28資訊網(wǎng)——每日最新資訊28at.com

自身維護(hù)的starter組件的命名:spring-boot-starter-XXXglj28資訊網(wǎng)——每日最新資訊28at.com

第三方維護(hù)的starter組件

  • 自己維護(hù)spring.factories文件
  • 命名方式:XXX-spring-boot-starter

這里有個(gè)小知識(shí):@ConditionalOnClass(XXX.class)在我們本地用的時(shí)候,如果XXX.class不存在的話壓根編譯不能通過,但是為什么springboot自身維護(hù)的能編譯通過呢?glj28資訊網(wǎng)——每日最新資訊28at.com

  • 其實(shí)原因也簡(jiǎn)單,因?yàn)樵趕tarter組件編譯的時(shí)候是引入了@ConditionnalOnClass里面的那個(gè)類了的,然后在pom文件引入的這個(gè)XXX類所在的jar包時(shí)加了true,等starter組件編譯打包之后不會(huì)將XXX類所在的jar包傳遞依賴給別的項(xiàng)目。
  • 這里就可以將spring-boot-autoconfigure包理解成一個(gè)starter組件,它在編譯的過程中引入了很多jar包,比如說引入Redis的相關(guān)jar包,然后加入了true,當(dāng)autoconfigure編譯打成jar包之后是沒問題的,但是別的項(xiàng)目依賴autoconfigure之后,必須要引入redis的jar包才能通過@ConditionalOnClass注解。

現(xiàn)在我們會(huì)手寫自己的starter組件了,也明白了不同組件的區(qū)別,那么接下來讓我們一起來看看springboot中的一個(gè)比較重要的組件——spring-boot-starter-web組件,為什么要看它呢?因?yàn)樗鼛臀覀兺瓿闪巳萜鞯膬?nèi)置以及啟動(dòng)。glj28資訊網(wǎng)——每日最新資訊28at.com

第4章 內(nèi)置容器

starter-web

Springboot整合Spring MVC只需要在pom.xml文件中引入。glj28資訊網(wǎng)——每日最新資訊28at.com

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency>

配置文件。glj28資訊網(wǎng)——每日最新資訊28at.com

server:  port: 8080 # web服務(wù)端口號(hào)  servlet:    multipart:      enabled: true # 啟用文件上傳      location: # 上傳文件臨時(shí)保存位置      max-file-size: 50MB # 單個(gè)文件上傳最大大小限制      max-request-size: 100MB # 單次請(qǐng)求主體最大大小限制  mvc:    format:      date: yyyy-MM-dd # 日期格式      date-time: yyyy-MM-dd HH:mm:ss # 日期時(shí)間格式      time: HH:mm:ss # 時(shí)間格式    servlet:      path: / # servlet路徑      static-path-pattern: # 匹配靜態(tài)資源路徑    view:      prefix: # view前綴      suffix: # view后綴,如:.jsp

以上是Spring MVC常用配置,更多配置可參見https://docs.spring.io/spring-boot/docs/2.3.7.RELEASE/reference/html/appendix-application-properties.html#common-application-properties-web。glj28資訊網(wǎng)——每日最新資訊28at.com

我們只配置最簡(jiǎn)單的。glj28資訊網(wǎng)——每日最新資訊28at.com

spring.mvc.view.suffix=.jspspring.mvc.view.prefix=/WEB-INF/jsp/

3.為項(xiàng)目添加WEB-INF目錄和web.xml文件。glj28資訊網(wǎng)——每日最新資訊28at.com

glj28資訊網(wǎng)——每日最新資訊28at.com

service:glj28資訊網(wǎng)——每日最新資訊28at.com

package com.example.springbootvipjtdemo.mvcdemo;import org.springframework.stereotype.Service;/** * @author Eclipse_2019 * @create 2022/6/11 16:03 */@Servicepublic class JspService {    public String sayHello(String name){        return "你真棒!"+name;    }}

controller:glj28資訊網(wǎng)——每日最新資訊28at.com

package com.example.springbootvipjtdemo.mvcdemo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.servlet.ModelAndView;/** * @author Eclipse_2019 * @create 2022/6/11 16:03 */@RestControllerpublic class JspController {    @Autowired    private JspService jspService;    @RequestMapping("/jsp")    public ModelAndView hello(@RequestParam String name){        ModelAndView modelAndView = new ModelAndView();        modelAndView.addObject("version","2.X版本");        modelAndView.addObject("name",name);        modelAndView.addObject("msg",jspService.sayHello(name));        modelAndView.setViewName("a");        return modelAndView;    }}

jsp:glj28資訊網(wǎng)——每日最新資訊28at.com

<%@page contentType="text/html; charset=UTF-8" language="java" %><!DOCTYPE html><html lang="en"><body><h2>${version}</h2><h2>${name}:${msg}</h2></body></html>

上面的案例實(shí)現(xiàn)了Springboot集成springmvc,但是現(xiàn)在還沒有哪里用到了容器,那容器是怎么啟動(dòng)的呢?glj28資訊網(wǎng)——每日最新資訊28at.com

先來看看spring-boot-starter-web包里面有啥:glj28資訊網(wǎng)——每日最新資訊28at.com

  • ServletWebServerFactoryAutoConfiguration配置類中Import了ServletWebServerFactoryConfiguration.EmbeddedTomcat.class。
  • 當(dāng)容器啟動(dòng)的時(shí)候也會(huì)自動(dòng)裝配該類,在該配置類中創(chuàng)建了TomcatServletWebServerFactory()。
  • WebMvcAutoConfiguration類完成了InternalResourceViewResolver解析器的注入。

然后再來看看springboot啟動(dòng)的時(shí)候是怎么去創(chuàng)建內(nèi)置容器的glj28資訊網(wǎng)——每日最新資訊28at.com

onRefresh

spring容器啟動(dòng)代碼就不說了,這里主要看一下onRefresh() 這個(gè)方法。轉(zhuǎn)到定義發(fā)現(xiàn)這個(gè)方法里面啥都沒有,這明顯是一個(gè)鉤子方法,它會(huì)鉤到它子類重寫onRefresh()方法。所以去看子類里面的onRefresh()glj28資訊網(wǎng)——每日最新資訊28at.com

protected void onRefresh() throws BeansException {    //這是一個(gè)空方法,AbstractApplicationContext 這個(gè)類是一個(gè)抽象類,    //所以我們要找到集成AbstractApplicationContext的子類,去看子類里面的onRefresh()	// For subclasses: do nothing by default.}

glj28資訊網(wǎng)——每日最新資訊28at.com

我們這里是一個(gè)Web項(xiàng)目,所以我們就去看ServletWebServerApplicationContext 這個(gè)類 ,我還是把類的關(guān)系圖貼一下。glj28資訊網(wǎng)——每日最新資訊28at.com

glj28資訊網(wǎng)——每日最新資訊28at.com

我們就去看ServletWebServerApplicationContext 這個(gè)類下面的 onRefresh() 方法。glj28資訊網(wǎng)——每日最新資訊28at.com

protected void onRefresh() {		super.onRefresh();		try {            //看到內(nèi)置容器的影子了,進(jìn)去看看			createWebServer();		}		catch (Throwable ex) {			throw new ApplicationContextException("Unable to start web server", ex);		}}

createWebServer

private void createWebServer() {		WebServer webServer = this.webServer;		ServletContext servletContext = getServletContext();		if (webServer == null && servletContext == null) {            //1、這個(gè)獲取webServerFactory還是要進(jìn)去看看			ServletWebServerFactory factory = getWebServerFactory();			this.webServer = factory.getWebServer(getSelfInitializer());		}		else if (servletContext != null) {			try {				getSelfInitializer().onStartup(servletContext);			}			catch (ServletException ex) {				throw new ApplicationContextException("Cannot initialize servlet context",						ex);			}		}		initPropertySources();}

我們繼續(xù)看下getWebServletFactory() 這個(gè)方法,這個(gè)里面其實(shí)就是選擇出哪種類型的web容器了。glj28資訊網(wǎng)——每日最新資訊28at.com

protected ServletWebServerFactory getWebServerFactory() {		// Use bean names so that we don't consider the hierarchy		String[] beanNames = getBeanFactory()				.getBeanNamesForType(ServletWebServerFactory.class);		if (beanNames.length == 0) {			throw new ApplicationContextException(					"Unable to start ServletWebServerApplicationContext due to missing "							+ "ServletWebServerFactory bean.");		}		if (beanNames.length > 1) {			throw new ApplicationContextException(					"Unable to start ServletWebServerApplicationContext due to multiple "							+ "ServletWebServerFactory beans : "							+ StringUtils.arrayToCommaDelimitedString(beanNames));		}		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);	}

getWebServer

我們?cè)倩仡^去看factory.getWebServer(getSelfInitializer()) ,轉(zhuǎn)到定義就會(huì)看到很熟悉的名字tomcat。glj28資訊網(wǎng)——每日最新資訊28at.com

public WebServer getWebServer(ServletContextInitializer... initializers) {        //tomcat這位大哥出現(xiàn)了		Tomcat tomcat = new Tomcat();		File baseDir = (this.baseDirectory != null ? this.baseDirectory				: createTempDir("tomcat"));		tomcat.setBaseDir(baseDir.getAbsolutePath());		Connector connector = new Connector(this.protocol);		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);		return getTomcatWebServer(tomcat);}

內(nèi)置的Servlet容器就是在onRefresh() 方法里面啟動(dòng)的,至此一個(gè)Servlet容器就啟動(dòng)OK了。glj28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-12699-0.html玩轉(zhuǎn)SpringBoot—Starter組件

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 使用Python對(duì)數(shù)據(jù)進(jìn)行操作轉(zhuǎn)換

下一篇: 如何使用CSS和JavaScript實(shí)施暗模式?

標(biāo)簽:
  • 熱門焦點(diǎn)
  • 鴻蒙OS 4.0公測(cè)機(jī)型公布:甚至連nova6都支持

    華為全新的HarmonyOS 4.0操作系統(tǒng)將于今天下午正式登場(chǎng),官方在發(fā)布會(huì)之前也已經(jīng)正式給出了可升級(jí)的機(jī)型產(chǎn)品,這意味著這些機(jī)型會(huì)率先支持升級(jí)享用。這次的HarmonyOS 4.0支持
  • 6月安卓手機(jī)好評(píng)榜:魅族20 Pro蟬聯(lián)冠軍

    性能榜和性價(jià)比榜之后,我們來看最后的安卓手機(jī)好評(píng)榜,數(shù)據(jù)來源安兔兔評(píng)測(cè),收集時(shí)間2023年6月1日至6月30日,僅限國(guó)內(nèi)市場(chǎng)。第一名:魅族20 Pro好評(píng)率:95%5月份的時(shí)候魅族20 Pro就是
  • 容量越大越不壞?24萬塊硬盤故障率報(bào)告公布 這些產(chǎn)品零故障

    8月5日消息,云存儲(chǔ)服務(wù)商Backblaze發(fā)布了最新的硬盤故障率報(bào)告,年故障率有所上升。Backblaze發(fā)布的硬盤季度統(tǒng)計(jì)數(shù)據(jù),其中包括故障率等重要方面。這些結(jié)
  • 如何正確使用:Has和:Nth-Last-Child

    我們可以用CSS檢查,以了解一組元素的數(shù)量是否小于或等于一個(gè)數(shù)字。例如,一個(gè)擁有三個(gè)或更多子項(xiàng)的grid。你可能會(huì)想,為什么需要這樣做呢?在某些情況下,一個(gè)組件或一個(gè)布局可能會(huì)
  • 只需五步,使用start.spring.io快速入門Spring編程

    步驟1打開https://start.spring.io/,按照屏幕截圖中的內(nèi)容創(chuàng)建項(xiàng)目,添加 Spring Web 依賴項(xiàng),并單擊“生成”按鈕下載 .zip 文件,為下一步做準(zhǔn)備。請(qǐng)?jiān)谶M(jìn)入步驟2之前進(jìn)行解壓。圖
  • 當(dāng)家的盒馬,加速謀生

    來源 | 價(jià)值星球Planet作者 | 歸去來自己&ldquo;當(dāng)家&rdquo;的盒馬,開始加速謀生了。據(jù)盒馬官微消息,盒馬計(jì)劃今年開放生鮮供應(yīng)鏈,將其生鮮商品送往食堂。目前,盒馬在上海已經(jīng)與
  • iQOO Neo8 Pro評(píng)測(cè):旗艦雙芯加持 最強(qiáng)性能游戲旗艦

    【Techweb評(píng)測(cè)】去年10月,iQOO推出了一款Neo7手機(jī),該機(jī)搭載了聯(lián)發(fā)科天璣9000+,配備獨(dú)顯芯片Pro+,帶來了同價(jià)位段最佳的游戲體驗(yàn),一經(jīng)上市便受到了諸多用
  • iQOO Neo8 Pro真機(jī)諜照曝光:天璣9200+和V1+旗艦雙芯加持

    去年10月,iQOO推出了iQOO Neo7系列機(jī)型,不僅搭載了天璣9000+,而且是同價(jià)位唯一一款天璣9000+直屏旗艦,一經(jīng)上市便受到了用戶的廣泛關(guān)注。在時(shí)隔半年后,
  • Meta盲目擴(kuò)張致超萬人被裁,重金押注元宇宙而前景未明

    圖片來源:圖蟲創(chuàng)意日前,Meta創(chuàng)始人兼CEO 馬克&middot;扎克伯發(fā)布公開信,宣布Meta計(jì)劃裁員超11000人,占其員工總數(shù)13%。他公開承認(rèn)了自己的預(yù)判失誤:&ldquo;不僅
Top 主站蜘蛛池模板: 四川省| 义马市| 项城市| 德令哈市| 山阳县| 三穗县| 贞丰县| 濮阳县| 繁峙县| 北碚区| 房产| 乐陵市| 瓮安县| 灵武市| 锡林郭勒盟| 惠州市| 青龙| 阿鲁科尔沁旗| 东安县| 美姑县| 达州市| 太白县| 平塘县| 罗江县| 安乡县| 左云县| 雅江县| 修武县| 涞水县| 于田县| 保康县| 拜泉县| 那曲县| 东平县| 赤峰市| 沈丘县| 清新县| 治多县| 景德镇市| 仁怀市| 波密县|