Skip to content

Commit 4bc207f

Browse files
committed
增加InterceptorCleaner
1 parent 9f4785d commit 4bc207f

File tree

4 files changed

+153
-130
lines changed

4 files changed

+153
-130
lines changed

WebApiClient/HttpApiFactory.cs

Lines changed: 16 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
2-
using System.Collections.Concurrent;
32
using System.Net.Http;
43
using System.Threading;
5-
using System.Threading.Tasks;
64

75
namespace WebApiClient
86
{
@@ -30,32 +28,22 @@ public class HttpApiFactory<TInterface> : IHttpApiFactory<TInterface>, IHttpApiF
3028
private TimeSpan lifeTime = TimeSpan.FromMinutes(2d);
3129

3230
/// <summary>
33-
/// 清理handler时间间隔
31+
/// 具有生命周期的拦截器延时创建对象
3432
/// </summary>
35-
private TimeSpan cleanupInterval = TimeSpan.FromSeconds(10d);
33+
private Lazy<LifetimeInterceptor> lifeTimeInterceptorLazy;
3634

3735
/// <summary>
38-
/// 过期的拦截器
36+
/// 拦截器清理器
3937
/// </summary>
40-
private readonly ConcurrentQueue<ExpiredInterceptor> expiredInterceptors = new ConcurrentQueue<ExpiredInterceptor>();
41-
42-
/// <summary>
43-
/// 当前过期的拦截器的数量
44-
/// </summary>
45-
private int expiredCount = 0;
46-
47-
/// <summary>
48-
/// 激活的拦截器
49-
/// </summary>
50-
private Lazy<ActiveInterceptor> activeInterceptorLazy;
38+
private readonly InterceptorCleaner interceptorCleaner = new InterceptorCleaner();
5139

5240
/// <summary>
5341
/// HttpApi创建工厂
5442
/// </summary>
5543
public HttpApiFactory()
5644
{
57-
this.activeInterceptorLazy = new Lazy<ActiveInterceptor>(
58-
this.CreateActiveInterceptor,
45+
this.lifeTimeInterceptorLazy = new Lazy<LifetimeInterceptor>(
46+
this.CreateInterceptor,
5947
LazyThreadSafetyMode.ExecutionAndPublication);
6048
}
6149

@@ -85,7 +73,7 @@ public HttpApiFactory<TInterface> SetCleanupInterval(TimeSpan interval)
8573
{
8674
throw new ArgumentOutOfRangeException();
8775
}
88-
this.cleanupInterval = interval;
76+
this.interceptorCleaner.CleanupInterval = interval;
8977
return this;
9078
}
9179

@@ -126,15 +114,15 @@ public TInterface CreateHttpApi()
126114
/// <returns></returns>
127115
object IHttpApiFactory.CreateHttpApi()
128116
{
129-
var interceptor = this.activeInterceptorLazy.Value;
117+
var interceptor = this.lifeTimeInterceptorLazy.Value;
130118
return HttpApiClient.Create(typeof(TInterface), interceptor);
131119
}
132120

133121
/// <summary>
134-
/// 创建激活状态的拦截器
122+
/// 创建LifetimeInterceptor
135123
/// </summary>
136124
/// <returns></returns>
137-
private ActiveInterceptor CreateActiveInterceptor()
125+
private LifetimeInterceptor CreateInterceptor()
138126
{
139127
var handler = this.handlerFunc?.Invoke() ?? new DefaultHttpClientHandler();
140128
var httpApiConfig = new HttpApiConfig(handler, true);
@@ -144,7 +132,7 @@ private ActiveInterceptor CreateActiveInterceptor()
144132
this.configAction.Invoke(httpApiConfig);
145133
}
146134

147-
return new ActiveInterceptor(
135+
return new LifetimeInterceptor(
148136
httpApiConfig,
149137
this.lifeTime,
150138
this.OnInterceptorDeactivate);
@@ -153,61 +141,15 @@ private ActiveInterceptor CreateActiveInterceptor()
153141
/// <summary>
154142
/// 当有拦截器失效时
155143
/// </summary>
156-
/// <param name="active">激活的拦截器</param>
157-
private void OnInterceptorDeactivate(ActiveInterceptor active)
144+
/// <param name="interceptor">拦截器</param>
145+
private void OnInterceptorDeactivate(LifetimeInterceptor interceptor)
158146
{
159147
// 切换激活状态的记录的实例
160-
this.activeInterceptorLazy = new Lazy<ActiveInterceptor>(
161-
this.CreateActiveInterceptor,
148+
this.lifeTimeInterceptorLazy = new Lazy<LifetimeInterceptor>(
149+
this.CreateInterceptor,
162150
LazyThreadSafetyMode.ExecutionAndPublication);
163151

164-
var expired = new ExpiredInterceptor(active);
165-
this.expiredInterceptors.Enqueue(expired);
166-
167-
// 从0变为1,要启动清理作业
168-
if (Interlocked.Increment(ref this.expiredCount) == 1)
169-
{
170-
this.RegisteCleanup();
171-
}
172-
}
173-
174-
175-
/// <summary>
176-
/// 注册清理任务
177-
/// </summary>
178-
private async void RegisteCleanup()
179-
{
180-
while (this.Cleanup() == false)
181-
{
182-
await Task.Delay(this.cleanupInterval).ConfigureAwait(false);
183-
}
184-
}
185-
186-
/// <summary>
187-
/// 清理失效的拦截器
188-
/// </summary>
189-
/// <returns>是否完全清理</returns>
190-
private bool Cleanup()
191-
{
192-
var cleanCount = this.expiredInterceptors.Count;
193-
for (var i = 0; i < cleanCount; i++)
194-
{
195-
this.expiredInterceptors.TryDequeue(out var expired);
196-
if (expired.CanDispose == false)
197-
{
198-
this.expiredInterceptors.Enqueue(expired);
199-
}
200-
else
201-
{
202-
expired.Dispose();
203-
if (Interlocked.Decrement(ref this.expiredCount) == 0)
204-
{
205-
return true;
206-
}
207-
}
208-
}
209-
210-
return false;
152+
this.interceptorCleaner.Add(interceptor);
211153
}
212154
}
213155
}

WebApiClient/Internal/HttpApiFactories/ExpiredInterceptor..cs

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace WebApiClient
7+
{
8+
/// <summary>
9+
/// 表示拦截器清理器
10+
/// </summary>
11+
class InterceptorCleaner
12+
{
13+
/// <summary>
14+
/// 当前监视生命周期的记录的数量
15+
/// </summary>
16+
private int trackingEntryCount = 0;
17+
18+
/// <summary>
19+
/// 监视生命周期的记录队列
20+
/// </summary>
21+
private readonly ConcurrentQueue<TrackingEntry> trackingEntries = new ConcurrentQueue<TrackingEntry>();
22+
23+
/// <summary>
24+
/// 获取或设置清理的时间间隔
25+
/// 默认10s
26+
/// </summary>
27+
public TimeSpan CleanupInterval { get; set; } = TimeSpan.FromSeconds(10d);
28+
29+
/// <summary>
30+
/// 添加要清除的拦截器
31+
/// </summary>
32+
/// <param name="interceptor">拦截器</param>
33+
public void Add(LifetimeInterceptor interceptor)
34+
{
35+
var entry = new TrackingEntry(interceptor);
36+
this.trackingEntries.Enqueue(entry);
37+
38+
// 从0变为1,要启动清理作业
39+
if (Interlocked.Increment(ref this.trackingEntryCount) == 1)
40+
{
41+
this.StartCleanup();
42+
}
43+
}
44+
45+
/// <summary>
46+
/// 启动清理作业
47+
/// </summary>
48+
private async void StartCleanup()
49+
{
50+
while (this.Cleanup() == false)
51+
{
52+
await Task.Delay(this.CleanupInterval).ConfigureAwait(false);
53+
}
54+
}
55+
56+
/// <summary>
57+
/// 清理失效的拦截器
58+
/// 返回是否完全清理
59+
/// </summary>
60+
/// <returns></returns>
61+
private bool Cleanup()
62+
{
63+
var cleanCount = this.trackingEntries.Count;
64+
for (var i = 0; i < cleanCount; i++)
65+
{
66+
this.trackingEntries.TryDequeue(out var entry);
67+
if (entry.CanDispose == false)
68+
{
69+
this.trackingEntries.Enqueue(entry);
70+
}
71+
else
72+
{
73+
entry.Dispose();
74+
if (Interlocked.Decrement(ref this.trackingEntryCount) == 0)
75+
{
76+
return true;
77+
}
78+
}
79+
}
80+
81+
return false;
82+
}
83+
84+
85+
/// <summary>
86+
/// 表示监视生命周期的记录
87+
/// </summary>
88+
private class TrackingEntry : IDisposable
89+
{
90+
/// <summary>
91+
/// 用于释放资源的对象
92+
/// </summary>
93+
private readonly IDisposable disposable;
94+
95+
/// <summary>
96+
/// 监视对象的弱引用
97+
/// </summary>
98+
private readonly WeakReference weakReference;
99+
100+
/// <summary>
101+
/// 获取是否可以释放资源
102+
/// </summary>
103+
/// <returns></returns>
104+
public bool CanDispose
105+
{
106+
get => this.weakReference.IsAlive == false;
107+
}
108+
109+
/// <summary>
110+
/// 监视生命周期的记录
111+
/// </summary>
112+
/// <param name="interceptor">激活状态的拦截器</param>
113+
public TrackingEntry(LifetimeInterceptor interceptor)
114+
{
115+
this.disposable = interceptor.HttpApiConfig;
116+
this.weakReference = new WeakReference(interceptor);
117+
}
118+
119+
/// <summary>
120+
/// 释放资源
121+
/// </summary>
122+
public void Dispose()
123+
{
124+
if (this.CanDispose == true)
125+
{
126+
this.disposable.Dispose();
127+
}
128+
}
129+
}
130+
}
131+
}

WebApiClient/Internal/HttpApiFactories/ActiveInterceptor.cs renamed to WebApiClient/Internal/HttpApiFactories/LifetimeInterceptor.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
namespace WebApiClient
66
{
77
/// <summary>
8-
/// 表示激活状态的拦截器
8+
/// 表示具有生命周期的拦截器
99
/// </summary>
10-
class ActiveInterceptor : ApiInterceptor
10+
class LifetimeInterceptor : ApiInterceptor
1111
{
1212
/// <summary>
13-
/// 激活状态的拦截器
13+
/// 具有生命周期的拦截器
1414
/// </summary>
1515
/// <param name="httpApiConfig">httpApi配置</param>
16-
/// <param name="lifeTime">生命周期</param>
17-
/// <param name="deactivateAction">生效委托</param>
16+
/// <param name="lifeTime">拦截器的生命周期</param>
17+
/// <param name="deactivateAction">失效回调</param>
1818
/// <exception cref="ArgumentNullException"></exception>
19-
public ActiveInterceptor(HttpApiConfig httpApiConfig, TimeSpan lifeTime, Action<ActiveInterceptor> deactivateAction)
19+
public LifetimeInterceptor(HttpApiConfig httpApiConfig, TimeSpan lifeTime, Action<LifetimeInterceptor> deactivateAction)
2020
: base(httpApiConfig)
2121
{
2222
if (deactivateAction == null)

0 commit comments

Comments
 (0)