1.springbootå¯å¨ç±»åçï¼
2.滴滴 Web 移动端组件库 cube-ui 开源
springbootå¯å¨ç±»åçï¼
SpringbootBatchçå¯å¨åç-Configuration
Springbootæ´åäºwebåbatchï¼ä½æ¯ä»ä»¬è¯å®ä¸æ¯åä¸æ¡è·¯ï¼å¨springbootä¸ï¼ä¼æ¨æå½åçè¿è¡ç¯å¢ãthis.webApplicationType=WebApplicationType.deduceFromClasspath();
ä»ä¸æå¯ä»¥çåºï¼Springå°è¯ä»classpathéæ¾å°ç¹å¾ç±»ï¼æ¥å¤æå½åappæ¯ä»ä¹ç±»åãå½ç¶è¿ç§å¤ææ¯æå±éæ§çï¼æå¯è½æ¯transitive带è¿æ¥ä¸ä¸ªå¸¦æservletç类被å½æäºWebApplicationType.SERVLETï¼å®é ä¸æ¯ä¸ªWebApplicationType.NONE;ãå¦æä¸æ³ä»¥webè¿è¡å°±æ¯æ³è¿è¡batchå¯ä»¥å¨application.properties强è¡æå®WebApplicationType
å ·ä½åçä½ç¨ç请çä¸é¢çstacktrace
å½ä¸ä¸ªbatchapplicationéè¦å¯å¨ï¼éè¦é ç½®JobRepositoryï¼Datasourceççï¼ææçå¼å§é½æ¥èªä¸ä¸ªannotation@EnableBatchProcessing
å½å å ¥@EnableBatchProcessingæ¶ï¼BatchConfigurationSelectorå¼å§å¯å¨ï¼æä¹å¯å¨ç大家å¯ä»¥åèä¸é¢çstacktraceã
import类主è¦æ¯ç±ConfigurationClassPostProcessoræ¥å®ç°çãå½BatchConfigurationSelector被è°ç¨çæ¶åï¼æ们å¯ä»¥çå°ä»æ两æ¡æ¯è·¯ã
é£ä¹è¿ä¸¤æ¡è·¯æå¥ä¸åå¢ã主è¦æ¯jobå®ä¹çæ¹å¼ä¸åã
modular=trueçæ åµä¸ï¼ä¸é¢æ¯ä¸ä¸ªä¾å
å¯ä»¥æå¤ä¸ªåApplicationContextFactoryï¼è¿æ ·å¥½å¤æ¯å¨é¤äºjob大家ä¸å¯ä»¥éå¤ï¼å 为æ¯å¨ä¸åçcontextéï¼å ¶ä»çstepï¼readerï¼writerï¼processorï¼mapperï¼ä»¥åææçbeanççé½å¯ä»¥éåã
é£ä¸ºä»ä¹Jobä¸å¯ä»¥éå¤ï¼æ¯å 为è½ç¶å¯ä»¥éå¤ï¼ä½æ¯å¦æjobä¹éå¤ï¼å¯¹ç¨æ·æ¥è®²å¤ªä¸å好äºãç¨æ·å¯è½ä¸ç¥éèªå·±é çæ¯åªä¸ªcontextçjobãå ·ä½ä¸ºä»ä¹å¯ä»¥éåè¦ççGenericApplicationContextFactoryçå®ç°ã
å½GenericApplicationContextFactory::createApplicationContext,启动ä¼è§¦åApplicationContextHelperçæé å½æ°ä»èè°ç¨loadConfiguration(config)æå®ä¹çbeanå å ¥å°contextéãé£ä¹æ个é®é¢ï¼parentå¨åªé设置ï¼createApplicationContextæ¯ä»ä¹æ¶åè°ç¨çã
æ们继ç»çModularConfiguration
ä»Modularçè§åº¦æ¥çé¦å ä»å¯ä»¥å¤é¨æ³¨å ¥ä¸ä¸ªConfigurerï¼å¦æ没æå°±éæ©DefaultBatchConfigurerï¼å¦ææå¤ä¸ªéæ©åä¼æåºã
å½ç¶Datasourceä¹å¯ä»¥éæ©å¤é¨æ³¨å ¥,æè ç±DefaultBatchConfigurer::initializeæ¹æ³SimpleJobLauncherï¼JobRepositoryåJobExploreré½æ¯ç±FactoryBeançæ¹å¼å®ç°çã
å¨è¿ä¸ªDefaultBatchConfigurerä¸å¯ä»¥çå°JobLauncherçç±»åæ¯
initializeéMapJobRepositoryFactoryBeanè¿ä¸ªå¯ä»¥éç¹è¯»ä¸ä¸ãé¦å ç¨FactoryBeanç模å¼å®ç°äºä¸ä¸ªProxyBeanï¼å¦ææ³äºè§£FactoryBeançç¨æ³ï¼è¿æ¯ä¸ªå ¸åçä¾åãä½æ¯è¿ä¸ªFactoryBeanæ¯ä»¥apiè¡ä¸ºç´æ¥è°ç¨çï¼å¹¶æ²¡æ注åå°Springçcontextä¸ã
é 置好jobéè¦çjobRepositoryï¼jobLauncherçé£ä¹éç¹æ¥äºï¼ä¸é¢çAutomaticJobRegistrarå°±æ¯æ¥å¤çApplicationContextFactory
è¿ä¸ªé»è¾æ¯æææçApplicationContextFactoryçbeaninstanceæ¾å ¥å°AutomaticJobRegistraréå»ãè¿å°±åå°äºç¬¬ä¸ä¸ªé®é¢ï¼parentcontextæ¯ä»ä¹æ¶åæ¾è¿å»çãå°±æ¯å¨
context.getBeansOfType(ApplicationContextFactory.class)请çä¸é¢çè°ç¨æ ï¼å¨ApplicationContextAwareProcessoréä¼èªå¨æparentcontextæ³¨å ¥ã
ä½æ¯æ¾è¿å»å¥æ¶åç¨å¢ï¼æ们çä¸ä¸AutomaticJobRegistrar
åæ¥AutomaticJobRegistraræ¯ä¸ªSmartlifecycleï¼ä»Smartlifecycleçç»èå¯ä»¥ä»SpringbootSmartlifecycleæ¥å¾ç¥ãå®å°±æ¯å¨ææbeané½åå§åç»æåå¼å§è¿è¡çä¸ä¸ªé¶æ®µãå¨è¿ä¸ªstartæ¹æ³ä¸ï¼å¼å§éåææçApplicationContextFactoryï¼æ¥è¿è¡å è½½ãä»ä¸æè¿ä¸ªjobLoaderæ¯DefaultJobLoaderã
é£ä¹å¯ä»¥ççDefaultJobLoader::doLoadæ¹æ³
è¿éæå ä¸ªå ³é®è°ç¨ç¬¬ä¸ä¸ªæ¯createApplicationContextï¼æcontextéå®ä¹çå ¨é¨å è½½å°Springcontextéå»ï¼è¿å°±æ»¡è¶³äºGenericApplicationContextFactoryå·¥ä½ç两个æ¡ä»¶ã第äºä¸ªæ¯doRegister(context,job)éjobRegistry.register(jobFactory);
æ们çä¸ä¸JobRepositoryçå®ç°MapJobRegistry::registeræ¹æ³ï¼å¨è¿éå°±æjobnameåjobFactoryçé®å¼å¯¹åå¨èµ·æ¥äºã
è¿æ ·å°±å¯ä»¥éè¿JobRepositoryè¿ä¸ªbeanæ¿å°ææ注åçjobäºã
å±ä»¬ååæ¥ç@EnableBatchProcessingè¿ä¸ªannotationï¼å½æ²¡æ设å®modularçæ¶åæ¯æ¯è¾ç®åçï¼åªæ¯å®ç°äºä¸ä¸ªproxybasedçJobçbeanã
åæ ·ä¹åªæBatchConfigureræ¥é ç½®ãè¿ä¸ªé»è¾åModularæ¯ä¸æ ·çãä»è¿ä¸¤ä¸ªé ç½®ç¥éï¼Modular注åäºå¨åcontextçé ç½®ï¼å¹¶ä¸å è½½ãä½æ¯å½ä»¥æ£å¸¸beançæ¹å¼åå¨çï¼æ¯æä¹è¯»è¿æ¥çå¢ãè¿æ¶åå°±è¦çJobRegistryBeanPostProcessor
è¿ä¸ªpostProcessAfterInitializationæ¹æ³éï¼å¯¹æ¯ä¸ªjobç±»åçbeanï¼jobRegistryå å ¥äºReferenceJobFactoryãè¿æ ·ææç以beançæ¹å¼å®ä¹çé½å¯ä»¥éè¿jobRegistryè·å¾ã
SpringBootStateråçä¸.SpringBootç好å¤
1.ä¾èµç®¡çï¼å¯ææå¼çç»ä»¶ç®¡çï¼å½éè¦æ个ç»ä»¶æ¶ï¼åªéè¦å¼å ¥ç¸å ³staterå³å¯ï¼ä¸éè¦åæå¨å¼å ¥å个jarå ï¼é¿å äºå éæ¼ãå å²çªçä¸å¿ è¦çé®é¢ãå¼å人åå¯ä»¥ä¸æ³¨äºä¸å¡å¼åï¼
2.èªå¨é ç½®ï¼éµä»"约å®ä¼äºé ç½®"çååï¼å¼å人åå¯ä»¥å¨å°éé ç½®æè ä¸é ç½®çæ åµä¸ï¼ä½¿ç¨æç»ä»¶ã
大大éä½é¡¹ç®æ建åç»ä»¶å¼å ¥çææ¬ï¼å¼å人åå¯ä»¥ä¸æ³¨äºä¸å¡å¼åï¼é¿å ç¹æçé ç½®å大éçjarå 管çã
äº.å®ç°åç
è¦å¼å ¥æç»ä»¶ï¼æ éè¦å两件äºãä¸æ¯å¼å ¥jarå å³pomæ件å¼å ¥staterï¼äºå°±æ¯ç¼åé ç½®æ件ï¼ä½¿ç¨Javaé ç½®çæ åµä¸å°±æ¯ç¼åä¸ç³»å@Configuration注解æ 注çç±»ãé£ä¹SpringBootæ¯æä¹æ¥å¼å ¥è¿äºé 置类çå¢ï¼å°±éè¦æä»¬æ·±å ¥SpringBootå¯å¨ç±»ä¸æ¢ç©¶ç«ã
SpringBootå¯å¨ç±»ä¸é¢ä¼æ@SpringBootApplication注解ï¼è¿æ¯SpringBootä¸æéè¦çä¸ä¸ªæ³¨è§£ï¼æ¯å®ç°èªå¨é ç½®çå ³é®ã@SpringBootApplicationæ¯ä¸ä¸ªç§å注解ï¼ä¸»è¦ç±@SpringBootConfigurationã@EnableAutoConfigurationã@ComponentScanä¸é¨åç»æã
@SpringBootConfiguration表æ该类æ¯ä¸ä¸ªé 置类ã@EnableAutoConfigurationç±@AutoConfigurationPackageå@Import(AutoConfigurationImportSelector.class)ç»æã@AutoConfigurationPackageç±@Import(AutoconfigurationPackages.Registrar.class)ç»æï¼åBean容å¨ä¸æ³¨åä¸ä¸ªAutoConfigurationPackagesç±»ï¼è¯¥ç±»ææbasePackageï¼ç®åæåç°çä½ç¨æ¯å¨MyBatisæ«æ注åMapperæ¶ä½ä¸ºå æ«æè·¯å¾ã@AutoConfigurationPackageçæ§è¡æµç¨å¦ä¸å¾ï¼
@Import(AutoConfigurationImportSelector.class)æ¯å¯å¨èªå¨é ç½®çæ ¸å¿ãè¿éè¿æä¸ä¸ªå°ææ²ï¼ä¸ç´å¨çAutoConfigurationImportSelectorçselectImportsæ¹æ³ï¼å´åç°æ²¡æ被è°ç¨ï¼ä»¥ä¸ºæ¯demo项ç®é®é¢ï¼å»çå®é¡¹ç®ä¸debugæç¹ï¼åç°ä¹æ²¡æè¿å ¥ï¼ç¬é´æµé¼ããã继ç»è·è¸ªåç°æ§è¡æµç¨å¦ä¸ï¼SpringBootå¯å¨åçåæ
èªå¨é ç½®æ ¸å¿ç±»SpringFactoriesLoader
ä¸é¢å¨è¯´@EnableAutoConfigurationçæ¶åæ说META-INFä¸çspring.factoriesæ件ï¼é£ä¹è¿ä¸ªæ件æ¯æä¹è¢«springå è½½å°çå¢ï¼å ¶å®å°±æ¯SpringFactoriesLoaderç±»ã
SpringFactoriesLoaderæ¯ä¸ä¸ªä¾Springå é¨ä½¿ç¨çéç¨å·¥åè£ è½½å¨ï¼SpringFactoriesLoaderéæ两个æ¹æ³ï¼
å¨è¿ä¸ªSpringBootåºç¨å¯å¨è¿ç¨ä¸ï¼SpringFactoriesLoaderåäºä»¥ä¸å 件äºï¼
å è½½ææMETA-INF/spring.factoriesä¸çInitializer
å è½½ææMETA-INF/spring.factoriesä¸çListener
å è½½EnvironmentPostProcessorï¼å 许å¨Springåºç¨æ建ä¹åå®å¶ç¯å¢é ç½®ï¼
æ¥ä¸æ¥å è½½PropertiesåYAMLçPropertySourceLoaderï¼é对SpringBootç两ç§é ç½®æ件çå è½½å¨ï¼
åç§å¼å¸¸æ åµçFailureAnalyzerï¼å¼å¸¸è§£éå¨ï¼
å è½½SpringBootå é¨å®ç°çåç§AutoConfiguration
模æ¿å¼æTemplateAvailabilityProviderï¼å¦FreemarkerãThymeleafãJspãVelocityçï¼
æ»å¾æ¥è¯´ï¼SpringFactoriesLoaderå@EnableAutoConfigurationé åèµ·æ¥ï¼æ´ä½åè½å°±æ¯æ¥æ¾spring.factoriesæ件ï¼å è½½èªå¨é 置类ã
æ´ä½å¯å¨æµç¨
å¨æ们æ§è¡å ¥å£ç±»çmainæ¹æ³ä¹åï¼è¿è¡SpringApplication.runï¼åé¢newäºä¸ä¸ªSpringApplication对象ï¼ç¶åæ§è¡å®çrunæ¹æ³ã
åå§åSpringApplicationç±»
å建ä¸ä¸ªSpringApplication对象æ¶ï¼ä¼è°ç¨å®èªå·±çinitializeæ¹æ³
æ§è¡æ ¸å¿runæ¹æ³
åå§åinitializeæ¹æ³æ§è¡å®ä¹åï¼ä¼è°ç¨runæ¹æ³ï¼å¼å§å¯å¨SpringBootã
é¦å éåæ§è¡ææéè¿SpringFactoriesLoaderï¼å¨å½åclasspathä¸çMETA-INF/spring.factoriesä¸æ¥æ¾ææå¯ç¨çSpringApplicationRunListeners并å®ä¾åãè°ç¨å®ä»¬çstarting()æ¹æ³ï¼éç¥è¿äºçå¬å¨SpringBootåºç¨å¯å¨ã
å建并é ç½®å½åSpringBootåºç¨å°è¦ä½¿ç¨çEnvironmentï¼å æ¬å½åææçPropertySource以åProfileã
éåè°ç¨ææçSpringApplicationRunListenersçenvironmentPrepared()çæ¹æ³ï¼éç¥è¿äºçå¬å¨SpringBootåºç¨çEnvironmentå·²ç»å®æåå§åã
æå°SpringBootåºç¨çbannerï¼SpringApplicationçshowBannerå±æ§ä¸ºtrueæ¶ï¼å¦æclasspathä¸åå¨banner.txtæ件ï¼åæå°å ¶å 容ï¼å¦åæå°é»è®¤bannerã
æ ¹æ®å¯å¨æ¶è®¾ç½®çapplicationContextClassåå¨initializeæ¹æ³è®¾ç½®çwebEnvironmentï¼å建对åºçapplicationContextã
å建å¼å¸¸è§£æå¨ï¼ç¨å¨å¯å¨ä¸åçå¼å¸¸çæ¶åè¿è¡å¼å¸¸å¤ç(å æ¬è®°å½æ¥å¿ãéæ¾èµæºç)ã
设置SpringBootçEnvironmentï¼æ³¨åSpringBeanå称çåºååå¨BeanNameGeneratorï¼å¹¶è®¾ç½®èµæºå è½½å¨ResourceLoaderï¼éè¿SpringFactoriesLoaderå è½½ApplicationContextInitializeråå§åå¨ï¼è°ç¨initializeæ¹æ³ï¼å¯¹å建çApplicationContextè¿ä¸æ¥åå§åã
è°ç¨ææçSpringApplicationRunListenersçcontextPreparedæ¹æ³ï¼éç¥è¿äºListenerå½åApplicationContextå·²ç»å建å®æ¯ã
ææ ¸å¿çä¸æ¥ï¼å°ä¹åéè¿@EnableAutoConfigurationè·åçææé 置以åå ¶ä»å½¢å¼çIoC容å¨é ç½®å è½½å°å·²ç»åå¤å®æ¯çApplicationContextã
è°ç¨ææçSpringApplicationRunListenerçcontextLoadedæ¹æ³ï¼å è½½åå¤å®æ¯çApplicationContextã
è°ç¨refreshContextï¼æ³¨åä¸ä¸ªå ³éSpring容å¨çé©åShutdownHookï¼å½ç¨åºå¨åæ¢çæ¶åéæ¾èµæºï¼å æ¬ï¼éæ¯Beanï¼å ³éSpringBeançå建工åçï¼
注ï¼é©åå¯ä»¥å¨ä»¥ä¸å ç§åºæ¯ä¸è¢«è°ç¨ï¼
1ï¼ç¨åºæ£å¸¸éåº
2ï¼ä½¿ç¨System.exit()
3ï¼ç»ç«¯ä½¿ç¨Ctrl+C触åçä¸æ
4ï¼ç³»ç»å ³é
5ï¼ä½¿ç¨Killpidå½ä»¤ææ»è¿ç¨
è·åå½åææApplicationRunneråCommandLineRunneræ¥å£çå®ç°ç±»ï¼æ§è¡å ¶runæ¹æ³
éåææçSpringApplicationRunListenerçfinished()æ¹æ³ï¼å®æSpringBootçå¯å¨ã
SpringBootåºç¨å¯å¨åç(äº)æ©å±URLClassLoaderå®ç°åµå¥jarå è½½å¨ä¸ç¯æç« ãSpringBootåºç¨å¯å¨åç(ä¸)å°å¯å¨èæ¬åµå ¥jarãä¸ä»ç»äºSpringBootå¦ä½å°å¯å¨èæ¬ä¸RunnableJaræ´å为ExecutableJarçåçï¼ä½¿å¾çæçjar/waræ件å¯ä»¥ç´æ¥å¯å¨
æ¬ç¯å°ä»ç»SpringBootå¦ä½æ©å±URLClassLoaderå®ç°åµå¥jarçç±»(èµæº)å è½½ï¼ä»¥å¯å¨æ们çåºç¨ã
é¦å ï¼ä»ä¸ä¸ªç®åç示ä¾å¼å§
build.gradle
WebApp.java
æ§è¡gradlebuildæ建jarå ï¼éé¢å å«åºç¨ç¨åºã第ä¸æ¹ä¾èµä»¥åSpringBootå¯å¨ç¨åºï¼å ¶ç®å½ç»æå¦ä¸
æ¥çMANIFEST.MFçå 容(MANIFEST.MFæ件çä½ç¨è¯·èªè¡GOOGLE)
å¯ä»¥çå°ï¼jarçå¯å¨ç±»ä¸ºorg.springframework.boot.loader.JarLauncherï¼è并ä¸æ¯æ们çcom.manerfan.SpringBoot.theory.WebAppï¼åºç¨ç¨åºå ¥å£ç±»è¢«æ 记为äºStart-Class
jarå¯å¨å¹¶ä¸æ¯éè¿åºç¨ç¨åºå ¥å£ç±»ï¼èæ¯éè¿JarLauncher代çå¯å¨ãå ¶å®SpringBootæ¥æ3ä¸ä¸åçLauncherï¼JarLauncherãWarLauncherãPropertiesLauncher
SpringBoot使ç¨Launcher代çå¯å¨ï¼å ¶æéè¦çä¸ç¹ä¾¿æ¯å¯ä»¥èªå®ä¹ClassLoaderï¼ä»¥å®ç°å¯¹jaræ件å ï¼jarinjarï¼æå ¶ä»è·¯å¾ä¸jarãclassæèµæºæ件çå è½½
å ³äºClassLoaderçæ´å¤ä»ç»å¯åèãæ·±å ¥ç解JVMä¹ClassLoaderã
SpringBootæ½è±¡äºArchiveçæ¦å¿µï¼ä¸ä¸ªArchiveå¯ä»¥æ¯jarï¼JarFileArchiveï¼ï¼å¯ä»¥æ¯ä¸ä¸ªæ件ç®å½ï¼ExplodedArchiveï¼ï¼å¯ä»¥æ½è±¡ä¸ºç»ä¸è®¿é®èµæºçé»è¾å±ã
ä¸ä¾ä¸ï¼spring-boot-theory-1.0.0.jaræ¢ä¸ºä¸ä¸ªJarFileArchiveï¼spring-boot-theory-1.0.0.jar!/BOOT-INF/libä¸çæ¯ä¸ä¸ªjarå ä¹æ¯ä¸ä¸ªJarFileArchive
å°spring-boot-theory-1.0.0.jar解åå°ç®å½spring-boot-theory-1.0.0ï¼åç®å½spring-boot-theory-1.0.0为ä¸ä¸ªExplodedArchive
æç §å®ä¹ï¼JarLauncherå¯ä»¥å è½½å é¨/BOOT-INF/libä¸çjarå/BOOT-INF/classesä¸çåºç¨class
å ¶å®JarLauncherå®ç°å¾ç®å
å ¶ä¸»å ¥å£æ°å»ºäºJarLauncher并è°ç¨ç¶ç±»Launcherä¸çlaunchæ¹æ³å¯å¨ç¨åº
åå建JarLauncheræ¶ï¼ç¶ç±»ExecutableArchiveLauncheræ¾å°èªå·±æå¨çjarï¼å¹¶å建archive
å¨Launcherçlaunchæ¹æ³ä¸ï¼éè¿ä»¥ä¸archiveçgetNestedArchivesæ¹æ³æ¾å°/BOOT-INF/libä¸ææjarå/BOOT-INF/classesç®å½æ对åºçarchiveï¼éè¿è¿äºarchivesçurlçæLaunchedURLClassLoaderï¼å¹¶å°å ¶è®¾ç½®ä¸ºçº¿ç¨ä¸ä¸æç±»å è½½å¨ï¼å¯å¨åºç¨
è³æ¤ï¼ææ§è¡æ们åºç¨ç¨åºä¸»å ¥å£ç±»çmainæ¹æ³ï¼ææåºç¨ç¨åºç±»æ件åå¯éè¿/BOOT-INF/classeså è½½ï¼ææä¾èµç第ä¸æ¹jaråå¯éè¿/BOOT-INF/libå è½½
å¨åæLaunchedURLClassLoaderåï¼é¦å äºè§£ä¸ä¸URLStreamHandler
javaä¸å®ä¹äºURLçæ¦å¿µï¼å¹¶å®ç°å¤ç§URLåè®®ï¼è§URLï¼*/didi/cube-ui。
cube-ui 从滴滴业务中提炼而来,源码b应用源由滴滴 WebApp 前端架构组开发和维护。启动cube-ui 的源码b应用源目标是让移动端的开发更加容易,让开发人员更加专注于业务逻辑的启动jdk的源码在开发,提升研发效率。源码b应用源源码分享网开源
cube-ui 的启动特性包括:精简提炼自滴滴内部组件库,每个组件都有充分单元测试;追求迅速响应、源码b应用源动画流畅、启动接近原生的源码b应用源交互体验;遵循统一的设计交互标准,接口标准化,启动支持按需引入和后编译,源码b应用源轻量灵活;扩展性强,启动牛b支付源码可以方便地基于现有组件实现二次开发。源码b应用源
cube-ui 相对于同类型的启动移动端组件库的优势在于,其组件主要包括基础组件、弹出层组件和滚动组件,简单跑腿系统源码总共开源了 个组件,且在组件的体验和交互,包括易用性上我们都追求极致。cube-ui 支持 2 种使用方式,口红机源码月入声明式和 API 式。
cube-ui 的某些组件有着很好的扩展性,可以根据实际场景需求做功能的扩展,例如基于弹层类组件的基类开发更丰富的弹层类组件,或者基于移动端选择器组件扩展出城市选择器组件。
cube-ui 底层依赖了 Vue 和 better-scroll,并依赖了一系列工具做了构建部署、单元测试等工作。未来我们会持续对 cube-ui 迭代和优化,包括但不限于开发更多通用的组件,支持换肤功能,以及考虑对静态类型检查的支持。