diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java index f992bfd39..417f3064e 100644 --- a/src/main/java/com/blade/Blade.java +++ b/src/main/java/com/blade/Blade.java @@ -489,6 +489,11 @@ public Environment environment() { return environment; } + public Blade environment(Environment environment) { + this.environment = environment; + return this; + } + /** * Set to start the web server to monitor port, the default is 9000 * @@ -550,14 +555,14 @@ public Blade appName(@NonNull String appName) { } /** - * Add a event listener + * Add a event watcher * When the trigger event is executed eventListener * * @param eventType event type - * @param eventListener event listener + * @param eventListener event watcher * @return blade */ - public Blade event(@NonNull EventType eventType, @NonNull EventListener eventListener) { + public Blade event(@NonNull EventType eventType, @NonNull EventListener eventListener) { eventManager.addEventListener(eventType, eventListener); return this; } @@ -630,6 +635,11 @@ public Blade disableSession() { return this; } + public Blade watchEnvChange(boolean watchEnvChange){ + this.environment.set(ENV_KEY_APP_WATCH_ENV, watchEnvChange); + return this; + } + /** * Start blade application. *

diff --git a/src/main/java/com/blade/event/Event.java b/src/main/java/com/blade/event/Event.java index 81aa8341e..eb146cc35 100644 --- a/src/main/java/com/blade/event/Event.java +++ b/src/main/java/com/blade/event/Event.java @@ -16,6 +16,7 @@ package com.blade.event; import com.blade.Blade; +import com.blade.mvc.WebContext; /** * Event @@ -23,18 +24,21 @@ * @author biezhi * @date 2017/9/18 */ -public class Event { +public class Event { public EventType eventType; - public Blade blade; + private T data; - public Event(EventType eventType) { + public Event(EventType eventType, T data) { this.eventType = eventType; + this.data = data; } - public Event(EventType eventType, Blade blade) { - this.eventType = eventType; - this.blade = blade; + public Blade blade(){ + return WebContext.blade(); } + public T data(){ + return this.data; + } } \ No newline at end of file diff --git a/src/main/java/com/blade/event/EventListener.java b/src/main/java/com/blade/event/EventListener.java index 616d47163..fdbd7f1c2 100644 --- a/src/main/java/com/blade/event/EventListener.java +++ b/src/main/java/com/blade/event/EventListener.java @@ -22,13 +22,13 @@ * @date 2017/9/18 */ @FunctionalInterface -public interface EventListener { +public interface EventListener { /** * Start event * * @param e Event instance */ - void trigger(Event e); + void trigger(Event e); } \ No newline at end of file diff --git a/src/main/java/com/blade/event/EventManager.java b/src/main/java/com/blade/event/EventManager.java index 81469801f..e5e588d03 100644 --- a/src/main/java/com/blade/event/EventManager.java +++ b/src/main/java/com/blade/event/EventManager.java @@ -15,7 +15,6 @@ */ package com.blade.event; -import com.blade.Blade; import com.blade.ioc.bean.OrderComparator; import java.util.LinkedList; @@ -39,14 +38,14 @@ public EventManager() { this.listenerMap = Stream.of(EventType.values()).collect(Collectors.toMap(v -> v, v -> new LinkedList<>())); } - public void addEventListener(EventType type, EventListener listener) { + public void addEventListener(EventType type, EventListener listener) { listenerMap.get(type).add(listener); } - public void fireEvent(EventType type, Blade blade) { + public void fireEvent(EventType type, T data) { listenerMap.get(type).stream() .sorted(comparator) - .forEach(listener -> listener.trigger(new Event(type, blade))); + .forEach(listener -> listener.trigger(new Event<>(type, data))); } void fireEvent(EventType type) { diff --git a/src/main/java/com/blade/event/EventType.java b/src/main/java/com/blade/event/EventType.java index cf89f3570..9a8f3f7c3 100644 --- a/src/main/java/com/blade/event/EventType.java +++ b/src/main/java/com/blade/event/EventType.java @@ -28,5 +28,6 @@ public enum EventType { SERVER_STOPPED, SESSION_CREATED, SESSION_DESTROY, - SOURCE_CHANGED + SOURCE_CHANGED, + ENVIRONMENT_CHANGED } \ No newline at end of file diff --git a/src/main/java/com/blade/mvc/Const.java b/src/main/java/com/blade/mvc/Const.java index 8b581acab..3be2d19eb 100644 --- a/src/main/java/com/blade/mvc/Const.java +++ b/src/main/java/com/blade/mvc/Const.java @@ -46,6 +46,7 @@ public interface Const { String ENV_KEY_DEV_MODE = "app.devMode"; String ENV_KEY_APP_NAME = "app.name"; String ENV_KEY_APP_THREAD_NAME = "app.thread-name"; + String ENV_KEY_APP_WATCH_ENV = "app.watch-env"; String ENV_KEY_BANNER_PATH = "app.banner-path"; String ENV_KEY_GZIP_ENABLE = "http.gzip.enable"; String ENV_KEY_CORS_ENABLE = "http.cors.enable"; diff --git a/src/main/java/com/blade/server/netty/NettyServer.java b/src/main/java/com/blade/server/netty/NettyServer.java index f8e380232..047c42b28 100644 --- a/src/main/java/com/blade/server/netty/NettyServer.java +++ b/src/main/java/com/blade/server/netty/NettyServer.java @@ -25,6 +25,7 @@ import com.blade.mvc.route.RouteMatcher; import com.blade.mvc.ui.template.DefaultEngine; import com.blade.server.Server; +import com.blade.watcher.EnvironmentWatcher; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; @@ -84,6 +85,8 @@ public void start(Blade blade, String[] args) throws Exception { this.shutdownHook(); + this.watchEnv(); + this.startServer(initStart); } @@ -115,7 +118,6 @@ private void initIoc() { } this.processors.stream().sorted(new OrderComparator<>()).forEach(b -> b.processor(blade)); - } private void startServer(long startTime) throws Exception { @@ -213,6 +215,17 @@ private boolean isExceptionHandler(Class clazz) { ReflectKit.hasInterface(clazz, ExceptionHandler.class) || clazz.getSuperclass().equals(DefaultExceptionHandler.class))); } + private void watchEnv() { + boolean watchEnv = environment.getBoolean(ENV_KEY_APP_WATCH_ENV, true); + log.info("⬢ Watched environment: {}", watchEnv); + + if (watchEnv) { + Thread t = new Thread(new EnvironmentWatcher()); + t.setName("watch@thread"); + t.start(); + } + } + private void loadConfig(String[] args) { String bootConf = blade.environment().get(ENV_KEY_BOOT_CONF, "classpath:app.properties"); @@ -278,7 +291,9 @@ private void initConfig() { } private void shutdownHook() { - Runtime.getRuntime().addShutdownHook(new Thread(this::stop)); + Thread shutdownThread = new Thread(this::stop); + shutdownThread.setName("shutdown@thread"); + Runtime.getRuntime().addShutdownHook(shutdownThread); } @Override diff --git a/src/main/java/com/blade/server/netty/ProgressiveFutureListener.java b/src/main/java/com/blade/server/netty/ProgressiveFutureListener.java index df4b60f32..adcba6e0f 100644 --- a/src/main/java/com/blade/server/netty/ProgressiveFutureListener.java +++ b/src/main/java/com/blade/server/netty/ProgressiveFutureListener.java @@ -7,7 +7,7 @@ import java.io.RandomAccessFile; /** - * File progressive future listener + * File progressive future watcher * * @author biezhi */ diff --git a/src/main/java/com/blade/watcher/EnvironmentWatcher.java b/src/main/java/com/blade/watcher/EnvironmentWatcher.java new file mode 100644 index 000000000..0ceb55b6f --- /dev/null +++ b/src/main/java/com/blade/watcher/EnvironmentWatcher.java @@ -0,0 +1,68 @@ +package com.blade.watcher; + +import com.blade.Environment; +import com.blade.event.EventType; +import com.blade.mvc.Const; +import com.blade.mvc.WebContext; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.*; + +/** + * Environment watcher + * + * @author biezhi + * @date 2017/12/24 + */ +@Slf4j +public class EnvironmentWatcher implements Runnable { + + @Override + public void run() { + final Path path = Paths.get(Const.CLASSPATH); + + try (WatchService watchService = FileSystems.getDefault().newWatchService()) { + + path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE); + + // start an infinite loop + while (true) { + final WatchKey key = watchService.take(); + for (WatchEvent watchEvent : key.pollEvents()) { + final WatchEvent.Kind kind = watchEvent.kind(); + if (kind == StandardWatchEventKinds.OVERFLOW) { + continue; + } + // get the filename for the event + final WatchEvent watchEventPath = (WatchEvent) watchEvent; + final String filename = watchEventPath.context().toString(); + // print it out + if (log.isDebugEnabled()) { + log.debug("⬢ {} -> {}", kind, filename); + } + if (kind == StandardWatchEventKinds.ENTRY_DELETE && + filename.startsWith(".app") && filename.endsWith(".properties.swp")) { + // reload env + log.info("⬢ Reload environment"); + + Environment environment = Environment.of("classpath:" + filename.substring(1, filename.length() - 4)); + WebContext.blade().environment(environment); + // notify + WebContext.blade().eventManager().fireEvent(EventType.ENVIRONMENT_CHANGED, environment); + } + } + // reset the keyf + boolean valid = key.reset(); + // exit loop if the key is not valid (if the directory was + // deleted, for + if (!valid) { + break; + } + } + } catch (IOException | InterruptedException ex) { + log.error("Environment watch error", ex); + } + } + +} diff --git a/src/test/java/com/blade/BladeTest.java b/src/test/java/com/blade/BladeTest.java index 03788aa37..449801d19 100644 --- a/src/test/java/com/blade/BladeTest.java +++ b/src/test/java/com/blade/BladeTest.java @@ -51,7 +51,7 @@ public void testRegister() { start( app.register(new BladeBeanDefineType()) .event(EventType.SERVER_STARTED, e -> { - Object bladeBeanDefineType = e.blade.getBean(BladeBeanDefineType.class); + Object bladeBeanDefineType = e.blade().getBean(BladeBeanDefineType.class); Assert.assertNotNull(bladeBeanDefineType); }) ); diff --git a/src/test/java/com/blade/event/EventTest.java b/src/test/java/com/blade/event/EventTest.java index cd167ab73..38e64fbc3 100644 --- a/src/test/java/com/blade/event/EventTest.java +++ b/src/test/java/com/blade/event/EventTest.java @@ -1,6 +1,5 @@ package com.blade.event; -import com.blade.Blade; import org.junit.Assert; import org.junit.Test; @@ -10,17 +9,11 @@ */ public class EventTest { - @Test - public void testEvent(){ - Event event = new Event(EventType.SERVER_STARTED); - Assert.assertEquals("SERVER_STARTED", event.eventType.name()); - } - @Test public void testEventAndBlade(){ - Event event = new Event(EventType.SERVER_STARTED, Blade.me()); + Event event = new Event(EventType.SERVER_STARTED, "hello"); Assert.assertEquals("SERVER_STARTED", event.eventType.name()); - Assert.assertNotNull(event.blade); + Assert.assertNotNull(event.data()); } } \ No newline at end of file diff --git a/src/test/java/netty_hello/ConfigChanged.java b/src/test/java/netty_hello/ConfigChanged.java new file mode 100644 index 000000000..2f105bf49 --- /dev/null +++ b/src/test/java/netty_hello/ConfigChanged.java @@ -0,0 +1,22 @@ +package netty_hello; + +import com.blade.Environment; +import com.blade.event.Event; +import com.blade.event.EventListener; +import com.blade.ioc.annotation.Bean; + +/** + * @author biezhi + * @date 2017/12/24 + */ +@Bean +public class ConfigChanged implements EventListener { + + @Override + public void trigger(Event e) { + Environment environment = e.data(); + System.out.println("EventListener::ConfigChanged"); + System.out.println(environment.toMap()); + } + +} diff --git a/src/test/java/netty_hello/Hello.java b/src/test/java/netty_hello/Hello.java index ca3cbe43c..6ef483461 100644 --- a/src/test/java/netty_hello/Hello.java +++ b/src/test/java/netty_hello/Hello.java @@ -1,6 +1,7 @@ package netty_hello; import com.blade.Blade; +import com.blade.event.EventType; /** * @author biezhi @@ -13,6 +14,7 @@ public static void main(String[] args) { // .devMode(false) // .environment(Const.ENV_KEY_NETTY_WORKERS, Runtime.getRuntime().availableProcessors()) .get("/hello", ((request, response) -> response.text("Hello World."))) + .event(EventType.ENVIRONMENT_CHANGED, new ConfigChanged()) .start(Hello.class, args); } }