30 changed files with 859 additions and 527 deletions
@ -1,8 +0,0 @@ |
|||
# Default ignored files |
|||
/shelf/ |
|||
/workspace.xml |
|||
# Datasource local storage ignored files |
|||
/dataSources/ |
|||
/dataSources.local.xml |
|||
# Editor-based HTTP Client requests |
|||
/httpRequests/ |
@ -1,6 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="CompilerConfiguration"> |
|||
<bytecodeTargetLevel target="8" /> |
|||
</component> |
|||
</project> |
@ -1,6 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectDictionaryState"> |
|||
<dictionary name="mima0000" /> |
|||
</component> |
|||
</project> |
@ -1,37 +0,0 @@ |
|||
<component name="InspectionProjectProfileManager"> |
|||
<profile version="1.0"> |
|||
<option name="myName" value="Project Default" /> |
|||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" /> |
|||
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true"> |
|||
<option name="TOP_LEVEL_CLASS_OPTIONS"> |
|||
<value> |
|||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
|||
<option name="REQUIRED_TAGS" value="" /> |
|||
</value> |
|||
</option> |
|||
<option name="INNER_CLASS_OPTIONS"> |
|||
<value> |
|||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
|||
<option name="REQUIRED_TAGS" value="" /> |
|||
</value> |
|||
</option> |
|||
<option name="METHOD_OPTIONS"> |
|||
<value> |
|||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
|||
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" /> |
|||
</value> |
|||
</option> |
|||
<option name="FIELD_OPTIONS"> |
|||
<value> |
|||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
|||
<option name="REQUIRED_TAGS" value="" /> |
|||
</value> |
|||
</option> |
|||
<option name="IGNORE_DEPRECATED" value="false" /> |
|||
<option name="IGNORE_JAVADOC_PERIOD" value="true" /> |
|||
<option name="IGNORE_DUPLICATED_THROWS" value="false" /> |
|||
<option name="IGNORE_POINT_TO_ITSELF" value="false" /> |
|||
<option name="myAdditionalJavadocTags" value="date" /> |
|||
</inspection_tool> |
|||
</profile> |
|||
</component> |
@ -1,8 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectModuleManager"> |
|||
<modules> |
|||
<module fileurl="file://$PROJECT_DIR$/.idea/nl-sso-server.iml" filepath="$PROJECT_DIR$/.idea/nl-sso-server.iml" /> |
|||
</modules> |
|||
</component> |
|||
</project> |
@ -1,9 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<module type="JAVA_MODULE" version="4"> |
|||
<component name="NewModuleRootManager" inherit-compiler-output="true"> |
|||
<exclude-output /> |
|||
<content url="file://$MODULE_DIR$" /> |
|||
<orderEntry type="inheritedJdk" /> |
|||
<orderEntry type="sourceFolder" forTests="false" /> |
|||
</component> |
|||
</module> |
@ -1,6 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="VcsDirectoryMappings"> |
|||
<mapping directory="" vcs="Git" /> |
|||
</component> |
|||
</project> |
@ -0,0 +1,42 @@ |
|||
package org.nl.config; |
|||
|
|||
import com.dtp.core.support.ThreadPoolBuilder; |
|||
import com.dtp.core.support.ThreadPoolCreator; |
|||
import com.dtp.core.thread.DtpExecutor; |
|||
import org.springframework.boot.web.servlet.server.ServletWebServerFactory; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
/** |
|||
* @author ldjun |
|||
* @version 1.0 |
|||
* @date 2023年01月13日 14:30 |
|||
* @desc desc |
|||
*/ |
|||
@Configuration |
|||
public class DtpConfig { |
|||
|
|||
/** |
|||
* 通过{@link ThreadPoolCreator} 快速创建一些简单配置的动态线程池 |
|||
* tips: 建议直接在配置中心配置就行,不用@Bean声明 |
|||
* |
|||
* @return 线程池实例 |
|||
*/ |
|||
@Bean |
|||
public DtpExecutor dtpExecutor1() { |
|||
|
|||
return ThreadPoolBuilder.newBuilder() |
|||
.threadPoolName("dtpExecutor1") |
|||
.corePoolSize(1) |
|||
.maximumPoolSize(1) |
|||
.queueCapacity(1) |
|||
.ioIntensive(true) |
|||
.buildDynamic(); |
|||
} |
|||
@Bean |
|||
public Object tomcatServletWebServerFactory(ServletWebServerFactory webServerFactory) { |
|||
return new Object(); |
|||
} |
|||
|
|||
|
|||
} |
@ -1,40 +0,0 @@ |
|||
package org.nl.modules.loki.rest; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.nl.modules.common.annotation.RateLimiter; |
|||
import org.nl.modules.loki.service.LokiService; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
/** |
|||
* @Author: lyd |
|||
* @Description: 日志监控 |
|||
* @Date: 2022-08-15 |
|||
*/ |
|||
@RestController |
|||
@RequiredArgsConstructor |
|||
@Api(tags = "日志监控") |
|||
@RequestMapping("/api/loki") |
|||
@Slf4j |
|||
public class LokiController { |
|||
|
|||
private final LokiService lokiService; |
|||
|
|||
@GetMapping("/labels/values") |
|||
@ApiOperation("获取标签") |
|||
public ResponseEntity<Object> labelsValues() { |
|||
return new ResponseEntity<>(lokiService.getLabelsValues(), HttpStatus.OK); |
|||
} |
|||
|
|||
@PostMapping("/logs") |
|||
@ApiOperation("获取日志") |
|||
@RateLimiter(value = 1, timeout = 300) // 限流
|
|||
public ResponseEntity<Object> getLogData(@RequestBody JSONObject json) { |
|||
return new ResponseEntity<>(lokiService.getLogData(json), HttpStatus.OK); |
|||
} |
|||
} |
@ -1,25 +0,0 @@ |
|||
package org.nl.modules.loki.service; |
|||
|
|||
import com.alibaba.fastjson.JSONArray; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
|
|||
/** |
|||
* @Author: lyd |
|||
* @Description: 服务类 |
|||
* @Date: 2022-08-15 |
|||
*/ |
|||
public interface LokiService { |
|||
|
|||
/** |
|||
* 获取日志信息 |
|||
* @param json |
|||
* @return |
|||
*/ |
|||
JSONObject getLogData(JSONObject json); |
|||
|
|||
/** |
|||
* 获取labels和values树 |
|||
* @return |
|||
*/ |
|||
JSONArray getLabelsValues(); |
|||
} |
@ -1,113 +0,0 @@ |
|||
package org.nl.modules.loki.service.impl; |
|||
|
|||
import cn.hutool.core.util.CharsetUtil; |
|||
import cn.hutool.http.HttpUtil; |
|||
import com.alibaba.fastjson.JSONArray; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.nl.modules.loki.service.LokiService; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* @Author: lyd |
|||
* @Description: 实现类 |
|||
* @Date: 2022-08-15 |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class LokiServiceImpl implements LokiService { |
|||
|
|||
@Value("${loki.url}") |
|||
private String lokiUrl; |
|||
|
|||
@Value("${loki.systemName}") |
|||
private String systemName; |
|||
|
|||
@Override |
|||
public JSONObject getLogData(JSONObject json) { |
|||
String logLabel = ""; |
|||
String logLabelValue = ""; |
|||
Long start = 0L; |
|||
Long end = 0L; |
|||
String text = ""; |
|||
String limit = "100"; |
|||
String direction = "backward"; |
|||
if (json.get("logLabel") != null) logLabel = json.getString("logLabel"); |
|||
if (json.get("logLabelValue") != null) logLabelValue = json.getString("logLabelValue"); |
|||
if (json.get("text") != null) text = json.getString("text"); |
|||
if (json.get("start") != null) start = json.getLong("start"); |
|||
if (json.get("end") != null) end = json.getLong("end"); |
|||
if (json.get("limits") != null) limit = json.getString("limits"); |
|||
if (json.get("direction") != null) direction = json.getString("direction"); |
|||
/** |
|||
* 组织参数 |
|||
* 纳秒数 |
|||
* 1660037391880000000 |
|||
* 1641453208415000000 |
|||
* http://localhost:3100/loki/api/v1/query_range?query={host="localhost"} |= ``&limit=1500&start=1641453208415000000&end=1660027623419419002
|
|||
*/ |
|||
JSONObject parse = null; |
|||
String query = lokiUrl + "/query_range?query={system=\"" + systemName + "\", " + logLabel + "=\"" + logLabelValue + "\"} |= `" + text + "`"; |
|||
String result = ""; |
|||
if (start==0L) { |
|||
result = HttpUtil.get(query + "&limit=" + limit + "&direction=" + direction, CharsetUtil.CHARSET_UTF_8); |
|||
} else { |
|||
result = HttpUtil.get(query + "&limit=" + limit + "&start=" + start + "&end=" + end + "&direction=" + direction, CharsetUtil.CHARSET_UTF_8); |
|||
} |
|||
try { |
|||
parse = (JSONObject) JSONObject.parse(result); |
|||
} catch (Exception e) { |
|||
// reslut的值可能为:too many outstanding requests,无法转化成Json
|
|||
System.out.println("reslut:" + result); |
|||
// e.printStackTrace();
|
|||
} |
|||
return parse; |
|||
} |
|||
|
|||
/** |
|||
* 获取labels和values树 |
|||
* |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public JSONArray getLabelsValues() { |
|||
/** |
|||
* [{ |
|||
* label: |
|||
* value: |
|||
* children:[{ |
|||
* label |
|||
* value |
|||
* }] |
|||
* }] |
|||
*/ |
|||
JSONArray result = new JSONArray(); |
|||
// 获取所有标签
|
|||
String labelString = HttpUtil.get(lokiUrl + "/labels", CharsetUtil.CHARSET_UTF_8); |
|||
JSONObject parse = (JSONObject) JSONObject.parse(labelString); |
|||
JSONArray labels = parse.getJSONArray("data"); |
|||
for (int i=0; i<labels.size(); i++) { |
|||
// 获取标签下的所有值
|
|||
String valueString = HttpUtil.get(lokiUrl + "/label/" + labels.getString(i) + "/values", CharsetUtil.CHARSET_UTF_8); |
|||
JSONObject parse2 = (JSONObject) JSONObject.parse(valueString); |
|||
JSONArray values = parse2.getJSONArray("data"); |
|||
JSONArray children = new JSONArray(); |
|||
// 组成树形状态 两级
|
|||
for (int j=0; j<values.size(); j++) { |
|||
JSONObject leaf = new JSONObject(); |
|||
leaf.put("label", values.getString(j)); |
|||
leaf.put("value", values.getString(j)); |
|||
children.add(leaf); |
|||
} |
|||
|
|||
JSONObject node = new JSONObject(); |
|||
node.put("label", labels.getString(i)); |
|||
node.put("value", labels.getString(i)); |
|||
node.put("children", children); |
|||
result.add(node); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,585 @@ |
|||
package org.nl.system.service.quartz; |
|||
|
|||
import org.quartz.SchedulerConfigException; |
|||
import org.quartz.spi.ThreadPool; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import java.util.Iterator; |
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
import java.util.concurrent.atomic.AtomicBoolean; |
|||
|
|||
/** |
|||
* quartz自定义线程池 |
|||
*/ |
|||
public class SimpleThreadPool implements ThreadPool { |
|||
|
|||
/* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
* |
|||
* Data members. |
|||
* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
*/ |
|||
|
|||
private int count = -1; |
|||
|
|||
private int prio = Thread.NORM_PRIORITY; |
|||
|
|||
private boolean isShutdown = false; |
|||
private boolean handoffPending = false; |
|||
|
|||
private boolean inheritLoader = false; |
|||
|
|||
private boolean inheritGroup = true; |
|||
|
|||
private boolean makeThreadsDaemons = false; |
|||
|
|||
private ThreadGroup threadGroup; |
|||
|
|||
private final Object nextRunnableLock = new Object(); |
|||
|
|||
private List<WorkerThread> workers; |
|||
private LinkedList<WorkerThread> availWorkers = new LinkedList<WorkerThread>(); |
|||
private LinkedList<WorkerThread> busyWorkers = new LinkedList<WorkerThread>(); |
|||
|
|||
private String threadNamePrefix; |
|||
|
|||
private final Logger log = LoggerFactory.getLogger(getClass()); |
|||
|
|||
private String schedulerInstanceName; |
|||
|
|||
/* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
* |
|||
* Constructors. |
|||
* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
*/ |
|||
|
|||
/** |
|||
* <p> |
|||
* Create a new (unconfigured) <code>SimpleThreadPool</code>. |
|||
* </p> |
|||
* |
|||
* @see #setThreadCount(int) |
|||
* @see #setThreadPriority(int) |
|||
*/ |
|||
public SimpleThreadPool() { |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Create a new <code>SimpleThreadPool</code> with the specified number |
|||
* of <code>Thread</code> s that have the given priority. |
|||
* </p> |
|||
* |
|||
* @param threadCount |
|||
* the number of worker <code>Threads</code> in the pool, must |
|||
* be > 0. |
|||
* @param threadPriority |
|||
* the thread priority for the worker threads. |
|||
* |
|||
* @see Thread |
|||
*/ |
|||
public SimpleThreadPool(int threadCount, int threadPriority) { |
|||
setThreadCount(threadCount); |
|||
setThreadPriority(threadPriority); |
|||
} |
|||
|
|||
/* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
* |
|||
* Interface. |
|||
* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
*/ |
|||
|
|||
public Logger getLog() { |
|||
return log; |
|||
} |
|||
|
|||
public int getPoolSize() { |
|||
return getThreadCount(); |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Set the number of worker threads in the pool - has no effect after |
|||
* <code>initialize()</code> has been called. |
|||
* </p> |
|||
*/ |
|||
public void setThreadCount(int count) { |
|||
this.count = count; |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Get the number of worker threads in the pool. |
|||
* </p> |
|||
*/ |
|||
public int getThreadCount() { |
|||
return count; |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Set the thread priority of worker threads in the pool - has no effect |
|||
* after <code>initialize()</code> has been called. |
|||
* </p> |
|||
*/ |
|||
public void setThreadPriority(int prio) { |
|||
this.prio = prio; |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Get the thread priority of worker threads in the pool. |
|||
* </p> |
|||
*/ |
|||
public int getThreadPriority() { |
|||
return prio; |
|||
} |
|||
|
|||
public void setThreadNamePrefix(String prfx) { |
|||
this.threadNamePrefix = prfx; |
|||
} |
|||
|
|||
public String getThreadNamePrefix() { |
|||
return threadNamePrefix; |
|||
} |
|||
|
|||
/** |
|||
* @return Returns the |
|||
* threadsInheritContextClassLoaderOfInitializingThread. |
|||
*/ |
|||
public boolean isThreadsInheritContextClassLoaderOfInitializingThread() { |
|||
return inheritLoader; |
|||
} |
|||
|
|||
/** |
|||
* @param inheritLoader |
|||
* The threadsInheritContextClassLoaderOfInitializingThread to |
|||
* set. |
|||
*/ |
|||
public void setThreadsInheritContextClassLoaderOfInitializingThread( |
|||
boolean inheritLoader) { |
|||
this.inheritLoader = inheritLoader; |
|||
} |
|||
|
|||
public boolean isThreadsInheritGroupOfInitializingThread() { |
|||
return inheritGroup; |
|||
} |
|||
|
|||
public void setThreadsInheritGroupOfInitializingThread( |
|||
boolean inheritGroup) { |
|||
this.inheritGroup = inheritGroup; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @return Returns the value of makeThreadsDaemons. |
|||
*/ |
|||
public boolean isMakeThreadsDaemons() { |
|||
return makeThreadsDaemons; |
|||
} |
|||
|
|||
/** |
|||
* @param makeThreadsDaemons |
|||
* The value of makeThreadsDaemons to set. |
|||
*/ |
|||
public void setMakeThreadsDaemons(boolean makeThreadsDaemons) { |
|||
this.makeThreadsDaemons = makeThreadsDaemons; |
|||
} |
|||
|
|||
public void setInstanceId(String schedInstId) { |
|||
} |
|||
|
|||
public void setInstanceName(String schedName) { |
|||
schedulerInstanceName = schedName; |
|||
} |
|||
|
|||
public void initialize() throws SchedulerConfigException { |
|||
|
|||
if(workers != null && workers.size() > 0) // already initialized...
|
|||
return; |
|||
|
|||
if (count <= 0) { |
|||
throw new SchedulerConfigException( |
|||
"Thread count must be > 0"); |
|||
} |
|||
if (prio <= 0 || prio > 9) { |
|||
throw new SchedulerConfigException( |
|||
"Thread priority must be > 0 and <= 9"); |
|||
} |
|||
|
|||
if(isThreadsInheritGroupOfInitializingThread()) { |
|||
threadGroup = Thread.currentThread().getThreadGroup(); |
|||
} else { |
|||
// follow the threadGroup tree to the root thread group.
|
|||
threadGroup = Thread.currentThread().getThreadGroup(); |
|||
ThreadGroup parent = threadGroup; |
|||
while ( !parent.getName().equals("main") ) { |
|||
threadGroup = parent; |
|||
parent = threadGroup.getParent(); |
|||
} |
|||
threadGroup = new ThreadGroup(parent, schedulerInstanceName + "-SimpleThreadPool"); |
|||
if (isMakeThreadsDaemons()) { |
|||
threadGroup.setDaemon(true); |
|||
} |
|||
} |
|||
|
|||
|
|||
if (isThreadsInheritContextClassLoaderOfInitializingThread()) { |
|||
getLog().info( |
|||
"Job execution threads will use class loader of thread: " |
|||
+ Thread.currentThread().getName()); |
|||
} |
|||
|
|||
// create the worker threads and start them
|
|||
Iterator<WorkerThread> workerThreads = createWorkerThreads(count).iterator(); |
|||
while(workerThreads.hasNext()) { |
|||
WorkerThread wt = workerThreads.next(); |
|||
wt.start(); |
|||
availWorkers.add(wt); |
|||
} |
|||
} |
|||
|
|||
protected List<WorkerThread> createWorkerThreads(int createCount) { |
|||
workers = new LinkedList<WorkerThread>(); |
|||
for (int i = 1; i<= createCount; ++i) { |
|||
String threadPrefix = getThreadNamePrefix(); |
|||
if (threadPrefix == null) { |
|||
threadPrefix = schedulerInstanceName + "_Worker"; |
|||
} |
|||
WorkerThread wt = new WorkerThread(this, threadGroup, |
|||
threadPrefix + "-" + i, |
|||
getThreadPriority(), |
|||
isMakeThreadsDaemons()); |
|||
if (isThreadsInheritContextClassLoaderOfInitializingThread()) { |
|||
wt.setContextClassLoader(Thread.currentThread() |
|||
.getContextClassLoader()); |
|||
} |
|||
workers.add(wt); |
|||
} |
|||
|
|||
return workers; |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Terminate any worker threads in this thread group. |
|||
* </p> |
|||
* |
|||
* <p> |
|||
* Jobs currently in progress will complete. |
|||
* </p> |
|||
*/ |
|||
public void shutdown() { |
|||
shutdown(true); |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Terminate any worker threads in this thread group. |
|||
* </p> |
|||
* |
|||
* <p> |
|||
* Jobs currently in progress will complete. |
|||
* </p> |
|||
*/ |
|||
public void shutdown(boolean waitForJobsToComplete) { |
|||
|
|||
synchronized (nextRunnableLock) { |
|||
getLog().debug("Shutting down threadpool..."); |
|||
|
|||
isShutdown = true; |
|||
|
|||
if(workers == null) // case where the pool wasn't even initialize()ed
|
|||
return; |
|||
|
|||
// signal each worker thread to shut down
|
|||
Iterator<WorkerThread> workerThreads = workers.iterator(); |
|||
while(workerThreads.hasNext()) { |
|||
WorkerThread wt = workerThreads.next(); |
|||
wt.shutdown(); |
|||
availWorkers.remove(wt); |
|||
} |
|||
|
|||
// Give waiting (wait(1000)) worker threads a chance to shut down.
|
|||
// Active worker threads will shut down after finishing their
|
|||
// current job.
|
|||
nextRunnableLock.notifyAll(); |
|||
|
|||
if (waitForJobsToComplete == true) { |
|||
|
|||
boolean interrupted = false; |
|||
try { |
|||
// wait for hand-off in runInThread to complete...
|
|||
while(handoffPending) { |
|||
try { |
|||
nextRunnableLock.wait(100); |
|||
} catch(InterruptedException _) { |
|||
interrupted = true; |
|||
} |
|||
} |
|||
|
|||
// Wait until all worker threads are shut down
|
|||
while (busyWorkers.size() > 0) { |
|||
WorkerThread wt = (WorkerThread) busyWorkers.getFirst(); |
|||
try { |
|||
getLog().debug( |
|||
"Waiting for thread " + wt.getName() |
|||
+ " to shut down"); |
|||
|
|||
// note: with waiting infinite time the
|
|||
// application may appear to 'hang'.
|
|||
nextRunnableLock.wait(2000); |
|||
} catch (InterruptedException _) { |
|||
interrupted = true; |
|||
} |
|||
} |
|||
|
|||
workerThreads = workers.iterator(); |
|||
while(workerThreads.hasNext()) { |
|||
WorkerThread wt = (WorkerThread) workerThreads.next(); |
|||
try { |
|||
wt.join(); |
|||
workerThreads.remove(); |
|||
} catch (InterruptedException _) { |
|||
interrupted = true; |
|||
} |
|||
} |
|||
} finally { |
|||
if (interrupted) { |
|||
Thread.currentThread().interrupt(); |
|||
} |
|||
} |
|||
|
|||
getLog().debug("No executing jobs remaining, all threads stopped."); |
|||
} |
|||
getLog().debug("Shutdown of threadpool complete."); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Run the given <code>Runnable</code> object in the next available |
|||
* <code>Thread</code>. If while waiting the thread pool is asked to |
|||
* shut down, the Runnable is executed immediately within a new additional |
|||
* thread. |
|||
* </p> |
|||
* |
|||
* @param runnable |
|||
* the <code>Runnable</code> to be added. |
|||
*/ |
|||
public boolean runInThread(Runnable runnable) { |
|||
if (runnable == null) { |
|||
return false; |
|||
} |
|||
|
|||
synchronized (nextRunnableLock) { |
|||
|
|||
handoffPending = true; |
|||
|
|||
// Wait until a worker thread is available
|
|||
while ((availWorkers.size() < 1) && !isShutdown) { |
|||
try { |
|||
nextRunnableLock.wait(500); |
|||
} catch (InterruptedException ignore) { |
|||
} |
|||
} |
|||
|
|||
if (!isShutdown) { |
|||
WorkerThread wt = (WorkerThread)availWorkers.removeFirst(); |
|||
busyWorkers.add(wt); |
|||
wt.run(runnable); |
|||
} else { |
|||
// If the thread pool is going down, execute the Runnable
|
|||
// within a new additional worker thread (no thread from the pool).
|
|||
WorkerThread wt = new WorkerThread(this, threadGroup, |
|||
"WorkerThread-LastJob", prio, isMakeThreadsDaemons(), runnable); |
|||
busyWorkers.add(wt); |
|||
workers.add(wt); |
|||
wt.start(); |
|||
} |
|||
nextRunnableLock.notifyAll(); |
|||
handoffPending = false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public int blockForAvailableThreads() { |
|||
synchronized(nextRunnableLock) { |
|||
|
|||
while((availWorkers.size() < 1 || handoffPending) && !isShutdown) { |
|||
try { |
|||
nextRunnableLock.wait(500); |
|||
} catch (InterruptedException ignore) { |
|||
} |
|||
} |
|||
|
|||
return availWorkers.size(); |
|||
} |
|||
} |
|||
|
|||
protected void makeAvailable(WorkerThread wt) { |
|||
synchronized(nextRunnableLock) { |
|||
if(!isShutdown) { |
|||
availWorkers.add(wt); |
|||
} |
|||
busyWorkers.remove(wt); |
|||
nextRunnableLock.notifyAll(); |
|||
} |
|||
} |
|||
|
|||
protected void clearFromBusyWorkersList(WorkerThread wt) { |
|||
synchronized(nextRunnableLock) { |
|||
busyWorkers.remove(wt); |
|||
nextRunnableLock.notifyAll(); |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
* |
|||
* WorkerThread Class. |
|||
* |
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
*/ |
|||
|
|||
/** |
|||
* <p> |
|||
* A Worker loops, waiting to execute tasks. |
|||
* </p> |
|||
*/ |
|||
class WorkerThread extends Thread { |
|||
|
|||
private final Object lock = new Object(); |
|||
|
|||
// A flag that signals the WorkerThread to terminate.
|
|||
private AtomicBoolean run = new AtomicBoolean(true); |
|||
|
|||
private SimpleThreadPool tp; |
|||
|
|||
private Runnable runnable = null; |
|||
|
|||
private boolean runOnce = false; |
|||
|
|||
/** |
|||
* <p> |
|||
* Create a worker thread and start it. Waiting for the next Runnable, |
|||
* executing it, and waiting for the next Runnable, until the shutdown |
|||
* flag is set. |
|||
* </p> |
|||
*/ |
|||
WorkerThread(SimpleThreadPool tp, ThreadGroup threadGroup, String name, |
|||
int prio, boolean isDaemon) { |
|||
|
|||
this(tp, threadGroup, name, prio, isDaemon, null); |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Create a worker thread, start it, execute the runnable and terminate |
|||
* the thread (one time execution). |
|||
* </p> |
|||
*/ |
|||
WorkerThread(SimpleThreadPool tp, ThreadGroup threadGroup, String name, |
|||
int prio, boolean isDaemon, Runnable runnable) { |
|||
|
|||
super(threadGroup, name); |
|||
this.tp = tp; |
|||
this.runnable = runnable; |
|||
if(runnable != null) |
|||
runOnce = true; |
|||
setPriority(prio); |
|||
setDaemon(isDaemon); |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Signal the thread that it should terminate. |
|||
* </p> |
|||
*/ |
|||
void shutdown() { |
|||
run.set(false); |
|||
} |
|||
|
|||
public void run(Runnable newRunnable) { |
|||
synchronized(lock) { |
|||
if(runnable != null) { |
|||
throw new IllegalStateException("Already running a Runnable!"); |
|||
} |
|||
|
|||
runnable = newRunnable; |
|||
lock.notifyAll(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* <p> |
|||
* Loop, executing targets as they are received. |
|||
* </p> |
|||
*/ |
|||
@Override |
|||
public void run() { |
|||
boolean ran = false; |
|||
|
|||
while (run.get()) { |
|||
try { |
|||
synchronized(lock) { |
|||
while (runnable == null && run.get()) { |
|||
lock.wait(500); |
|||
} |
|||
|
|||
if (runnable != null) { |
|||
ran = true; |
|||
runnable.run(); |
|||
} |
|||
} |
|||
} catch (InterruptedException unblock) { |
|||
// do nothing (loop will terminate if shutdown() was called
|
|||
try { |
|||
getLog().error("Worker thread was interrupt()'ed.", unblock); |
|||
} catch(Exception e) { |
|||
// ignore to help with a tomcat glitch
|
|||
} |
|||
} catch (Throwable exceptionInRunnable) { |
|||
try { |
|||
getLog().error("Error while executing the Runnable: ", |
|||
exceptionInRunnable); |
|||
} catch(Exception e) { |
|||
// ignore to help with a tomcat glitch
|
|||
} |
|||
} finally { |
|||
synchronized(lock) { |
|||
runnable = null; |
|||
} |
|||
// repair the thread in case the runnable mucked it up...
|
|||
if(getPriority() != tp.getThreadPriority()) { |
|||
setPriority(tp.getThreadPriority()); |
|||
} |
|||
|
|||
if (runOnce) { |
|||
run.set(false); |
|||
clearFromBusyWorkersList(this); |
|||
} else if(ran) { |
|||
ran = false; |
|||
makeAvailable(this); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
//if (log.isDebugEnabled())
|
|||
try { |
|||
getLog().debug("WorkerThread is shut down."); |
|||
} catch(Exception e) { |
|||
// ignore to help with a tomcat glitch
|
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,120 +0,0 @@ |
|||
# 端口 |
|||
server: |
|||
port: 9000 |
|||
|
|||
# Sa-Token 配置 |
|||
sa-token: |
|||
# ------- SSO-模式一相关配置 (非模式一不需要配置) |
|||
|
|||
# 配置 Cookie 作用域 |
|||
|
|||
# ------- SSO-模式二相关配置 |
|||
sso: |
|||
# Ticket有效期 (单位: 秒),默认五分钟 |
|||
ticket-timeout: 300 |
|||
# 所有允许的授权回调地址比较重要 |
|||
allow-url: "*" |
|||
# 是否打开单点注销功能 |
|||
is-slo: true |
|||
# ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开) |
|||
# # 是否打开模式三 |
|||
isHttp: true |
|||
# # 接口调用秘钥(用于SSO模式三的单点注销功能) |
|||
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor |
|||
token-name: EL-ADMIN-TOEKN |
|||
# # ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明) |
|||
# |
|||
spring: |
|||
#配置 Jpa |
|||
jpa: |
|||
hibernate: |
|||
ddl-auto: none |
|||
open-in-view: true |
|||
properties: |
|||
hibernate: |
|||
dialect: org.hibernate.dialect.MySQL5InnoDBDialect |
|||
enable_lazy_load_no_trans: true |
|||
# 数据源 |
|||
datasource: |
|||
druid: |
|||
db-type: com.alibaba.druid.pool.DruidDataSource |
|||
driverClassName: com.mysql.cj.jdbc.Driver |
|||
# url: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:whxr_test}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true |
|||
url: jdbc:mysql://${DB_HOST:47.111.78.178}:${DB_PORT:3306}/${DB_NAME:whxr}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true |
|||
username: ${DB_USER:root} |
|||
password: ${DB_PWD:P@ssw0rd} |
|||
# username: ${DB_USER:root} |
|||
# password: ${DB_PWD:root} |
|||
# 初始连接数 |
|||
initial-size: 5 |
|||
# 最小连接数 |
|||
min-idle: 15 |
|||
# 最大连接数 |
|||
max-active: 30 |
|||
# 是否自动回收超时连接 |
|||
remove-abandoned: true |
|||
# 超时时间(以秒数为单位) |
|||
remove-abandoned-timeout: 180 |
|||
# 获取连接超时时间 |
|||
max-wait: 300 |
|||
# 连接有效性检测时间 |
|||
time-between-eviction-runs-millis: 60000 |
|||
# 连接在池中最小生存的时间 |
|||
min-evictable-idle-time-millis: 300000 |
|||
# 连接在池中最大生存的时间 |
|||
max-evictable-idle-time-millis: 900000 |
|||
# 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 |
|||
test-while-idle: true |
|||
# 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 |
|||
test-on-borrow: true |
|||
# 是否在归还到池中前进行检验 |
|||
test-on-return: false |
|||
# 检测连接是否有效 |
|||
validation-query: select 1 |
|||
# 配置监控统计 |
|||
# webStatFilter: |
|||
# enabled: true |
|||
# stat-view-servlet: |
|||
# enabled: true |
|||
# url-pattern: /druid/* |
|||
# reset-enable: false |
|||
# filter: |
|||
# stat: |
|||
# enabled: true |
|||
# # 记录慢SQL |
|||
# log-slow-sql: true |
|||
# slow-sql-millis: 1000 |
|||
# merge-sql: true |
|||
# wall: |
|||
# config: |
|||
# multi-statement-allow: true |
|||
|
|||
# Redis配置 (SSO模式一和模式二使用Redis来同步会话) |
|||
redis: |
|||
# Redis数据库索引(默认为0) |
|||
database: 1 |
|||
# Redis服务器地址 |
|||
host: 47.96.133.178 |
|||
# Redis服务器连接端口 |
|||
port: 6479 |
|||
# Redis服务器连接密码(默认为空) |
|||
password: 942464Yy |
|||
# 连接超时时间 |
|||
timeout: 10s |
|||
lettuce: |
|||
pool: |
|||
# 连接池最大连接数 |
|||
max-active: 200 |
|||
# 连接池最大阻塞等待时间(使用负值表示没有限制) |
|||
max-wait: -1ms |
|||
# 连接池中的最大空闲连接 |
|||
max-idle: 10 |
|||
# 连接池中的最小空闲连接 |
|||
min-idle: 0 |
|||
|
|||
forest: |
|||
# 关闭 forest 请求日志打印 |
|||
log-enabled: false |
|||
|
|||
|
|||
|
@ -0,0 +1,8 @@ |
|||
CREATE TABLE `t_javastack` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', |
|||
`name` varchar(20) NOT NULL COMMENT '姓名', |
|||
`age` int(5) DEFAULT NULL COMMENT '年龄', |
|||
PRIMARY KEY (`id`) |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
|||
|
|||
|
@ -0,0 +1,8 @@ |
|||
CREATE TABLE `t_javastack` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', |
|||
`name` varchar(20) NOT NULL COMMENT '姓名', |
|||
`age` int(5) DEFAULT NULL COMMENT '年龄', |
|||
PRIMARY KEY (`id`) |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
|||
|
|||
|
@ -0,0 +1,8 @@ |
|||
CREATE TABLE `t2_javastack` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', |
|||
`name` varchar(20) NOT NULL COMMENT '姓名', |
|||
`age` int(5) DEFAULT NULL COMMENT '年龄', |
|||
PRIMARY KEY (`id`) |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
|||
|
|||
|
Loading…
Reference in new issue