needle 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/manual-html/chapter-1.html +138 -78
- data/doc/manual-html/chapter-2.html +180 -99
- data/doc/manual-html/chapter-3.html +111 -75
- data/doc/manual-html/chapter-4.html +80 -48
- data/doc/manual-html/chapter-5.html +106 -56
- data/doc/manual-html/chapter-6.html +82 -34
- data/doc/manual-html/chapter-7.html +74 -38
- data/doc/manual-html/chapter-8.html +70 -41
- data/doc/manual-html/chapter-9.html +88 -63
- data/doc/manual-html/index.html +6 -6
- data/doc/manual-html/needle.png +0 -0
- data/doc/manual-html/{manual.css → stylesheets/manual.css} +83 -10
- data/doc/manual-html/stylesheets/ruby.css +17 -0
- data/doc/manual/chapter.erb +20 -0
- data/doc/manual/img/Needle.ai +0 -0
- data/doc/manual/img/needle.png +0 -0
- data/doc/manual/manual.rb +80 -5
- data/doc/manual/manual.yml +3 -3
- data/doc/manual/page.erb +1 -1
- data/doc/manual/parts/01_use_cases.txt +70 -70
- data/doc/manual/parts/02_creating.txt +19 -19
- data/doc/manual/parts/02_namespaces.txt +29 -29
- data/doc/manual/parts/02_services.txt +40 -41
- data/doc/manual/parts/03_conventional.txt +20 -20
- data/doc/manual/parts/03_locator.txt +44 -44
- data/doc/manual/parts/04_overview.txt +1 -1
- data/doc/manual/parts/04_setup.txt +32 -32
- data/doc/manual/parts/customizing_contexts.txt +14 -14
- data/doc/manual/parts/customizing_interceptors.txt +25 -25
- data/doc/manual/parts/customizing_namespaces.txt +12 -12
- data/doc/manual/parts/interceptors_attaching.txt +29 -30
- data/doc/manual/parts/interceptors_custom.txt +16 -16
- data/doc/manual/parts/interceptors_ordering.txt +5 -5
- data/doc/manual/parts/libraries_creating.txt +18 -18
- data/doc/manual/parts/libraries_using.txt +19 -19
- data/doc/manual/parts/logging_configuration.txt +13 -13
- data/doc/manual/parts/logging_logfactory.txt +21 -22
- data/doc/manual/parts/models_models.txt +8 -8
- data/doc/manual/parts/models_overview.txt +1 -1
- data/doc/manual/parts/models_pipelines.txt +22 -22
- data/doc/manual/{manual.css → stylesheets/manual.css} +83 -10
- data/doc/manual/stylesheets/ruby.css +17 -0
- data/lib/needle/definition-context.rb +3 -2
- data/lib/needle/lifecycle/proxy.rb +1 -1
- data/lib/needle/version.rb +1 -1
- metadata +94 -85
@@ -1,7 +1,7 @@
|
|
1
1
|
<html>
|
2
2
|
<head>
|
3
3
|
<title>Needle Manual :: Chapter 3: Service Locator</title>
|
4
|
-
<link type="text/css" rel="stylesheet" href="manual.css" />
|
4
|
+
<link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
|
5
5
|
</head>
|
6
6
|
|
7
7
|
<body>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.2.
|
18
|
-
Manual Last Updated: <strong>
|
17
|
+
Needle Version: <strong>1.2.1</strong><br />
|
18
|
+
Manual Last Updated: <strong>2005-07-27 05:49 UTC</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -208,7 +208,17 @@
|
|
208
208
|
|
209
209
|
<div id="content">
|
210
210
|
|
211
|
-
|
211
|
+
<div class="top"><div class="prevnext">
|
212
|
+
|
213
|
+
<a href="chapter-2.html">Previous (2. Registry)</a> |
|
214
|
+
|
215
|
+
<a href="index.html">Up</a>
|
216
|
+
|
217
|
+
| <a href="chapter-4.html">Next (4. Dependency Injection)</a>
|
218
|
+
|
219
|
+
</div></div>
|
220
|
+
|
221
|
+
<h1>3. Service Locator</h1>
|
212
222
|
|
213
223
|
|
214
224
|
|
@@ -222,7 +232,10 @@
|
|
222
232
|
<div class="section">
|
223
233
|
<p>The <em>service locator</em> design pattern can be considered a subset of dependency injection. Because it is simpler, it is as good of a place to start teaching DI as any.</p>
|
224
234
|
|
235
|
+
|
225
236
|
<p>To demonstrate both techniques, we’ll pretend we’re going to write an online forum application. To start, let’s come up with a rough design by cataloging the components we’ll need.</p>
|
237
|
+
|
238
|
+
|
226
239
|
<ul>
|
227
240
|
<li><code>Logger</code>. This will be used to write messages to a file.</li>
|
228
241
|
<li><code>Authenticator</code>. This will be used to validate whether a user is who they say they are.</li>
|
@@ -232,9 +245,13 @@
|
|
232
245
|
<li><code>Application</code>. The controller that ties it all together.</li>
|
233
246
|
</ul>
|
234
247
|
|
248
|
+
|
235
249
|
<p>(Of course, a <em>real</em> online forum application would be significantly more complex, but the above components will do for our purposes.)</p>
|
236
250
|
|
251
|
+
|
237
252
|
<p>The dependencies between these components are:</p>
|
253
|
+
|
254
|
+
|
238
255
|
<ul>
|
239
256
|
<li><code>Authenticator</code> <em>has</em> <code>Database</code> (for querying user authentication information) and <code>Logger</code></li>
|
240
257
|
<li><code>Database</code> <em>has</em> <code>Logger</code> (for indicating database accesses and query times)</li>
|
@@ -256,31 +273,35 @@
|
|
256
273
|
<p>A conventional architecture will have each component instantiate its own dependencies. For example, the <code>Application</code> would do something like this:</p>
|
257
274
|
|
258
275
|
|
259
|
-
<
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
</pre>
|
276
|
+
<div class='figure'>
|
277
|
+
<span class='caption'>A conventional application implementation [ruby]</span>
|
278
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">class </span><span class="class">Application</span>
|
279
|
+
<span class="keyword">def </span><span class="method">initialize</span>
|
280
|
+
<span class="attribute">@logger</span> <span class="punct">=</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span>
|
281
|
+
<span class="attribute">@authenticator</span> <span class="punct">=</span> <span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span>
|
282
|
+
<span class="attribute">@database</span> <span class="punct">=</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span>
|
283
|
+
<span class="attribute">@view</span> <span class="punct">=</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span>
|
284
|
+
<span class="attribute">@session</span> <span class="punct">=</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span>
|
285
|
+
<span class="keyword">end</span>
|
286
|
+
<span class="keyword">end</span></pre></div></td></tr></table></div></div>
|
287
|
+
|
288
|
+
|
270
289
|
<p>However, the above is already flawed, because the <code>Authenticator</code> and the <code>Session</code> both need access to the <code>Database</code>, so you really need to make sure you instantiate things in the right order and pass them as parameters to the constructor of each object that needs them, like so:</p>
|
271
290
|
|
272
291
|
|
273
|
-
<
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
end
|
283
|
-
</pre>
|
292
|
+
<div class='figure'>
|
293
|
+
<span class='caption'>A parameterized application implementation [ruby]</span>
|
294
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">class </span><span class="class">Application</span>
|
295
|
+
<span class="keyword">def </span><span class="method">initialize</span>
|
296
|
+
<span class="attribute">@view</span> <span class="punct">=</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span>
|
297
|
+
<span class="attribute">@logger</span> <span class="punct">=</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span>
|
298
|
+
<span class="attribute">@database</span> <span class="punct">=</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@logger</span> <span class="punct">)</span>
|
299
|
+
<span class="attribute">@authenticator</span> <span class="punct">=</span> <span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@logger</span><span class="punct">,</span> <span class="attribute">@database</span> <span class="punct">)</span>
|
300
|
+
<span class="attribute">@session</span> <span class="punct">=</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@logger</span><span class="punct">,</span> <span class="attribute">@database</span> <span class="punct">)</span>
|
301
|
+
<span class="keyword">end</span>
|
302
|
+
<span class="keyword">end</span></pre></div></td></tr></table></div></div>
|
303
|
+
|
304
|
+
|
284
305
|
<p>The problem with this is that if you later decide that <code>View</code> needs to access the database, you need to rearrange the order of how things are instantiated in the <code>Application</code> constructor.</p>
|
285
306
|
</div>
|
286
307
|
|
@@ -297,68 +318,83 @@
|
|
297
318
|
<p>The <em>service locator</em> pattern makes things a <em>little</em> easier. Instead of instantiating everything in the constructor of the <code>Application</code>, you can create a factory method somewhere that returns the new <code>Application</code> instance. Then, inside of this factory method, you assign each new object to collection, and pass that collection to each constructor.</p>
|
298
319
|
|
299
320
|
|
300
|
-
<
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
end
|
332
|
-
|
333
|
-
|
334
|
-
|
321
|
+
<div class='figure'>
|
322
|
+
<span class='caption'>Service locator example [ruby]</span>
|
323
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">require</span> <span class="punct">'</span><span class="string">needle</span><span class="punct">'</span>
|
324
|
+
|
325
|
+
<span class="keyword">def </span><span class="method">create_application</span>
|
326
|
+
<span class="ident">locator</span> <span class="punct">=</span> <span class="constant">Needle</span><span class="punct">::</span><span class="constant">Registry</span><span class="punct">.</span><span class="ident">new</span>
|
327
|
+
|
328
|
+
<span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:view</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
329
|
+
<span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:logger</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
330
|
+
<span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:database</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
331
|
+
<span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:authenticator</span> <span class="punct">)</span> <span class="punct">{</span><span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
332
|
+
<span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:session</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
333
|
+
<span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:app</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Application</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
334
|
+
|
335
|
+
<span class="ident">locator</span><span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span>
|
336
|
+
<span class="keyword">end</span>
|
337
|
+
|
338
|
+
<span class="keyword">class </span><span class="class">Application</span>
|
339
|
+
<span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">locator</span> <span class="punct">)</span>
|
340
|
+
<span class="attribute">@view</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:view</span><span class="punct">]</span>
|
341
|
+
<span class="attribute">@logger</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:logger</span><span class="punct">]</span>
|
342
|
+
<span class="attribute">@database</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:database</span><span class="punct">]</span>
|
343
|
+
<span class="attribute">@authenticator</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:authenticator</span><span class="punct">]</span>
|
344
|
+
<span class="attribute">@session</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:session</span><span class="punct">]</span>
|
345
|
+
<span class="keyword">end</span>
|
346
|
+
<span class="keyword">end</span>
|
347
|
+
|
348
|
+
<span class="keyword">class </span><span class="class">Session</span>
|
349
|
+
<span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">locator</span> <span class="punct">)</span>
|
350
|
+
<span class="attribute">@database</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:database</span><span class="punct">]</span>
|
351
|
+
<span class="attribute">@logger</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:logger</span><span class="punct">]</span>
|
352
|
+
<span class="keyword">end</span>
|
353
|
+
<span class="keyword">end</span>
|
354
|
+
|
355
|
+
<span class="punct">...</span></pre></div></td></tr></table></div></div>
|
356
|
+
|
357
|
+
|
335
358
|
<p>This has the benefit of allowing each object to construct itself <em>� la carte</em> from the objects in the locator. Also, each object no longer cares what class implements each service—it only cares that each object implements the methods it will attempt to invoke on that object.</p>
|
336
359
|
|
360
|
+
|
337
361
|
<p>Also, because Needle defers the instantiation of each service until the service is actually requested, we can actually register each item with the locator in any arbitrary order. All that is happening is the block is associated with the symbol, so that when the service is requested, the corresponding block is invoked. What is more, by default each service is then cached, so that it is only instantiated once.</p>
|
338
362
|
|
363
|
+
|
339
364
|
<p>Thus, when we get the <code>:app</code> service (on the last line), the <code>Application</code> constructor is invoked, passing the locator to the constructor. Inside the constructor, <code>Application</code> retrieves each of its dependencies from the locator, causing each of them to be instantiated in turn. By this means, everything is initialized and constructed when the <code>create_application</code> method returns.</p>
|
340
365
|
|
366
|
+
|
341
367
|
<p>In the interest of brevity, the <code>create_application</code> could have been written like this, using a “builder” object (called <code>b</code> in the example below) to help register the services:</p>
|
342
368
|
|
343
369
|
|
344
|
-
<
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
</pre>
|
370
|
+
<div class='figure'>
|
371
|
+
<span class='caption'>Service locator example using #define [ruby]</span>
|
372
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">def </span><span class="method">create_application</span>
|
373
|
+
<span class="ident">locator</span> <span class="punct">=</span> <span class="constant">Needle</span><span class="punct">::</span><span class="constant">Registry</span><span class="punct">.</span><span class="ident">define</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">b</span><span class="punct">|</span>
|
374
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">view</span> <span class="punct">{</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
375
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">{</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
376
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">database</span> <span class="punct">{</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
377
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">authenticator</span> <span class="punct">{</span><span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
378
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">session</span> <span class="punct">{</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
379
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">app</span> <span class="punct">{</span> <span class="constant">Application</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
|
380
|
+
<span class="keyword">end</span>
|
381
|
+
|
382
|
+
<span class="ident">locator</span><span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span>
|
383
|
+
<span class="keyword">end</span></pre></div></td></tr></table></div></div>
|
358
384
|
</div>
|
359
385
|
|
360
386
|
|
361
387
|
|
388
|
+
<div class="bottom"><div class="prevnext">
|
389
|
+
|
390
|
+
<a href="chapter-2.html">Previous (2. Registry)</a> |
|
391
|
+
|
392
|
+
<a href="index.html">Up</a>
|
393
|
+
|
394
|
+
| <a href="chapter-4.html">Next (4. Dependency Injection)</a>
|
395
|
+
|
396
|
+
</div></div>
|
397
|
+
|
362
398
|
|
363
399
|
</div>
|
364
400
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<html>
|
2
2
|
<head>
|
3
3
|
<title>Needle Manual :: Chapter 4: Dependency Injection</title>
|
4
|
-
<link type="text/css" rel="stylesheet" href="manual.css" />
|
4
|
+
<link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
|
5
5
|
</head>
|
6
6
|
|
7
7
|
<body>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.2.
|
18
|
-
Manual Last Updated: <strong>
|
17
|
+
Needle Version: <strong>1.2.1</strong><br />
|
18
|
+
Manual Last Updated: <strong>2005-07-27 05:49 UTC</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -208,7 +208,17 @@
|
|
208
208
|
|
209
209
|
<div id="content">
|
210
210
|
|
211
|
-
|
211
|
+
<div class="top"><div class="prevnext">
|
212
|
+
|
213
|
+
<a href="chapter-3.html">Previous (3. Service Locator)</a> |
|
214
|
+
|
215
|
+
<a href="index.html">Up</a>
|
216
|
+
|
217
|
+
| <a href="chapter-5.html">Next (5. Interceptors)</a>
|
218
|
+
|
219
|
+
</div></div>
|
220
|
+
|
221
|
+
<h1>4. Dependency Injection</h1>
|
212
222
|
|
213
223
|
|
214
224
|
|
@@ -221,15 +231,24 @@
|
|
221
231
|
|
222
232
|
<div class="section">
|
223
233
|
<p>The service locator works well when there are few dependencies, and the dependency graph is not very deep. However, it has a few drawbacks:</p>
|
234
|
+
|
235
|
+
|
236
|
+
<ol>
|
237
|
+
<li>It requires each object to accept the locator as a parameter, and to know how to use it. This is problematic if you want to use existing classes that were created without knowledge of a locator. (I.e., <code>Logger</code>, in the Ruby library).</li>
|
238
|
+
</ol>
|
239
|
+
|
240
|
+
|
241
|
+
<ol>
|
242
|
+
<li>It requires each object to know what the services are named, in the locator. If you ever decide to change the name of a service in the locator, you may have to change lots of code to comply with the change.</li>
|
243
|
+
</ol>
|
244
|
+
|
245
|
+
|
224
246
|
<ol>
|
225
|
-
<li>
|
226
|
-
</li>
|
227
|
-
<li>It requires each object to know what the services are named, in the locator. If you ever decide to change the name of a service in the locator, you may have to change lots of code to comply with the change.
|
228
|
-
</li>
|
229
|
-
<li>For deep dependency graphs, it can become cumbersome to have to pass the locator to each constructor.</li>
|
247
|
+
<li>For deep dependency graphs, it can become cumbersome to have to pass the locator to each constructor.</li>
|
230
248
|
</ol>
|
231
249
|
|
232
|
-
|
250
|
+
|
251
|
+
<p>This is where <em>dependency injection</em> comes in. It allows you to define how each service is initialized, including setting dependencies (either via constructor parameters or via property accessors). In fact, it can do a lot more than that, even allowing you to specify how the lifestyle of the service should be managed and hooking “interceptors” onto the service to filter method invocations.</p>
|
233
252
|
</div>
|
234
253
|
|
235
254
|
|
@@ -245,51 +264,64 @@
|
|
245
264
|
<p>Setting up for DI is very similar to the setup for a service locator, but instead of passing the locator (we’ll call it a <em>registry</em> now), we only pass (or set) the dependencies that the service itself needs.</p>
|
246
265
|
|
247
266
|
|
248
|
-
<
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
end
|
283
|
-
|
284
|
-
|
285
|
-
|
267
|
+
<div class='figure'>
|
268
|
+
<span class='caption'>Dependency injection example [ruby]</span>
|
269
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">require</span> <span class="punct">'</span><span class="string">needle</span><span class="punct">'</span>
|
270
|
+
|
271
|
+
<span class="keyword">def </span><span class="method">create_application</span>
|
272
|
+
<span class="ident">registry</span> <span class="punct">=</span> <span class="constant">Needle</span><span class="punct">::</span><span class="constant">Registry</span><span class="punct">.</span><span class="ident">define</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">b</span><span class="punct">|</span>
|
273
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">view</span> <span class="punct">{</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span> <span class="punct">}</span>
|
274
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">{</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span> <span class="punct">}</span>
|
275
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">database</span> <span class="punct">{</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">)</span> <span class="punct">}</span>
|
276
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">authenticator</span> <span class="punct">{</span> <span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span><span class="punct">,</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span><span class="punct">)</span> <span class="punct">}</span>
|
277
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">session</span> <span class="punct">{</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span><span class="punct">,</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span><span class="punct">)</span> <span class="punct">}</span>
|
278
|
+
|
279
|
+
<span class="ident">b</span><span class="punct">.</span><span class="ident">app</span> <span class="keyword">do</span>
|
280
|
+
<span class="ident">app</span> <span class="punct">=</span> <span class="constant">Application</span><span class="punct">.</span><span class="ident">new</span>
|
281
|
+
<span class="ident">app</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span>
|
282
|
+
<span class="ident">app</span><span class="punct">.</span><span class="ident">view</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">view</span>
|
283
|
+
<span class="ident">app</span><span class="punct">.</span><span class="ident">database</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span>
|
284
|
+
<span class="ident">app</span><span class="punct">.</span><span class="ident">authenticator</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">authenticator</span>
|
285
|
+
<span class="ident">app</span><span class="punct">.</span><span class="ident">session</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">session</span>
|
286
|
+
<span class="ident">app</span>
|
287
|
+
<span class="keyword">end</span>
|
288
|
+
<span class="keyword">end</span>
|
289
|
+
|
290
|
+
<span class="ident">registry</span><span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span>
|
291
|
+
<span class="keyword">end</span>
|
292
|
+
|
293
|
+
<span class="keyword">class </span><span class="class">Application</span>
|
294
|
+
<span class="ident">attr_writer</span> <span class="symbol">:view</span><span class="punct">,</span> <span class="symbol">:logger</span><span class="punct">,</span> <span class="symbol">:database</span><span class="punct">,</span> <span class="symbol">:authenticator</span><span class="punct">,</span> <span class="symbol">:session</span>
|
295
|
+
<span class="keyword">end</span>
|
296
|
+
|
297
|
+
<span class="keyword">class </span><span class="class">Session</span>
|
298
|
+
<span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">logger</span><span class="punct">,</span> <span class="ident">database</span> <span class="punct">)</span>
|
299
|
+
<span class="attribute">@database</span> <span class="punct">=</span> <span class="ident">database</span>
|
300
|
+
<span class="attribute">@logger</span> <span class="punct">=</span> <span class="ident">logger</span>
|
301
|
+
<span class="keyword">end</span>
|
302
|
+
<span class="keyword">end</span>
|
303
|
+
|
304
|
+
<span class="punct">...</span></pre></div></td></tr></table></div></div>
|
305
|
+
|
306
|
+
|
286
307
|
<p>The <code>create_application</code> method is now (necessarily) a little more complex, since it now contains all of the initialization logic for each service in the application. However, look how much simpler this made the other classes, especially the <code>Application</code> class.</p>
|
287
308
|
|
309
|
+
|
288
310
|
<p>Now, each class no longer even needs to care that it is being initialized via another container. All it knows is that when it is created, it will be given each of its dependencies (either as constructor parameters or as property accessors).</p>
|
289
311
|
</div>
|
290
312
|
|
291
313
|
|
292
314
|
|
315
|
+
<div class="bottom"><div class="prevnext">
|
316
|
+
|
317
|
+
<a href="chapter-3.html">Previous (3. Service Locator)</a> |
|
318
|
+
|
319
|
+
<a href="index.html">Up</a>
|
320
|
+
|
321
|
+
| <a href="chapter-5.html">Next (5. Interceptors)</a>
|
322
|
+
|
323
|
+
</div></div>
|
324
|
+
|
293
325
|
|
294
326
|
</div>
|
295
327
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<html>
|
2
2
|
<head>
|
3
3
|
<title>Needle Manual :: Chapter 5: Interceptors</title>
|
4
|
-
<link type="text/css" rel="stylesheet" href="manual.css" />
|
4
|
+
<link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
|
5
5
|
</head>
|
6
6
|
|
7
7
|
<body>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.2.
|
18
|
-
Manual Last Updated: <strong>
|
17
|
+
Needle Version: <strong>1.2.1</strong><br />
|
18
|
+
Manual Last Updated: <strong>2005-07-27 05:49 UTC</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -208,7 +208,17 @@
|
|
208
208
|
|
209
209
|
<div id="content">
|
210
210
|
|
211
|
-
|
211
|
+
<div class="top"><div class="prevnext">
|
212
|
+
|
213
|
+
<a href="chapter-4.html">Previous (4. Dependency Injection)</a> |
|
214
|
+
|
215
|
+
<a href="index.html">Up</a>
|
216
|
+
|
217
|
+
| <a href="chapter-6.html">Next (6. Service Models)</a>
|
218
|
+
|
219
|
+
</div></div>
|
220
|
+
|
221
|
+
<h1>5. Interceptors</h1>
|
212
222
|
|
213
223
|
|
214
224
|
|
@@ -222,8 +232,10 @@
|
|
222
232
|
<div class="section">
|
223
233
|
<p>Interceptors are objects (or blocks) that sit between a client and a service and <em>intercept</em> messages (methods) sent to the service. Each service may have many such interceptors. When control is passed to an interceptor, it may then do something before and after passing control to the next interceptor, possibly even returning instead of passing control. This allows for some simple <acronym title="Aspect-Oriented Programming">AOP</acronym>-like hooks to be placed on your services.</p>
|
224
234
|
|
235
|
+
|
225
236
|
<p>Needle comes with one interceptor, the LoggingInterceptor. This allows you to easily trace the execution of your services by logging method entry and exit, as well as any exceptions that are raised.</p>
|
226
237
|
|
238
|
+
|
227
239
|
<p>You can, of course, implement your own interceptors as well.</p>
|
228
240
|
</div>
|
229
241
|
|
@@ -239,8 +251,10 @@
|
|
239
251
|
<div class="section">
|
240
252
|
<p>Interceptors are implemented as proxy objects that front the requested service. Thus, if you request a service that has 3 interceptors wrapped around it, you’re really getting a proxy object back that will invoke the interceptors (in order) before the requested method of the service is invoked.</p>
|
241
253
|
|
254
|
+
|
242
255
|
<p>The interceptors themselves are attached to the service during the execution of its instantiation pipeline (see Service Models). Thus, any action in the pipeline that is situated closer to the service than the interceptor pipeline action will bypass the interceptors altogether. This allows you to attach hooks to your service that can be called without invoking the interceptors on the service.</p>
|
243
256
|
|
257
|
+
|
244
258
|
<p>Another thing to keep in mind is that the interceptors are one-to-one for each service instance. Thus, if your service is a prototype (see the Service Models chapter), you’ll have one instance of each interceptor for each instance of your service.</p>
|
245
259
|
</div>
|
246
260
|
|
@@ -256,66 +270,85 @@
|
|
256
270
|
<div class="section">
|
257
271
|
<p>There are two ways to attach interceptors to your services. The first is to implement an interceptor <em>factory</em> that returns new interceptor <em>instances</em>, and attach the factory to your service. The second is to specify a block that implements the required functionality. Both have their uses.</p>
|
258
272
|
|
273
|
+
|
259
274
|
<h3>Interceptor Factories</h3>
|
260
275
|
|
276
|
+
|
261
277
|
<p>Interceptor factories are useful in situations where you want to implement some functionality and have it apply to multiple services. Interceptors from factories are also faster (less overhead) than interceptors from blocks, and so might be appropriate where performance is an issue.</p>
|
262
278
|
|
279
|
+
|
263
280
|
<p>An example is the LoggingInterceptor that ships with Needle. Because it is functionality that could be used on any number of services, it is implemented as a factory.</p>
|
264
281
|
|
282
|
+
|
265
283
|
<p>You can attach interceptor factories to your service using the <code>#interceptor(...).with {...}</code> syntax:</p>
|
266
284
|
|
267
285
|
|
268
|
-
<
|
269
|
-
|
270
|
-
|
271
|
-
</pre>
|
286
|
+
<div class='figure'>
|
287
|
+
<span class='caption'>Attaching an interceptor to a service [ruby]</span>
|
288
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
|
289
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
|
290
|
+
|
291
|
+
|
272
292
|
<p>Note that you could also make the interceptor factory a service:</p>
|
273
293
|
|
274
294
|
|
275
|
-
<
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
</pre>
|
295
|
+
<div class='figure'>
|
296
|
+
<span class='caption'>Attaching an service as an interceptor [ruby]</span>
|
297
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
|
298
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:my_interceptor</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span>
|
299
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">c</span><span class="punct">|</span> <span class="ident">c</span><span class="punct">.</span><span class="ident">my_interceptor</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
|
300
|
+
|
301
|
+
|
280
302
|
<p>And, to make accessing interceptor services even more convenient, you can use the <code>#with!</code> method (which executes its block within the context of the calling container):</p>
|
281
303
|
|
282
304
|
|
283
|
-
<
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
</pre>
|
305
|
+
<div class='figure'>
|
306
|
+
<span class='caption'>Attaching an service as an interceptor via #with! [ruby]</span>
|
307
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
|
308
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:my_interceptor</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span>
|
309
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with!</span> <span class="punct">{</span> <span class="ident">my_interceptor</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
|
310
|
+
|
311
|
+
|
288
312
|
<h3>Blocks</h3>
|
289
313
|
|
314
|
+
|
290
315
|
<p>Sometimes creating an entire class to implement an interceptor is overkill. This is particularly the case during debugging or testing, when you might want to attach an interceptor to class to verify that a parameter passed is correct, or a return value is what you expect. To satisfy these conditions, you can using the
|
291
316
|
<code>#doing</code> method. Just give it a block that accepts two parameters (the chain, and context) and you’re good to go!</p>
|
292
317
|
|
293
318
|
|
294
|
-
<
|
295
|
-
|
296
|
-
|
297
|
-
</pre>
|
319
|
+
<div class='figure'>
|
320
|
+
<span class='caption'>Defining interceptors on the fly [ruby]</span>
|
321
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
|
322
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">doing</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">chain</span><span class="punct">,</span><span class="ident">ctx</span><span class="punct">|</span> <span class="punct">...;</span> <span class="ident">chain</span><span class="punct">.</span><span class="ident">process_next</span><span class="punct">(</span> <span class="ident">ctx</span> <span class="punct">)</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
|
323
|
+
|
324
|
+
|
298
325
|
<p>Note that this approach is about 40% slower than using an interceptor factory, so it should not be used if performance is an issue.</p>
|
299
326
|
|
327
|
+
|
300
328
|
<h3>Options</h3>
|
301
329
|
|
330
|
+
|
302
331
|
<p>Some interceptors can accept configuration options. For example, the LoggingInterceptor allows clients to specify methods that should and shouldn’t be intercepted. Options are specified via the <code>#with_options</code> method.</p>
|
303
332
|
|
304
333
|
|
305
|
-
<
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
</pre>
|
334
|
+
<div class='figure'>
|
335
|
+
<span class='caption'>Configuring interceptors [ruby]</span>
|
336
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
|
337
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span>
|
338
|
+
<span class="ident">with</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">c</span><span class="punct">|</span> <span class="ident">c</span><span class="punct">.</span><span class="ident">logging_interceptor</span> <span class="punct">}.</span>
|
339
|
+
<span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:exclude</span> <span class="punct">=></span> <span class="punct">[</span> <span class="punct">"</span><span class="string">method1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">method2</span><span class="punct">"</span> <span class="punct">]</span> <span class="punct">)</span></pre></div></td></tr></table></div></div>
|
340
|
+
|
341
|
+
|
311
342
|
<p>Options can apply to the blocks given to the <code>#doing</code> method, too. The block may access the options via the <code>#data[:options]</code> member of the context:</p>
|
312
343
|
|
313
344
|
|
314
|
-
<
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
</pre>
|
345
|
+
<div class='figure'>
|
346
|
+
<span class='caption'>Configuring #doing interceptors [ruby]</span>
|
347
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span>
|
348
|
+
<span class="ident">doing</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">ch</span><span class="punct">,</span><span class="ident">ctx</span><span class="punct">|</span> <span class="punct">...;</span> <span class="ident">p</span> <span class="ident">ctx</span><span class="punct">.</span><span class="ident">data</span><span class="punct">[</span><span class="symbol">:options</span><span class="punct">][</span><span class="symbol">:value</span><span class="punct">];</span> <span class="punct">...</span> <span class="punct">}.</span>
|
349
|
+
<span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:value</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">hello</span><span class="punct">"</span> <span class="punct">)</span></pre></div></td></tr></table></div></div>
|
350
|
+
|
351
|
+
|
319
352
|
<p>With blocks, of course, the value of such an approach is limited.</p>
|
320
353
|
</div>
|
321
354
|
|
@@ -331,16 +364,20 @@
|
|
331
364
|
<div class="section">
|
332
365
|
<p>As was mentioned, a service may have multiple interceptors attached to it. By default, a method will be filtered by the interceptors in the same order that they were attached, with the first interceptor that was attached being the first one to intercept every method call.</p>
|
333
366
|
|
367
|
+
|
334
368
|
<p>You can specify a different ordering of the interceptors by giving each one a <em>priority</em>. The priority is a number, where interceptors with a higher priority sort <em>closer</em> to the service, and those with lower priorities sort <em>further</em> from the service.</p>
|
335
369
|
|
370
|
+
|
336
371
|
<p>You can specify the priority as an option when attaching an interceptor:</p>
|
337
372
|
|
338
373
|
|
339
|
-
<
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
</pre>
|
374
|
+
<div class='figure'>
|
375
|
+
<span class='caption'>Setting interceptor priorities [ruby]</span>
|
376
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{</span> <span class="punct">...</span> <span class="punct">}</span>
|
377
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">Something</span> <span class="punct">}.</span><span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:priority</span> <span class="punct">=></span> <span class="number">100</span> <span class="punct">)</span>
|
378
|
+
<span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">SomethingElse</span> <span class="punct">}.</span><span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:priority</span> <span class="punct">=></span> <span class="number">50</span> <span class="punct">)</span></pre></div></td></tr></table></div></div>
|
379
|
+
|
380
|
+
|
344
381
|
<p>Without the priorities, when a method of <code>:foo</code> was invoked, Something would be called first, and then SomethingElse. <em>With</em> the priorities (as specified), SomethingElse would be called before Something (since SomethingElse has a lower priority).</p>
|
345
382
|
</div>
|
346
383
|
|
@@ -356,34 +393,47 @@
|
|
356
393
|
<div class="section">
|
357
394
|
<p>Creating your own interceptors is very easy. As was demonstrated earlier, you can always use blocks to implement an interceptor. However, for more complex interceptors, or for interceptors that you want to reuse across multiple services, you can also implement your own interceptor <em>factories</em>.</p>
|
358
395
|
|
396
|
+
|
359
397
|
<p>An interceptor factory can be any object, as long as it implements the method <code>#new</code> with two parameters, the <em>service point</em> (service “definition”) of the service that the interceptor will be bound to, and a hash of the options that were passed to the interceptor when it was attached to the service. This method should then return a new interceptor instance, which must implement the <code>#process</code> method. The <code>#process</code> method should accept two parameters: an object representing the <em>chain</em> of interceptors, and the invocation <em>context</em>.</p>
|
360
398
|
|
361
399
|
|
362
|
-
<
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
end
|
376
|
-
</pre>
|
400
|
+
<div class='figure'>
|
401
|
+
<span class='caption'>Custom interceptor example [ruby]</span>
|
402
|
+
<div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">class </span><span class="class">MyInterceptorFactory</span>
|
403
|
+
<span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">point</span><span class="punct">,</span> <span class="ident">options</span> <span class="punct">)</span>
|
404
|
+
<span class="punct">...</span>
|
405
|
+
<span class="keyword">end</span>
|
406
|
+
|
407
|
+
<span class="keyword">def </span><span class="method">process</span><span class="punct">(</span> <span class="ident">chain</span><span class="punct">,</span> <span class="ident">context</span> <span class="punct">)</span>
|
408
|
+
<span class="comment"># context.sym : the name of the method that was invoked</span>
|
409
|
+
<span class="comment"># context.args : the array of arguments passed to the method</span>
|
410
|
+
<span class="comment"># context.block : the block passed to the method, if any</span>
|
411
|
+
<span class="comment"># context.data : a hash that may be used to share data between interceptors</span>
|
412
|
+
<span class="keyword">return</span> <span class="ident">context</span><span class="punct">.</span><span class="ident">process_next</span><span class="punct">(</span> <span class="ident">context</span> <span class="punct">)</span>
|
413
|
+
<span class="keyword">end</span>
|
414
|
+
<span class="keyword">end</span></pre></div></td></tr></table></div></div>
|
415
|
+
|
416
|
+
|
377
417
|
<p>Once you’ve created your factory, you can attach it to a service:</p>
|
378
418
|
|
379
419
|
|
380
|
-
<
|
381
|
-
|
382
|
-
</pre>
|
420
|
+
<div class='figure'>
|
421
|
+
<span class='caption'>Attaching a custom interceptor [ruby]</span>
|
422
|
+
<div class='body'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span></pre></div></div></div>
|
383
423
|
</div>
|
384
424
|
|
385
425
|
|
386
426
|
|
427
|
+
<div class="bottom"><div class="prevnext">
|
428
|
+
|
429
|
+
<a href="chapter-4.html">Previous (4. Dependency Injection)</a> |
|
430
|
+
|
431
|
+
<a href="index.html">Up</a>
|
432
|
+
|
433
|
+
| <a href="chapter-6.html">Next (6. Service Models)</a>
|
434
|
+
|
435
|
+
</div></div>
|
436
|
+
|
387
437
|
|
388
438
|
</div>
|
389
439
|
|