All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.noear.solon.SolonApp Maven / Gradle / Ivy
/*
* Copyright 2017-2024 noear.org and authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.noear.solon;
import org.noear.solon.annotation.Import;
import org.noear.solon.core.*;
import org.noear.solon.core.convert.ConverterManager;
import org.noear.solon.core.event.EventListener;
import org.noear.solon.core.event.*;
import org.noear.solon.core.exception.StatusException;
import org.noear.solon.core.handle.*;
import org.noear.solon.core.route.RouterWrapper;
import org.noear.solon.core.runtime.NativeDetector;
import org.noear.solon.core.util.ConsumerEx;
import org.noear.solon.core.util.LogUtil;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* 应用管理中心
*
*
* @SolonMain
* public class DemoApp{
* public static void main(String[] args){
* Solon.start(DemoApp.class, args);
* }
* }
*
*
* @author noear
* @since 1.0
*/
public class SolonApp extends RouterWrapper {
private final SolonProps _cfg; //属性配置
private final AppContext _context;//容器上下文
private final ConverterManager _converterManager; //转换管理器
private final RenderManager _renderManager; //渲染管理器
private final HandlerPipeline _handler = new HandlerPipeline();
private final Class> _source; //应用加载源
private final URL _sourceLocation;
private final long _startupTime;
protected boolean stopped = false;
/**
* 应用上下文
*/
@Override
public AppContext context() {
return _context;
}
/**
* 转换管理器
*/
public ConverterManager converterManager() {
return _converterManager;
}
/**
* 渲染管理器
* */
public RenderManager renderManager() {
return _renderManager;
}
/**
* 工厂管理器
*/
public FactoryManager factoryManager() {
return FactoryManager.getGlobal();
}
/**
* 应用属性(或配置)
*/
public SolonProps cfg() {
return _cfg;
}
protected SolonApp(Class> source, NvMap args) throws Exception {
//添加启动类检测
if (source == null) {
throw new IllegalArgumentException("The startup class parameter('source') cannot be null");
}
_startupTime = System.currentTimeMillis();
_source = source;
_sourceLocation = source.getProtectionDomain().getCodeSource().getLocation();
_converterManager = new ConverterManager();
_renderManager = new RenderManager();
//添加启动类包名检测
if (source.getPackage() == null || Utils.isEmpty(source.getPackage().getName())) {
throw new IllegalStateException("The startup class is missing package: " + source.getName());
}
//初始化配置
_cfg = new SolonProps(this, args);
_context = new AppContext(new AppClassLoader(AppClassLoader.global()), _cfg);
//初始化路由
initRouter();
_handler.next(routerHandler());
}
/**
* 启动
*/
protected void start(ConsumerEx initialize) throws Throwable {
//1.0.打印构造时的告警
if (_cfg.warns.size() > 0) {
for (String warn : _cfg.warns) {
LogUtil.global().warn(warn);
}
}
//2.0.内部初始化等待(尝试ping等待)
initAwait();
//2.1.内部初始化(如配置等,顺序不能乱)
init(initialize);
//3.运行应用(运行插件、扫描Bean等)
run();
}
/**
* 初始化等待
*/
private void initAwait() throws Throwable {
String addr = cfg().get("solon.start.ping");
if (Utils.isNotEmpty(addr)) {
try {
while (true) {
if (Utils.ping(addr)) {
LogUtil.global().info("App: Start ping succeed: " + addr);
Thread.sleep(1000); //成功也再等1s
break;
} else {
LogUtil.global().warn("App: Start ping failure: " + addr);
Thread.sleep(2000);
}
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
}
/**
* 初始化(不能合在构建函数里)
*/
private void init(ConsumerEx initialize) throws Throwable {
List loaderList;
//1.尝试加载扩展文件夹
String filterStr = cfg().extendFilter();
if (Utils.isEmpty(filterStr)) {
//不需要过滤
loaderList = ExtendLoader.load(cfg().extend(), false);
} else {
//增加过滤
String[] filterS = filterStr.split(",");
loaderList = ExtendLoader.load(cfg().extend(), false, (path) -> {
for (String f : filterS) {
if (path.contains(f)) {
return true;
}
}
return false;
});
}
//2.尝试扫描插件
cfg().plugsScan(loaderList);
//3.运行自定义初始化
if (initialize != null) {
initialize.accept(this);
}
}
/**
* 运行应用
*/
private void run() throws Throwable {
//event::0.x.推送App init end事件
EventBus.publish(new AppInitEndEvent(this));
List plugs = cfg().plugs();
//1.0.尝式初始化插件 //一般插件不需要
for (int i = 0, len = plugs.size(); i < len; i++) {
if (Solon.cfg().isDebugMode()) {
LogUtil.global().info("App: plugin init: " + plugs.get(i).getClassName());
}
plugs.get(i).init(context());
}
//event::1.0.x推送Plugin init end事件
EventBus.publish(new AppPluginInitEndEvent(this));
LogUtil.global().info("App: Plugin starting");
//1.1.尝试启动插件(顺序不能乱) //不能用forEach,以免当中有插进来
for (int i = 0, len = plugs.size(); i < len; i++) {
plugs.get(i).start(context());
}
//1.2.检查配置是否完全适配
cfg().complete();
//event::1.3.推送Plugin load end事件
EventBus.publish(new AppPluginLoadEndEvent(this));
LogUtil.global().info("App: Bean scanning");
//2.1.通过注解导入bean(一般是些配置器)
beanImportTry();
//2.2.通过源扫描bean
if (source() != null) {
context().beanScan(source());
}
//event::2.x.推送Bean load end事件
EventBus.publish(new AppBeanLoadEndEvent(this));
//3.加载渲染关系
Map map = cfg().getMap("solon.view.mapping.");
map.forEach((k, v) -> {
renderManager().register("." + k, v);
});
//3.1.尝试设置 context-path
if (Utils.isNotEmpty(Solon.cfg().serverContextPath())) {
filterIfAbsent(Constants.FT_IDX_CONTEXT_PATH, new ContextPathFilter());
}
//3.2.标识上下文加载完成
context().start();
//event::4.x.推送App load end事件
EventBus.publish(new AppLoadEndEvent(this));
}
//通过注解,导入bean
protected void beanImportTry() {
if (_source == null) {
return;
}
for (Annotation a1 : _source.getAnnotations()) {
if (a1 instanceof Import) {
context().beanImport((Import) a1);
} else {
context().beanImport(a1.annotationType().getAnnotation(Import.class));
}
}
}
//////////////////////////////////
private final Map signals = new LinkedHashMap<>();
/**
* 添加信号
*/
public void signalAdd(Signal instance) {
signals.putIfAbsent(instance.port(), instance);
}
/**
* 获取信号
*
* @param port 端口
*/
public Signal signalGet(int port) {
return signals.get(port);
}
/**
* 获取信号记录
*/
public Collection signals() {
return Collections.unmodifiableCollection(signals.values());
}
//////////////////////////////////
/**
* 共享变量(一般用于插件之间)
*/
private final Set> _onSharedAdd_event = new HashSet<>();
private final Map _shared = new HashMap<>();
private Map _shared_unmod;
/**
* 类加载器
*/
public ClassLoader classLoader() {
return context().getClassLoader();
}
/**
* 添加共享对象
*/
public void sharedAdd(String key, Object obj) {
_shared.put(key, obj);
_onSharedAdd_event.forEach(fun -> {
fun.accept(key, obj);
});
}
/**
* 获取共享对象(异步获取)
*/
public void sharedGet(String key, Consumer event) {
Object tmp = _shared.get(key);
if (tmp != null) {
event.accept((T) tmp);
} else {
onSharedAdd((k, v) -> {
if (k.equals(key)) {
event.accept((T) v);
}
});
}
}
/**
* 共享对象添加事件
*/
public void onSharedAdd(BiConsumer event) {
_onSharedAdd_event.add(event);
}
/**
* 共享对象
*/
public Map shared() {
if (_shared_unmod == null) {
_shared_unmod = Collections.unmodifiableMap(_shared);
}
return _shared_unmod;
}
/**
* 从启动开启已运行时间
*/
protected long elapsedTimes() {
return System.currentTimeMillis() - _startupTime;
}
/**
* 启动入口类
*/
public Class> source() {
return _source;
}
/**
* 启动入口类所在位置
*/
public URL sourceLocation() {
return _sourceLocation;
}
/**
* 插入插件(一般用于动态加载,比如 faas)
*/
public void plug(Plugin plugin) {
PluginEntity p = new PluginEntity(plugin);
p.init(context());
p.start(context());
cfg().plugs().add(p);
}
/**
* 添加插件(只有执行前添加才有效)
*
* @param priority 优先级(越大越优化)
* @param plugin 插件
*/
public void pluginAdd(int priority, Plugin plugin) {
PluginEntity p = new PluginEntity(plugin, priority);
cfg().plugs().add(p);
cfg().plugsSort();
}
/**
* 处理器获取
*/
public HandlerPipeline handler() {
return _handler;
}
/**
* 应用请求处理入口(异常时,自动500处理)
*/
public void tryHandle(Context x) {
try {
//设置当前线程上下文
ContextUtil.currentSet(x);
if (stopped) {
x.status(503);
} else {
chainManager().doFilter(x, _handler);
//todo: 改由 HttpException 处理(不会到这里来了)
// if (x.getHandled() == false) { //@since: 1.9
// if (x.status() <= 200 && x.mainHandler() == null) {//@since: 1.10
// int statusPreview = x.statusPreview(); //支持405 //@since: 2.5
// if (statusPreview > 0) {
// x.status(statusPreview);
// } else {
// x.status(404);
// }
// }
// //x.setHandled(true); //todo: 不能加,对websocket有影响
// }
}
//40x,50x...
doStatus(x);
} catch (Throwable ex) {
ex = Utils.throwableUnwrap(ex);
//如果未处理,尝试处理
if (ex instanceof StatusException) {
StatusException se = (StatusException) ex;
x.status(se.getCode());
if (se.getCode() != 404 && se.getCode() != 405) {
LogUtil.global().warn("SolonApp tryHandle failed, code=" + se.getCode(), ex);
}
} else {
//推送异常事件 //todo: Action -> Gateway? -> RouterHandler -> Filter -> SolonApp!
LogUtil.global().warn("SolonApp tryHandle failed!", ex);
if (x.getHandled() == false) {
if (x.status() < 400) {
x.status(500);
}
//x.setHandled(true); 不再需要
}
}
//如果未渲染,尝试渲染
if (x.getRendered() == false) {
//40x,50x...
try {
if (doStatus(x) == false) {
if (Solon.cfg().isDebugMode()) {
x.output(ex);
}
}
} catch (RuntimeException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
} finally {
//移除当前线程上下文
ContextUtil.currentRemove();
}
}
protected boolean doStatus(Context x) throws Throwable {
if (x.status() >= 400 && _statusHandlers.size() > 0) {
Handler h = _statusHandlers.get(x.status());
if (h != null) {
x.status(200);
x.setHandled(true);
h.handle(x);
return true;
}
}
return false;
}
/**
* 订阅事件
*/
public SolonApp onEvent(Class type, EventListener handler) {
EventBus.subscribe(type, handler);
return this;
}
/**
* 订阅事件
*/
public SolonApp onEvent(Class type, int index, EventListener handler) {
EventBus.subscribe(type, index, handler);
return this;
}
private Map _statusHandlers = new HashMap<>();
/**
* 订阅异常状态
*/
public SolonApp onStatus(Integer code, Handler handler) {
_statusHandlers.put(code, handler);
return this;
}
/**
* 锁住线程(如果有需要,建议在启动程序的最后调用)
*/
public void block() throws InterruptedException {
Thread.currentThread().join();
}
private boolean _enableHttp = true; //与函数同名,_开头
/**
* 是否已启用 Http 信号接入
*/
public boolean enableHttp() {
return _enableHttp && NativeDetector.isNotAotRuntime();
}
/**
* 启用 Http 信号接入
*/
public SolonApp enableHttp(boolean enable) {
_enableHttp = enable;
return this;
}
private boolean _enableWebSocket = false;
public boolean enableWebSocket() {
return _enableWebSocket && NativeDetector.isNotAotRuntime();
}
/**
* 启用 WebSocket 信号接入
*
* @param enable 是否启用
*/
public SolonApp enableWebSocket(boolean enable) {
_enableWebSocket = enable;
return this;
}
private boolean _enableSocketD = false;
/**
* 是否已启用 SocketD 信号接入
*/
public boolean enableSocketD() {
return _enableSocketD && NativeDetector.isNotAotRuntime();
}
/**
* 启用 SocketD 信号接入
*
* @param enable 是否启用
*/
public SolonApp enableSocketD(boolean enable) {
_enableSocketD = enable;
return this;
}
private boolean _enableTransaction = true;
/**
* 是否已启用事务
*/
public boolean enableTransaction() {
return _enableTransaction;
}
/**
* 启用事务
*
* @param enable 是否启用
*/
public SolonApp enableTransaction(boolean enable) {
_enableTransaction = enable;
return this;
}
private boolean _enableCaching = true;
/**
* 是否已启用缓存
*/
public boolean enableCaching() {
return _enableCaching;
}
/**
* 启用缓存
*
* @param enable 是否启用
*/
public SolonApp enableCaching(boolean enable) {
_enableCaching = enable;
return this;
}
private boolean _enableStaticfiles = true;
/**
* 是否已启用静态文件服务
*/
public boolean enableStaticfiles() {
return _enableStaticfiles;
}
/**
* 启用静态文件服务
*
* @param enable 是否启用
*/
public SolonApp enableStaticfiles(boolean enable) {
_enableStaticfiles = enable;
return this;
}
private boolean _enableSessionState = true;
/**
* 是否已启用会话状态
*/
public boolean enableSessionState() {
return _enableSessionState;
}
/**
* 启用会话状态
*
* @param enable 是否启用
*/
public SolonApp enableSessionState(boolean enable) {
_enableSessionState = enable;
return this;
}
}