Prefácio
Este artigo analisa o princípio de trabalho da Spring Boot 1.3. Botagem de primavera 1.4. Depois disso, a estrutura da embalagem foi alterada e o diretório de inicialização foi adicionado, mas o princípio básico permanece inalterado.
Para alterações no ClassLoader na BOOT Spring 1.4.*, consulte: http://www.vevb.com/article/141479.htm
Início rápido da bota de primavera
Na Spring Boot, um recurso muito atraente é que o aplicativo pode ser empacotado diretamente em um jar/guerra e, em seguida, esse jar/guerra pode ser iniciado diretamente sem configurar outro servidor da web.
Se você não usou a Spring Boot antes, poderá experimentá -la através da demonstração abaixo.
Aqui está um projeto como exemplo para demonstrar como iniciar o projeto de inicialização da primavera:
git clone [email protected]: hengyunabc/spring-boot-demo.gitmvn primavera-boot-demojava -jar alvo/demo-0.0.1-snapshot.jar
Se o IDE usado for Spring STS ou IDEA, você poderá criar um projeto de inicialização de mola através do assistente.
Você também pode se referir ao tutorial oficial:
http://docs.spring.io/spring-boot/docs/current-snapshot/reference/htmlsingle/#getting-started-first-application
Duas perguntas sobre a bota da primavera
Quando você começa a entrar em contato com a Spring Boot, você geralmente tem essas perguntas
Vamos analisar como a bota da primavera é feita.
Como a bota da primavera é iniciada quando embalada como uma única jarra
Depois que o maven for embalado, dois arquivos JAR serão gerados:
Demo-0.0.1-snapshot.jardemo-0.0.1-snapshot.jar.original
onde Demo-0.0.1-Snapshot.jar.original é o pacote gerado padrão do maven-jar-plugin.
Demo-0.0.1-snapshot.jar é um pacote JAR gerado pelo plug-in do Maven Spring Boot Maven, que contém dependências de aplicativos e classes relacionadas à inicialização da mola. A seguir, é chamado de jarra de gordura.
Primeiro, vamos verificar a estrutura do diretório dos pacotes preparados pela Spring Boot (omiti -la se não for importante):
├── meta-inf│ ├── manifest.mf├── Application.properties├sto └ └sto Exemplo│ └── SpringBootDemoApplication.class├─ Lib│ ├sto. └── carregador ├── ExecutiveSearchivelAuncher.class ├── jarlauncher.class ├─— javaagentDeTector.class ├── lançouDurlClassloader.class ├── lançador.class ├── mainmethrunner.class ├nada.
Vamos dar uma olhada nesses conteúdos, por sua vez.
Manifest.mf
Manifest-Version: 1.0Start-Class: com.example.springbootdemoApplicationImplementation-vendor-id: com.examplespring-boot-version: 1.3.0.releasecreated-by: Maven Apache 3.3.3Build-JDK: 1.8.0_60Implementation-TENGENGEMENTION-TENLEMENTORES-TENSTRAÇÃO-JDK: 1.8.0_64 org.springframework.boot.loader.jarlauncher
Você pode ver que a classe principal é org.springframework.boot.loader.jarlauncher, que é a principal função iniciada por jar.
Há também uma classe inicial que é com.example.springbootDemoApplication, que é a principal função que aplicamos.
@SpringbooTApplicationPublic Classe SpringbootDemoApplication {public static void main (string [] args) {springapplication.run (springbootdemoApplication.class, args); }} diretório com/exemplo
Aqui está o arquivo .class do aplicativo.
diretório lib
Aqui está o arquivo de pacote JAR do qual o aplicativo depende.
Por exemplo, primavera, primavera-mVC e outros potes.
diretório org/springframework/boot/carregador
Aqui está o arquivo .class do carregador de inicialização da mola.
Conceito de arquivo
Na bota da primavera, o conceito de arquivo é abstraído.
Um arquivo pode ser um frasco (jarfilearchive) ou um diretório de arquivos (explodedarchive). Pode ser entendido como a camada de recursos de acesso unificado abstraídos pela Spring Boot.
O Demo-0.0.1-SNAPSHOT.JAR acima é um arquivo e, em seguida, cada pacote de jar no diretório /lib no Demo-0.0.1-snapshot.jar também é um arquivo.
Arquivo de classe abstrato public {public abstrate url geturl (); public string getMainClass (); Coleção Pública Resumo <Entry> getentries (); Lista de resumos públicos <Rechive> GetnestedArchives (Filtro de entrada de entrada);Você pode ver que o arquivo tem seu próprio URL, como:
jar: arquivo: /tmp/target/demo-0.0.1-snapshot.jar!/
Há também uma função Getnestedchives, que realmente retorna a lista de frascos de jarros sob Demo-0.0.1-Snapshot.jar/lib. Seus URLs são:
JAR: FILE: /tmp/target/demo-0.0.1-snapshot.jar! /lib/aopalliance-1.0.jarjar: file: /tmp/target/demo-0.0.1-snapsshot.jar! /lib/springeans-4.20.Jar
Jarlauncher
De manifest.mf, podemos ver que a função principal é o Jarlauncher. Vamos analisar seu fluxo de trabalho abaixo.
A estrutura de herança da classe Jarlauncher é:
Classe Jarlauncher estende ExecutiveSearchivelAuncherclass ExecutiveSearchivelauncher Extends Launcher
Crie um arquivo com Demo-0.0.1-Snapshot.jar:
Jarlauncher primeiro encontra o caminho da jarra onde está localizado, ou seja, Demo-0.0.1-Snapshot.jar e depois cria um arquivo.
O código a seguir mostra o truque de como encontrar o local de carregamento de uma classe:
Protected Final Archive Cremearchive () lança Exceção {ProtectionDomain ProtectionDomain = getClass (). getProtectionDomain (); Código Código Código = ProtectionDomain.getCodesource (); Localização URI = (Codesource == NULL? NULL: CodESource.getLocation (). Touri ()); String Path = (Location == NULL? NULL: Location.getSchemespecificPart ()); if (path == null) {lança new IllegalStateException ("Não é possível determinar o arquivo da fonte de código"); } Arquivo root = novo arquivo (caminho); if (! root.exists ()) {lança new ilegalStateException ("Não é possível determinar o arquivo da fonte de código de" + root); } return (root.isdirectory ()? novo explodedarchive (raiz): new jarfilearchive (root));} Obtenha o frasco abaixo da lib/ e crie um carregador lançado
Depois que o Jarlauncher cria o arquivo, ele usa a função Getnestedchives para obter todos os arquivos JAR abaixo da Demo-0.0.1-Snapshot.jar/lib e os cria como lista.
Observe que, como mencionado acima, o Archive tem seu próprio URL.
Depois de obter esses URLs de arquivo, você receberá uma matriz de URL [] e usará isso para construir um carregador de classe personalizado: lançouDurlClassLoader.
Depois de criar o carregador de classe, leia a classe inicial do manifest.mf, ou seja, com.example.springbootDemoApplication e, em seguida, crie um novo thread para iniciar a função principal do aplicativo.
/*** Inicie o aplicativo, dado o arquivo de arquivo e um carregador de classe totalmente configurado. */Protected void Launch (string [] args, string mainClass, classLoader classLoader) lança exceção {runnable runner = createMainMethodRunner (mainClass, args, classe de classe); Thread corrernerthread = novo thread (corredor); runnerthread.setContextClassloader (classe de classe); runnerthread.setName (Thread.currentThread (). getName ()); runnerthread.start ();}/*** Crie o {@code mainMethodRunner} usado para iniciar o aplicativo. */Protected Runnable CreateMainMethodRunner (String mainClass, string [] args, classLoader classloader lança Exceção {class <?> runnerclass = classload.loadclass (runner_class); Construtor <?> Construtor = runnerclass.getConstructor (string.class, string []. Classe); Return (Runnable) construtor.NewInstance (mainClass, args);} LançouDurlClassLoader
A diferença entre o lançamento do Lançado e o UrlClassLoader comum é que ele fornece a capacidade de carregar .Class do arquivo.
Combinando a função Getentries fornecida pelo Archive, você pode obter o recurso no arquivo. É claro que ainda existem muitos detalhes por dentro, então descrevo -o abaixo.
Resumo do processo de inicialização do aplicativo de inicialização da primavera
Depois de ver isso, você pode resumir o processo de inicialização do Spring Boot Application:
Detalhes no carregador de inicialização da primavera
Endereço de código: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-loader
Extensões de URLs Jarfile
A bota de primavera pode ser iniciada com um frasco de gordura. O mais importante é que ele implementa o método de carregamento do jar no jar.
A definição do URL do Jarfile original do JDK pode ser encontrada aqui:
http://docs.oracle.com/javase/7/docs/api/java/net/jarurlconnection.html
O URL do Jarfile original se parece com o seguinte:
jar: arquivo: /tmp/target/demo-0.0.1-snapshot.jar!/
URL do recurso no pacote JAR:
Copie o código da seguinte forma: JAR: FILE: /tmp/target/demo-0.0.1-snapshot.jar! /Com/example/springbootdemoapplication.class
Você pode ver que, para os recursos em jar, a definição é separada por '!/'. O URL do Jarfile original suporta apenas um '!/'.
A bota de primavera estende este protocolo para suportar múltiplos '!/', Que pode representar o jar em jar, jar em recursos de diretório.
Por exemplo, o URL a seguir representa o spring-beans -4.2.3.release.jar no diretório Lib de Demo-0.0.1-Snapshot.jar:
Copie o código da seguinte forma: JAR: FILE: /tmp/target/demo-0.0.1-snapshot.jar! /Lib/spring-beans-4.2.3.release.jar! /Meta-inf/manifest.mf
UrlStreamHandler personalizado, estender o Jarfile e JarurlConnection
Ao construir um URL, você pode passar por um manipulador e o JDK vem com uma classe manipuladora padrão. O aplicativo pode registrar o próprio manipulador para lidar com URLs personalizados.
Public URL (protocolo de String, host de string, porta int, arquivo de string, manipulador urlstreamhandler) lança malformedurlexception
Consulte:
https://docs.oracle.com/javase/8/docs/api/java/net/url.html#url-java.lang.string-java.lang.string-int-java.lang.string-
A bota de primavera lida com a lógica de vários frascos em frascos, registrando uma classe de manipulador personalizada.
Este manipulador usará o Softreference para armazenar em cache todos os Jarfiles abertos.
Ao processar URLs como o seguinte, o separador '!/' É processado com ciclados. A partir da camada superior, primeiro construa o Jarfile Demo-0.0.1-Snapshot.jar e, em seguida, construa o jarfile spring-beans-4.2.3.Release.jar e depois construir a jarurlConnection que aponta para se manifestar.mf.
Copie o código da seguinte forma: JAR: FILE: /tmp/target/demo-0.0.1-snapshot.jar! /Lib/spring-beans-4.2.3.release.jar! /Meta-inf/manifest.mf
//org.springframework.boot.loader.jar.Handlerpublic Classe Handler estende o UrlStreamHandler {private Static Final String Separator = "!/"; SoftReference estática privada <map <arquivo, jarfile >> rootfilecache; @Override Protected UrlConnection OpenEnconnection (URL URL) lança ioexception {if (this.jarfile! = Null) {retorna nova jarurlConnection (url, this.jarfile); } tente {return New JarurlConnection (url, getRootjarFileFromurl (URL)); } catch (exceção ex) {return OpenFallbackConnection (url, ex); }} public jarfile getrootjarfilefromurl (url url) lança ioexception {string spec = url.getfile (); int separatorIndex = spec.indexOf (separador); if (separatorIndex == -1) {lança a nova malformException ("JAR URL não contém!/ separador"); } Nome da string = spec.substring (0, separatorIndex); return getrootjarfile (nome); } Como o Classloader lê para o recurso
Que habilidades necessárias para um carregador de classe?
A API correspondente é:
Public URL FindreSource (nome da string)
Como mencionado acima, quando as construções de inicialização do Spring são lançadas no conjunto, ele passa uma matriz de URL []. A matriz é o URL do frasco sob o diretório Lib.
Como JDK ou Classloader sabem como ler o conteúdo para um URL?
De fato, o processo se parece com o seguinte:
A chamada final é a função getInputStream () da jarurlConnection.
//org.springframework.boot.loader.jar.jarurlConnection @Override public inputStream getInputStream () lança IoException {Connect (); if (this.jarentryname.isEmpty ()) {lança a nova ioException ("nenhum nome de entrada especificado"); } return this.jarentrydata.getInputStream (); }De um URL para finalmente ler o conteúdo no URL, todo o processo é bastante complicado. Vamos resumir:
Existem muitos detalhes aqui, apenas alguns pontos importantes estão listados.
Então, como o URLClassLoader getResource?
Ao construir o URLClassLoader, ele possui parâmetros de matriz de URL [] e usará essa matriz para construir um URLClassPath:
Urlclasspath ucp = novo urlclasspath (URLs);
No URLClassPath, um carregador será construído para todos os URLs e, ao receber o resumo, tentará obtê -los desses carregadores um por um.
Se a aquisição for bem -sucedida, ela será empacotada como um recurso como abaixo.
Recurso getResource (nome da string final, checagem booleana) {URL final URL; tente {url = novo url (base, parseutil.encodepath (nome, false)); } catch (malformedUrlexception e) {lança nova ilegalArgumentException ("nome"); } UrlConnection final UC; tente {if (check) {urlclasspath.check (url); } uc = url.openconnection (); InputStream in = uc.getInputStream (); se (uc instanceof jarurlConnection) { / * precisar lembrar o arquivo JAR para que possa ser fechado * com pressa. */ JarurlConnection juc = (jarurlConnection) uc; jarfile = jarloader.checkjar (juc.getjarfile ()); }} catch (Exceção e) {return null; } return new Resource () {public String getName () {Return Name; } public url geturl () {return url; } public URL getCodesourceUrl () {Return Base; } public inputStream getInputStream () lança ioexception {return uc.getInputStream (); } public int getContentLength () lança IoException {return uc.getContentLength (); }};}Como você pode ver no código, o url.Openconnection () é realmente chamado. Dessa forma, a cadeia completa pode ser conectada.
Observe que o código da classe URLClassPath não vem com o seu próprio no JDK. Aqui você pode ver http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/misc/urlclasspath.java#506
Iniciar o aplicativo de inicialização da mola no diretório IDE/aberto
O acima é mencionado apenas o processo de iniciar o aplicativo de inicialização da mola em um frasco de gordura. A seguir, é apresentada uma análise de como a bota da primavera é iniciada no IDE.
No IDE, a principal função que é executada diretamente é aplicar sua própria função principal:
@SpringbooTApplicationPublic Classe SpringbootDemoApplication {public static void main (string [] args) {springapplication.run (springbootdemoApplication.class, args); }}De fato, o aplicativo inicial de inicialização da primavera no IDE é o caso mais fácil, porque os frascos de dependência são colocados no caminho de classe, então a bota da primavera é iniciada.
Outra situação é iniciar a inicialização da primavera em um diretório aberto. O chamado diretório aberto é descomprimir o frasco de gordura e iniciar diretamente o aplicativo.
java org.springframework.boot.loader.jarlauncher
No momento, a Spring Boot determinará se está atualmente em um diretório. Nesse caso, construa um marquinho explodido (o anterior é o JarFilEarchive) e o processo de inicialização subsequente é semelhante ao jarra de gordura.
Armazenamento de Tomcat
Determine se está no ambiente da web
Quando a bota da primavera for iniciada, primeiro determine se está no ambiente da web, simplesmente pesquisando a classe do servlet:
String final estática privada [] web_environment_classes = {"javax.servlet.servlet", "org.springframework.web.context.configurablewebApplicationContext"}; private boolean deduceweburironment () {para (string " (! Classutils.ispresent (className, null)) {return false; }} retornar true;}Nesse caso, será criado AnnotationConfigEmbeddedwebApplicationContext, caso contrário, o contexto da primavera é anotaçãoConfigApplicationContext:
//org.springframework.boot.springApplication ConfigurableApplicationContext Protected ConfigurablicationContext CreateApplicationContext () {class <?> contextClass = this.ApplicationContextClass; if (contextClass == null) {try {contextClass = class.ForName (this.webenvironment? default_web_context_class: default_context_class); } catch (classNotFoundException ex) {THROW NOVA ILGLELGALSTATEEXCECCEIRA ("Não é possível criar um ApplicationContext padrão," + ", especifique um ApplicationContextClass", ex); }} return (configurableApplicationContext) beanutils.instantiate (contextClass); } Obtenha a classe de implementação de incorporado
O Spring Boot inicia o servidor da Web correspondente, obtendo incorporado o ServLeTLeRAnerFactory.
As duas classes de implementação comumente usadas são TOMCATEMBEDDEDSERVLEVLEGLONTAINERFACTORY e JETTYEMBEDSERVERVLETCONTAINERFACTORY.
Código para iniciar o tomcat:
// tomcatembeddedservletContainerFactory@SubsteridePublic INCEDDEDSERVLETLEGRONER GETEMBEDDEDSERVLEVLETContainer (servletContextinitializer ... Initializers) {tomcat tomcat = new Tomcat (); Arquivo baseado em arquivo = (this.BaseDirectory! = Null? This.basedir: createTempdir ("tomcat")); tomcat.setBasedir (baseado.getabsolutepath ()); Conector conector = novo conector (this.protocol); tomcat.getService (). addConnector (conector); CUSTERIZECONCENCIONCIONCIONAL (CONECTOR); tomcat.setConnector (conector); tomcat.gethost (). setautodelaPlay (false); tomcat.getEngine (). setbackgroundProcessorDelay (-1); para (conector adicionalConnector: this.additionaltomcatconnectors) {tomcat.getservice (). addConnector (adicionalConnector); } prepareContext (tomcat.gethost (), inicializadores); Retornar getTomcatembeddedServletContainer (tomcat);} Um diretório de arquivos temporário será criado para Tomcat, como:
/tmp/tomcat.2233614112516545210.8080, como a base do tomcat. Arquivos Tomcat temporários, como diretório de trabalho, serão colocados dentro.
Alguns servlets Tomcat também serão inicializados, como o servlet mais importante padrão/jsp:
private void addDefaultServlet (contexto de contexto) {wrapper defaultServlet = context.createwrapper (); defaultServlet.setName ("padrão"); defaultServlet.SetServletClass ("org.apache.catalina.servlets.defaultServlet"); defaultServlet.addinitParameter ("Debug", "0"); defaultServlet.addinitParameter ("Listagens", "false"); defaultServlet.SetLoadOnStartup (1); // Caso contrário, o local padrão de um despachoServlet de mola não pode ser definido padrão padrão.setOverridable (true); context.addchild (padrãoServlet); context.addServletMapping ("/", "padrão");} private void addjSpServlet (contexto de contexto) {wrapper jspServlet = context.CreateWrapper (); JSPServlet.SetName ("JSP"); JSPServlet.SetServletClass (getJSPServLatClassName ()); JSPServlet.addinitParameter ("Fork", "False"); JSPServlet.SetLoadOnStartup (3); context.addchild (JSPServlet); context.AddServletMapping ("*. JSP", "JSP"); Context.AddServletMapping ("*. JSPX", "JSP");} Como acessar o recurso com o aplicativo Spring Boot Web
Como faço para acessar o recurso da web quando o aplicativo de inicialização da primavera é embalado como um frasco de gordura?
Na verdade, é implementado através da URL fornecida pelo Arquivo e, em seguida, pela capacidade de acessar o recurso de caminho de classe fornecido pelo Classloader.
index.html
Por exemplo, você precisa configurar um index.html, que pode ser colocado diretamente no diretório src/main/recursos/estático no código.
Para a página de boas -vindas Index.html, quando a bota da primavera for inicializada, um ViewController será criado para lidar:
// ResourcePropertiesPublic Class ResourceProperties implementa ResourceLoaderaWare {String final privada final [] servlet_resource_locations = {"/"}; String final estática privada [] ClassPath_Resource_locations = {"ClassPath:/meta-Inf/Resources/", "ClassPath:/Resources/", "ClassPath:/static/", "Classpath:/public/"}; // webmvCautoconfigurationAdapter @Override public void AddViewControllers (Registry ViewControllerRegistry) {página de recursos = this.ResourceProperties.getWelcomePage (); if (página! = null) {logger.info ("Adicionando página de boas -vindas:" + página); Registry.addViewController ("/"). SetViewName ("Forward: Index.html"); }} modelo
Por exemplo, o arquivo de modelo de página pode ser colocado no diretório SRC/Main/Recursos/Modelos. Mas isso é realmente tratado pela própria classe de implementação do modelo. Por exemplo, na classe ThymeleafProperties:
public static final string default_prefix = "ClassPath:/modelos/";
JSP
A página JSP é semelhante ao modelo. Na verdade, é tratado pelo JSTLView construído no MVC da primavera.
Você pode configurar spring.view.prefix para definir o diretório da página JSP:
spring.view.prefix:/web-inf/jsp/
Manuseio de páginas de erro unificado na inicialização da primavera
Para páginas de erro, a Spring Boot também é tratada uniformemente, criando um BasicErRorController.
@Controlador@requestmapping ("$ {server.error.path: $ {error.path:/error}}") public class BasicErrorController estende abstracterrorControllerA visualização correspondente é um lembrete simples de HTML:
@Configuration@condicionalonProperty (prefix = "server.error.whitelabel", name = "Habiled", matchifmissing = true) @condicional (errorTemplatemissingCondition.cllass) Classe estática protegida WhiteLabELERRorviewConfiguration (SPELVVIEW FINAL SPELVIEW "<html> <body> <h1> Whitelabel Error Page </h1>" + "<p> Este aplicativo não possui mapeamento explícito para/erro, então você está vendo isso como um fallback. status = $ {status}). @Bean (name = "Error") @conditionalonMissingBean (name = "error") public View DeFAULTERRORVIEW () {return this.defaulterRorview; }A bota da primavera é uma boa prática, que evita a exceção padrão lançada quando os aplicativos tradicionais da Web cometem erros, facilitando o vazamento de segredos.
Processo de embalagem Maven de aplicação de inicialização de primavera
Primeiro, gerar um frasco contendo dependências através da plugina maven-de-sombra e empacote as classes relacionadas ao carregador de inicialização do Spring e manifesto.mf no frasco através do plug-in Spring-Boot-Maven-Plugin.
Implementação de toras de cores na bota da primavera
Ao iniciar o aplicativo de inicialização do spring no shell, você descobrirá que sua saída de madeireiro é colorida, o que é muito interessante.
Esta configuração pode ser desligada:
spring.output.ansi.enabled = false
O princípio é obter essa configuração através do AnsiOutputApplicationListener e, em seguida, definir o logback na saída, adicionar um COLORCONVERTER e renderizar alguns campos através do org.springframework.boot.ansi.ansiOutput.
Algumas dicas de código
Ao implementar o ClassLoader, suporta o carregamento paralelo do JDK7
Você pode se referir ao LockProvider no Lançado
A classe pública lançada oLlClassLoader estende o URLClassLoader {private Static LockProvider Lock_Provider = setUplockProvider (); Private estático LockProvider setUplockProvider () {try {ClassLoader.ReGisterasparallelCapable (); retornar novo java7lockprovider (); } catch (nosuchmethoderror ex) {return new LockProvider (); }} @Override Classe protegida <?> Loadclass (nome da string, resolução booleana) lança classNotFoundException {Synchronized (lançouDurlClassLoader.lock_provider.getLock (this, nome)) {class <? if (carregedclass == null) {handler.setuseFastConnectionExceptions (true); tente {loadedClass = doloadclass (nome); } finalmente {Handler.SetuseFastConnectionExceptions (false); }} if (resolve) {ResolveClass (carregamento de Classário); } return carregedclass; }} Verifique se o pacote JAR é carregado através do agente
InputArgumentsJavaAGentDetCector, o princípio é detectar se o URL do frasco tem o prefixo de "-Javaagent:".
String final estática privada java_agent_prefix = "-javaagent:";
Obtenha o PID do processo
ApplicationPid, você pode obter o PID.
private string getpid () {try {string jvmname = gerenciamentofactory.getRuntimEmxBean (). getName (); return jvmname.split ("@") [0]; } catch (throwable ex) {return null; }} Classe de logger de embalagem
A Boot Spring possui um conjunto de loggers que suportam Java, Log4J, Log4J2, Logback. Você pode se referir a isso quando precisar empacotar seus madeireiros no futuro.
No pacote org.springframework.boot.logging.
Obtenha a função principal do início original
Através do método obtido na pilha, julgue a função principal e encontre a função principal original iniciada.
classe privada <?> deducemainApplicationClass () {try {sTackTraceElement [] StackTrace = new RunTimeException (). getStackTrace (); para (StackTraceElement StackTraceElement: StackTrace) {if ("main" .equals (StackTraceElement.getMethodName ())) {return class.ForName (StacktraceElement.getClassName ()); }}} Catch (ClassNotFoundException Ex) {// Swallow e continue} retornar null;} Algumas desvantagens da bota de Spirng:
Quando o aplicativo de inicialização da primavera é executado em um frasco de gordura, alguns problemas serão encontrados. Aqui estão minhas opiniões pessoais:
Resumir
A bota de primavera estende o protocolo JAR, abstraia o conceito de arquivo e o jarfile de suporte, o jarurlconnection e o lançamento do Lançado, realizando assim a experiência de desenvolvimento de tudo em um sem percepção da aplicação da camada superior. Embora a guerra executável não seja um conceito proposto pela primavera, a bota da primavera permite que ela seja levada adiante.
A Boot Spring é um projeto incrível, que pode ser considerado a segunda primavera da primavera. Configuração de mola-nuvem, sessão de primavera, métricas, conchas remotas etc. são todos projetos e recursos que os desenvolvedores amam. É quase certo que o designer tem uma experiência rica no desenvolvimento da linha de frente e está bem ciente dos pontos problemáticos dos desenvolvedores.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.