mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add smart http support
This commit is contained in:
parent
2af90ebaa5
commit
7f12d45b4e
@ -34,7 +34,7 @@ import java.util.LinkedHashMap;
|
|||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class FIFOCache<K, V> extends ReentrantCache<K, V> {
|
public class FIFOCache<K, V> extends LockedCache<K, V> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,7 +55,7 @@ public class FIFOCache<K, V> extends ReentrantCache<K, V> {
|
|||||||
public FIFOCache(final int capacity, final long timeout) {
|
public FIFOCache(final int capacity, final long timeout) {
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
cacheMap = new LinkedHashMap<>(capacity + 1, 1.0f, false);
|
this.cacheMap = new LinkedHashMap<>(capacity + 1, 1.0f, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.cache.impl;
|
package org.dromara.hutool.core.cache.impl;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import org.dromara.hutool.core.thread.lock.NoLock;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LFU(least frequently used) 最少使用率缓存<br>
|
* LFU(least frequently used) 最少使用率缓存<br>
|
||||||
@ -31,7 +33,7 @@ import java.util.Iterator;
|
|||||||
* @param <K> 键类型
|
* @param <K> 键类型
|
||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
*/
|
*/
|
||||||
public class LFUCache<K, V> extends StampedCache<K, V> {
|
public class LFUCache<K, V> extends LockedCache<K, V> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +58,10 @@ public class LFUCache<K, V> extends StampedCache<K, V> {
|
|||||||
|
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
cacheMap = new HashMap<>(capacity + 1, 1.0f);
|
//lock = new ReentrantLock();
|
||||||
|
//cacheMap = new HashMap<>(capacity + 1, 1.0f);
|
||||||
|
lock = NoLock.INSTANCE;
|
||||||
|
cacheMap = new ConcurrentHashMap<>(capacity + 1, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------- prune
|
// ---------------------------------------------------------------- prune
|
||||||
|
@ -20,6 +20,7 @@ import org.dromara.hutool.core.lang.mutable.Mutable;
|
|||||||
import org.dromara.hutool.core.map.FixedLinkedHashMap;
|
import org.dromara.hutool.core.map.FixedLinkedHashMap;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LRU (least recently used)最近最久未使用缓存<br>
|
* LRU (least recently used)最近最久未使用缓存<br>
|
||||||
@ -33,7 +34,7 @@ import java.util.Iterator;
|
|||||||
* @param <K> 键类型
|
* @param <K> 键类型
|
||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
*/
|
*/
|
||||||
public class LRUCache<K, V> extends ReentrantCache<K, V> {
|
public class LRUCache<K, V> extends LockedCache<K, V> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,6 +66,7 @@ public class LRUCache<K, V> extends ReentrantCache<K, V> {
|
|||||||
listener.onRemove(entry.getKey().get(), entry.getValue().getValue());
|
listener.onRemove(entry.getKey().get(), entry.getValue().getValue());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
lock = new ReentrantLock();
|
||||||
cacheMap = fixedLinkedHashMap;
|
cacheMap = fixedLinkedHashMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,24 +19,24 @@ package org.dromara.hutool.core.cache.impl;
|
|||||||
import org.dromara.hutool.core.collection.iter.CopiedIter;
|
import org.dromara.hutool.core.collection.iter.CopiedIter;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用{@link ReentrantLock}保护的缓存,读写都使用悲观锁完成,主要避免某些Map无法使用读写锁的问题<br>
|
* 使用{@link Lock}保护的缓存,读写都使用悲观锁完成,主要避免某些Map无法使用读写锁的问题<br>
|
||||||
* 例如使用了LinkedHashMap的缓存,由于get方法也会改变Map的结构,因此读写必须加互斥锁
|
* 例如使用了LinkedHashMap的缓存,由于get方法也会改变Map的结构,因此读写必须加互斥锁
|
||||||
*
|
*
|
||||||
* @param <K> 键类型
|
* @param <K> 键类型
|
||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
* @author looly
|
* @author looly
|
||||||
* @since 5.7.15
|
|
||||||
*/
|
*/
|
||||||
public abstract class ReentrantCache<K, V> extends AbstractCache<K, V> {
|
public abstract class LockedCache<K, V> extends AbstractCache<K, V> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一些特殊缓存,例如使用了LinkedHashMap的缓存,由于get方法也会改变Map的结构,导致无法使用读写锁
|
* 一些特殊缓存,例如使用了LinkedHashMap的缓存,由于get方法也会改变Map的结构,导致无法使用读写锁
|
||||||
*/
|
*/
|
||||||
protected final ReentrantLock lock = new ReentrantLock();
|
protected Lock lock = new ReentrantLock();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(final K key, final V object, final long timeout) {
|
public void put(final K key, final V object, final long timeout) {
|
@ -1,203 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* http://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.dromara.hutool.core.cache.impl;
|
|
||||||
|
|
||||||
import org.dromara.hutool.core.collection.iter.CopiedIter;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.concurrent.locks.StampedLock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用{@link StampedLock}保护的缓存,使用读写乐观锁<br>
|
|
||||||
* 使用乐观锁有效的提高的缓存性能,但是无法避免脏读问题
|
|
||||||
*
|
|
||||||
* @param <K> 键类型
|
|
||||||
* @param <V> 值类型
|
|
||||||
* @author looly
|
|
||||||
* @since 5.7.15
|
|
||||||
*/
|
|
||||||
public abstract class StampedCache<K, V> extends AbstractCache<K, V> {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 乐观锁,此处使用乐观锁解决读多写少的场景<br>
|
|
||||||
* get时乐观读,再检查是否修改,修改则转入悲观读重新读一遍,可以有效解决在写时阻塞大量读操作的情况。<br>
|
|
||||||
* see: https://www.cnblogs.com/jiagoushijuzi/p/13721319.html
|
|
||||||
*/
|
|
||||||
protected final StampedLock lock = new StampedLock();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(final K key, final V object, final long timeout) {
|
|
||||||
final long stamp = lock.writeLock();
|
|
||||||
try {
|
|
||||||
putWithoutLock(key, object, timeout);
|
|
||||||
} finally {
|
|
||||||
lock.unlockWrite(stamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(final K key) {
|
|
||||||
return null != doGet(key, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public V get(final K key, final boolean isUpdateLastAccess) {
|
|
||||||
return doGet(key, isUpdateLastAccess, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<CacheObj<K, V>> cacheObjIterator() {
|
|
||||||
CopiedIter<CacheObj<K, V>> copiedIterator;
|
|
||||||
final long stamp = lock.readLock();
|
|
||||||
try {
|
|
||||||
copiedIterator = CopiedIter.copyOf(cacheObjIter());
|
|
||||||
} finally {
|
|
||||||
lock.unlockRead(stamp);
|
|
||||||
}
|
|
||||||
return new CacheObjIterator<>(copiedIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int prune() {
|
|
||||||
final long stamp = lock.writeLock();
|
|
||||||
try {
|
|
||||||
return pruneCache();
|
|
||||||
} finally {
|
|
||||||
lock.unlockWrite(stamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(final K key) {
|
|
||||||
final long stamp = lock.writeLock();
|
|
||||||
CacheObj<K, V> co;
|
|
||||||
try {
|
|
||||||
co = removeWithoutLock(key);
|
|
||||||
} finally {
|
|
||||||
lock.unlockWrite(stamp);
|
|
||||||
}
|
|
||||||
if (null != co) {
|
|
||||||
onRemove(co.key, co.obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
final long stamp = lock.writeLock();
|
|
||||||
try {
|
|
||||||
cacheMap.clear();
|
|
||||||
} finally {
|
|
||||||
lock.unlockWrite(stamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取值,使用乐观锁,但是此方法可能导致读取脏数据,但对于缓存业务可容忍。情况如下:
|
|
||||||
* <pre>
|
|
||||||
* 1. 读取时无写入,不冲突,直接获取值
|
|
||||||
* 2. 读取时无写入,但是乐观读时触发了并发异常,此时获取同步锁,获取新值
|
|
||||||
* 3. 读取时有写入,此时获取同步锁,获取新值
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param key 键
|
|
||||||
* @param isUpdateLastAccess 是否更新最后修改时间
|
|
||||||
* @param isUpdateCount 是否更新命中数,get时更新,contains时不更新
|
|
||||||
* @return 值或null
|
|
||||||
*/
|
|
||||||
private V doGet(final K key, final boolean isUpdateLastAccess, final boolean isUpdateCount) {
|
|
||||||
// 尝试读取缓存,使用乐观读锁
|
|
||||||
CacheObj<K, V> co = null;
|
|
||||||
long stamp = lock.tryOptimisticRead();
|
|
||||||
boolean isReadError = true;
|
|
||||||
if(lock.validate(stamp)){
|
|
||||||
try{
|
|
||||||
// 乐观读,可能读取脏数据,在缓存中可容忍,分两种情况
|
|
||||||
// 1. 读取时无线程写入
|
|
||||||
// 2. 读取时有线程写入,导致数据不一致,此时读取未更新的缓存值
|
|
||||||
co = getWithoutLock(key);
|
|
||||||
isReadError = false;
|
|
||||||
} catch (final Exception ignore){
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isReadError){
|
|
||||||
// 转换为悲观读
|
|
||||||
// 原因可能为无锁读时触发并发异常,或者锁被占(正在写)
|
|
||||||
stamp = lock.readLock();
|
|
||||||
try {
|
|
||||||
co = getWithoutLock(key);
|
|
||||||
} finally {
|
|
||||||
lock.unlockRead(stamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未命中
|
|
||||||
if (null == co) {
|
|
||||||
if (isUpdateCount) {
|
|
||||||
missCount.increment();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} else if (!co.isExpired()) {
|
|
||||||
if (isUpdateCount) {
|
|
||||||
hitCount.increment();
|
|
||||||
}
|
|
||||||
return co.get(isUpdateLastAccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 悲观锁,二次检查
|
|
||||||
return getOrRemoveExpired(key, isUpdateCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步获取值,如果过期则移除之
|
|
||||||
*
|
|
||||||
* @param key 键
|
|
||||||
* @param isUpdateCount 是否更新命中数,get时更新,contains时不更新
|
|
||||||
* @return 有效值或null
|
|
||||||
*/
|
|
||||||
private V getOrRemoveExpired(final K key, final boolean isUpdateCount) {
|
|
||||||
final long stamp = lock.writeLock();
|
|
||||||
CacheObj<K, V> co;
|
|
||||||
try {
|
|
||||||
co = getWithoutLock(key);
|
|
||||||
if (null == co) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!co.isExpired()) {
|
|
||||||
// 首先尝试获取值,如果值存在且有效,返回之
|
|
||||||
if (isUpdateCount) {
|
|
||||||
hitCount.increment();
|
|
||||||
}
|
|
||||||
return co.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 无效移除
|
|
||||||
co = removeWithoutLock(key);
|
|
||||||
if (isUpdateCount) {
|
|
||||||
missCount.increment();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlockWrite(stamp);
|
|
||||||
}
|
|
||||||
if (null != co) {
|
|
||||||
onRemove(co.key, co.obj);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,9 +19,15 @@ package org.dromara.hutool.core.cache.impl;
|
|||||||
import org.dromara.hutool.core.cache.GlobalPruneTimer;
|
import org.dromara.hutool.core.cache.GlobalPruneTimer;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.core.lang.mutable.Mutable;
|
import org.dromara.hutool.core.lang.mutable.Mutable;
|
||||||
|
import org.dromara.hutool.core.thread.lock.NoLock;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时缓存<br>
|
* 定时缓存<br>
|
||||||
@ -33,7 +39,7 @@ import java.util.concurrent.ScheduledFuture;
|
|||||||
* @param <K> 键类型
|
* @param <K> 键类型
|
||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
*/
|
*/
|
||||||
public class TimedCache<K, V> extends StampedCache<K, V> {
|
public class TimedCache<K, V> extends LockedCache<K, V> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** 正在执行的定时任务 */
|
/** 正在执行的定时任务 */
|
||||||
@ -57,6 +63,8 @@ public class TimedCache<K, V> extends StampedCache<K, V> {
|
|||||||
public TimedCache(final long timeout, final Map<Mutable<K>, CacheObj<K, V>> map) {
|
public TimedCache(final long timeout, final Map<Mutable<K>, CacheObj<K, V>> map) {
|
||||||
this.capacity = 0;
|
this.capacity = 0;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
|
// 如果使用线程安全的Map,则不加锁,否则默认使用ReentrantLock
|
||||||
|
this.lock = map instanceof ConcurrentMap ? NoLock.INSTANCE : new ReentrantLock();
|
||||||
this.cacheMap = Assert.isNotInstanceOf(LinkedHashMap.class, map);
|
this.cacheMap = Assert.isNotInstanceOf(LinkedHashMap.class, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import java.util.concurrent.ScheduledFuture;
|
|||||||
* @param <K> 键类型
|
* @param <K> 键类型
|
||||||
* @param <V> 值类型
|
* @param <V> 值类型
|
||||||
*/
|
*/
|
||||||
public class TimedReentrantCache<K, V> extends ReentrantCache<K, V> {
|
public class TimedReentrantCache<K, V> extends LockedCache<K, V> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** 正在执行的定时任务 */
|
/** 正在执行的定时任务 */
|
||||||
|
@ -22,8 +22,6 @@ import org.dromara.hutool.core.lang.mutable.Mutable;
|
|||||||
import org.dromara.hutool.core.lang.ref.Ref;
|
import org.dromara.hutool.core.lang.ref.Ref;
|
||||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||||
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弱引用缓存<br>
|
* 弱引用缓存<br>
|
||||||
* 对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。<br>
|
* 对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。<br>
|
||||||
@ -44,7 +42,7 @@ public class WeakCache<K, V> extends TimedCache<K, V>{
|
|||||||
* @param timeout 超时时常,单位毫秒,-1或0表示无限制
|
* @param timeout 超时时常,单位毫秒,-1或0表示无限制
|
||||||
*/
|
*/
|
||||||
public WeakCache(final long timeout) {
|
public WeakCache(final long timeout) {
|
||||||
super(timeout, new WeakHashMap<>());
|
super(timeout, new WeakConcurrentMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
<jetty.version>9.4.56.v20240826</jetty.version>
|
<jetty.version>9.4.56.v20240826</jetty.version>
|
||||||
<!-- 固定 9.x支持到JDK8 -->
|
<!-- 固定 9.x支持到JDK8 -->
|
||||||
<tomcat.version>9.0.97</tomcat.version>
|
<tomcat.version>9.0.97</tomcat.version>
|
||||||
|
<smartboot.version>1.4.3</smartboot.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -131,6 +132,12 @@
|
|||||||
<version>${tomcat.version}</version>
|
<version>${tomcat.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.smartboot.http</groupId>
|
||||||
|
<artifactId>smart-http-server</artifactId>
|
||||||
|
<version>${smartboot.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 仅用于测试 -->
|
<!-- 仅用于测试 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.dromara.hutool.http.server.engine.smart;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.io.IORuntimeException;
|
||||||
|
import org.dromara.hutool.http.server.handler.ServerRequest;
|
||||||
|
import org.smartboot.http.server.HttpRequest;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SmartHttp请求对象
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class SmartHttpRequest implements ServerRequest {
|
||||||
|
|
||||||
|
private final HttpRequest request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param request 请求对象
|
||||||
|
*/
|
||||||
|
public SmartHttpRequest(final HttpRequest request) {
|
||||||
|
this.request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod() {
|
||||||
|
return request.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPath() {
|
||||||
|
return request.getRequestURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getQuery() {
|
||||||
|
return request.getQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeader(final String name) {
|
||||||
|
return request.getHeader(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有Header名称
|
||||||
|
*
|
||||||
|
* @return 所有Header名称
|
||||||
|
*/
|
||||||
|
public Collection<String> getHeaderNames() {
|
||||||
|
return request.getHeaderNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getBodyStream() {
|
||||||
|
try {
|
||||||
|
return request.getInputStream();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new IORuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.dromara.hutool.http.server.engine.smart;
|
||||||
|
|
||||||
|
import org.dromara.hutool.http.server.handler.ServerResponse;
|
||||||
|
import org.smartboot.http.common.enums.HttpStatus;
|
||||||
|
import org.smartboot.http.server.HttpResponse;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SmartHttp响应对象
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class SmartHttpResponse implements ServerResponse {
|
||||||
|
|
||||||
|
private final HttpResponse response;
|
||||||
|
private Charset charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param response 响应对象
|
||||||
|
*/
|
||||||
|
public SmartHttpResponse(final HttpResponse response) {
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmartHttpResponse setStatus(final int statusCode) {
|
||||||
|
response.setHttpStatus(HttpStatus.valueOf(statusCode));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmartHttpResponse setCharset(final Charset charset) {
|
||||||
|
this.charset = charset;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Charset getCharset() {
|
||||||
|
return this.charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmartHttpResponse addHeader(final String header, final String value) {
|
||||||
|
this.response.addHeader(header, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmartHttpResponse setHeader(final String header, final String value) {
|
||||||
|
this.response.setHeader(header, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
return this.response.getOutputStream();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.dromara.hutool.http.server.engine.smart;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
import org.dromara.hutool.http.HttpException;
|
||||||
|
import org.dromara.hutool.http.server.ServerConfig;
|
||||||
|
import org.dromara.hutool.http.server.engine.AbstractServerEngine;
|
||||||
|
import org.smartboot.http.server.*;
|
||||||
|
import org.smartboot.http.server.impl.Request;
|
||||||
|
import org.smartboot.socket.extension.plugins.SslPlugin;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smart-http-server引擎
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class SmartHttpServerEngine extends AbstractServerEngine {
|
||||||
|
|
||||||
|
private HttpBootstrap bootstrap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*/
|
||||||
|
public SmartHttpServerEngine() {
|
||||||
|
// issue#IABWBL JDK8下,在IDEA旗舰版加载Spring boot插件时,启动应用不会检查字段类是否存在
|
||||||
|
// 此处构造时调用下这个类,以便触发类是否存在的检查
|
||||||
|
Assert.notNull(HttpBootstrap.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
initEngine();
|
||||||
|
bootstrap.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpBootstrap getRawEngine() {
|
||||||
|
return this.bootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reset() {
|
||||||
|
if(null != this.bootstrap){
|
||||||
|
this.bootstrap.shutdown();
|
||||||
|
this.bootstrap = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initEngine() {
|
||||||
|
if (null != this.bootstrap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final HttpBootstrap bootstrap = new HttpBootstrap();
|
||||||
|
final HttpServerConfiguration configuration = bootstrap.configuration();
|
||||||
|
|
||||||
|
final ServerConfig config = this.config;
|
||||||
|
configuration.host(config.getHost());
|
||||||
|
|
||||||
|
// SSL
|
||||||
|
final SSLContext sslContext = config.getSslContext();
|
||||||
|
if(null != sslContext){
|
||||||
|
final SslPlugin<Request> sslPlugin;
|
||||||
|
try {
|
||||||
|
sslPlugin = new SslPlugin<>(() -> sslContext);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new HttpException(e);
|
||||||
|
}
|
||||||
|
configuration.addPlugin(sslPlugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选项
|
||||||
|
final int coreThreads = config.getCoreThreads();
|
||||||
|
if(coreThreads > 0){
|
||||||
|
configuration.threadNum(coreThreads);
|
||||||
|
}
|
||||||
|
|
||||||
|
final long idleTimeout = config.getIdleTimeout();
|
||||||
|
if(idleTimeout > 0){
|
||||||
|
configuration.setHttpIdleTimeout((int) idleTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap.httpHandler(new HttpServerHandler() {
|
||||||
|
@Override
|
||||||
|
public void handle(final HttpRequest request, final HttpResponse response) {
|
||||||
|
handler.handle(new SmartHttpRequest(request), new SmartHttpResponse(response));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bootstrap.setPort(config.getPort());
|
||||||
|
this.bootstrap = bootstrap;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smart-http-server服务器引擎实现<br>
|
||||||
|
* 见:https://smartboot.tech/smart-http/
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
package org.dromara.hutool.http.server.engine.smart;
|
@ -17,4 +17,5 @@
|
|||||||
org.dromara.hutool.http.server.engine.undertow.UndertowEngine
|
org.dromara.hutool.http.server.engine.undertow.UndertowEngine
|
||||||
org.dromara.hutool.http.server.engine.tomcat.TomcatEngine
|
org.dromara.hutool.http.server.engine.tomcat.TomcatEngine
|
||||||
org.dromara.hutool.http.server.engine.jetty.JettyEngine
|
org.dromara.hutool.http.server.engine.jetty.JettyEngine
|
||||||
|
org.dromara.hutool.http.server.engine.smart.SmartHttpServerEngine
|
||||||
org.dromara.hutool.http.server.engine.sun.SunHttpServerEngine
|
org.dromara.hutool.http.server.engine.sun.SunHttpServerEngine
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package org.dromara.hutool.http.server.engine;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.io.file.FileUtil;
|
||||||
|
import org.dromara.hutool.core.lang.Console;
|
||||||
|
import org.dromara.hutool.core.net.ssl.SSLContextUtil;
|
||||||
|
import org.dromara.hutool.crypto.KeyStoreUtil;
|
||||||
|
import org.dromara.hutool.http.server.ServerConfig;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
|
||||||
|
public class SmartHttpServerTest {
|
||||||
|
public static void main(final String[] args) throws Exception {
|
||||||
|
final char[] pwd = "123456".toCharArray();
|
||||||
|
final KeyStore keyStore = KeyStoreUtil.readJKSKeyStore(FileUtil.file("d:/test/keystore.jks"), pwd);
|
||||||
|
// 初始化SSLContext
|
||||||
|
final SSLContext sslContext = SSLContextUtil.createSSLContext(keyStore, pwd);
|
||||||
|
|
||||||
|
final ServerEngine engine = ServerEngineFactory.createEngine("SmartHttpServer");
|
||||||
|
engine.init(ServerConfig.of().setSslContext(sslContext));
|
||||||
|
engine.setHandler((request, response) -> {
|
||||||
|
Console.log(request.getPath());
|
||||||
|
response.write("Hutool Smart-Http response test");
|
||||||
|
});
|
||||||
|
engine.start();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user