java - tiempo - Fuerce habilite DevTools con arranque de resorte cuando ejecute Jar
que es correcto fuerces o forces (1)
La solución es incompleta, por lo que decide si es bueno para usted. La solución final es la última parte de esta publicación
Es difícil lanzar la solución, primero necesito explicar cómo llegué allí. En primer lugar, porque livereload no está habilitado cuando se inicia fuera del IDE:
Comprenda lo que está pasando
(1) La configuración de LocalDevToolsAutoConfiguration es condicional en @ConditionalOnInitializedRestarter/OnInitializedRestarterCondition
:
@Configuration
@ConditionalOnInitializedRestarter
@EnableConfigurationProperties(DevToolsProperties.class)
public class LocalDevToolsAutoConfiguration {
...
(2) OnInitializedRestarterCondition recupera una instancia de reiniciador y comprueba si es nula; de lo contrario, restarter.getInitialUrls()
devuelve null. En mi caso, restarter.getInitialUrls()
devolvía nulo.
class OnInitializedRestarterCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Restarter restarter = getRestarter();
if (restarter == null) {
return ConditionOutcome.noMatch("Restarter unavailable");
}
if (restarter.getInitialUrls() == null) {
return ConditionOutcome.noMatch("Restarter initialized without URLs");
}
return ConditionOutcome.match("Restarter available and initialized");
}
(3) initialUrls
se inicializa en Restarter.class
través de DefaultRestartInitializer.getInitialUrls(..)
class Restarter{
this.initialUrls = initializer.getInitialUrls(thread);
}
class DefaultRestartInitializer{
@Override
public URL[] getInitialUrls(Thread thread) {
if (!isMain(thread)) {
return null;
}
for (StackTraceElement element : thread.getStackTrace()) {
if (isSkippedStackElement(element)) {
return null;
}
}
return getUrls(thread);
}
protected boolean isMain(Thread thread) {
return thread.getName().equals("main") && thread.getContextClassLoader()
.getClass().getName().contains("AppClassLoader");
}
}
thread.getContextClassLoader () .getClass (). getName (). contains ("AppClassLoader")
solo es cierto cuando se ejecuta desde Eclipse (posiblemente cualquier IDE? + springboot-maven-plugin?). Recordar:
isMain () devuelve falso;
el initialUrls no se inicializa;
el LocalConvToolsAutoConfiguration condicional no está configurado;
sin carga en vivo
UNA SOLUCIÓN:
Asegúrese de que el nombre del cargador de clases sea "AppClassLoader" creando su propio cargador de clases AppClassLoader. En la primera línea de la base de su bota de resorte, reemplace el cargador de clase con el suyo:
URLClassLoader originalClassLoader = (URLClassLoader)Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(new CustomAppClassLoader(originalClassLoader));
Nuestra implementación personalizada del cargador de clases simplemente delega en la original:
public class CustomAppClassLoader extends URLClassLoader{
private URLClassLoader contextClassLoader;
public CustomAppClassLoader(URLClassLoader contextClassLoader) {
super(contextClassLoader.getURLs(), contextClassLoader.getParent());
this.contextClassLoader = contextClassLoader;
}
public int hashCode() {
return contextClassLoader.hashCode();
}
public boolean equals(Object obj) {
return contextClassLoader.equals(obj);
}
public InputStream getResourceAsStream(String name) {
return contextClassLoader.getResourceAsStream(name);
}
public String toString() {
return contextClassLoader.toString();
}
public void close() throws IOException {
contextClassLoader.close();
}
public URL[] getURLs() {
return contextClassLoader.getURLs();
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return contextClassLoader.loadClass(name);
}
public URL findResource(String name) {
return contextClassLoader.findResource(name);
}
public Enumeration<URL> findResources(String name) throws IOException {
return contextClassLoader.findResources(name);
}
public URL getResource(String name) {
return contextClassLoader.getResource(name);
}
public Enumeration<URL> getResources(String name) throws IOException {
return contextClassLoader.getResources(name);
}
public void setDefaultAssertionStatus(boolean enabled) {
contextClassLoader.setDefaultAssertionStatus(enabled);
}
public void setPackageAssertionStatus(String packageName, boolean enabled) {
contextClassLoader.setPackageAssertionStatus(packageName, enabled);
}
public void setClassAssertionStatus(String className, boolean enabled) {
contextClassLoader.setClassAssertionStatus(className, enabled);
}
public void clearAssertionStatus() {
contextClassLoader.clearAssertionStatus();
}
}
Configuré CustomAppClassLoader tanto como pude (llamando a super con ''url'' y ''parent'' desde el cargador de clases original), pero igual sigo delegando todos los métodos públicos en el cargador de clases original.
Esto funciona para mi. Ahora, la mejor pregunta es, ¿realmente quiero esto? :)
Una mejor opción
Creo que Spring Cloud''s RestartEndpoint
es una mejor opción: Spring Cloud''s RestartEndpoint
programáticamente la aplicación Spring Boot Sin embargo, RestartEndPoint
no maneja la detección de cambios en la ruta de clase.
Estoy ejecutando mi aplicación de arranque de primavera en un contenedor Docker, tratando de utilizar LiveReload remoto .
La documentación DevTools de arranque de primavera indica que
Las herramientas de desarrollador se desactivan automáticamente cuando se ejecuta una aplicación completamente empaquetada. Si su aplicación se inicia utilizando java -jar o si ha comenzado a usar un cargador de clases especial, entonces se considera una "aplicación de producción".
¿Hay alguna forma de forzar la habilitación de DevTools?