X Tutup
Skip to content

Commit 0e796c8

Browse files
committed
SESPRINGPYTHONPY-92: Updated documentation to show more usability of pure python IoC container.
git-svn-id: https://src.springframework.org/svn/se-springpython-py/trunk/springpython@462 ce8fead1-4192-4296-8608-a705134b927f
1 parent 51468b4 commit 0e796c8

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

docs/reference/src/aop.xml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,92 @@ factory.interceptors = [WrappingInterceptor()]
268268

269269
It produces the same thing.
270270

271+
</section>
272+
273+
<section id="aop-pure-python">
274+
<title>Coding AOP with Pure Python</title>
275+
276+
<para>There is a long history of Spring being based on XML. However, Spring Python offers an easy to use alternative: a
277+
<link linkend="objects-config-object">pure python decorator-based PythonConfig</link>. Imagine you had set up a simple
278+
context like this:</para>
279+
280+
<programlisting><![CDATA[
281+
from springpython.config import *
282+
from springpython.context import *
283+
284+
class MovieBasedApplicationContext(PythonConfig):
285+
def __init__(self):
286+
super(MovieBasedApplicationContext, self).__init__()
287+
288+
@Object(scope.PROTOTYPE)
289+
def MovieLister(self):
290+
lister = MovieLister()
291+
lister.finder = self.MovieFinder()
292+
lister.description = self.SingletonString()
293+
self.logger.debug("Description = %s" % lister.description)
294+
return lister
295+
296+
@Object(scope.SINGLETON)
297+
def MovieFinder(self):
298+
return ColonMovieFinder(filename="support/movies1.txt")
299+
300+
@Object # scope.SINGLETON is the default
301+
def SingletonString(self):
302+
return StringHolder("There should only be one copy of this string")
303+
]]></programlisting>
304+
305+
<para>From an AOP perspective, it is easy to intercept <classname>MovieFinder</classname> and wrap it with some
306+
advice. Because you have already exposed it as an injection point with this pure-python IoC container, you just need
307+
to make this change:</para>
308+
309+
<programlisting><![CDATA[
310+
from springpython.aop import *
311+
from springpython.config import *
312+
from springpython.context import *
313+
314+
class MovieBasedApplicationContext(PythonConfig):
315+
def __init__(self):
316+
super(MovieBasedApplicationContext, self).__init__()
317+
318+
@Object(scope.PROTOTYPE)
319+
def MovieLister(self):
320+
lister = MovieLister()
321+
lister.finder = self.MovieFinder()
322+
lister.description = self.SingletonString()
323+
self.logger.debug("Description = %s" % lister.description)
324+
return lister
325+
326+
# By renaming the original service to this...
327+
def targetMovieFinder(self):
328+
return ColonMovieFinder(filename="support/movies1.txt")
329+
330+
#...we can substitute a proxy that will wrap it with an interceptor
331+
@Object(scope.SINGLETON)
332+
def MovieFinder(self):
333+
return ProxyFactoryObject(target=self.targetMovieFinder(),
334+
interceptors=MyInterceptor())
335+
336+
337+
@Object # scope.SINGLETON is the default
338+
def SingletonString(self):
339+
return StringHolder("There should only be one copy of this string")
340+
341+
class MyInterceptor(MethodInterceptor):
342+
def invoke(self, invocation):
343+
results = "<Wrapped>" + invocation.proceed() + "</Wrapped>"
344+
return results
345+
]]></programlisting>
346+
347+
<para>Now, everything that was referring to the original <classname>ColonMovieFinder</classname> instance, is instead pointing
348+
to a wrapping interceptor. The caller and callee involved don't know anything about it, keeping your code isolated and clean.</para>
349+
350+
<note>
351+
<title>Shouldn't you decouple the interceptor from the IoC configuration?</title>
352+
353+
<para>It is usually good practice to split up configuration from actual business code. These two
354+
were put together in the same file for demonstration purposes.</para>
355+
</note>
356+
271357
</section>
272358

273359
</chapter>

docs/reference/src/objects.xml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,53 @@ class MixedApplicationContext2(PythonConfig):
970970
and <classname>PythonObjectFactory</classname>. These classes should rarely be used directly by
971971
the developer. They are instead used by the different types of configuration scanners.</para>
972972

973+
</section>
974+
975+
<section id="objects-testable-code">
976+
<title>Testable Code</title>
977+
978+
<para>One key value of using the IoC container is the how you can isolate parts of your code for better testing.
979+
Imagine you had the following configuration:</para>
980+
981+
<programlisting><![CDATA[
982+
from springpython.config import *
983+
from springpython.context import *
984+
985+
class MovieBasedApplicationContext(PythonConfig):
986+
def __init__(self):
987+
super(MovieBasedApplicationContext, self).__init__()
988+
989+
@Object(scope.PROTOTYPE)
990+
def MovieLister(self):
991+
lister = MovieLister()
992+
lister.finder = self.MovieFinder()
993+
lister.description = self.SingletonString()
994+
self.logger.debug("Description = %s" % lister.description)
995+
return lister
996+
997+
@Object(scope.SINGLETON)
998+
def MovieFinder(self):
999+
return ColonMovieFinder(filename="support/movies1.txt")
1000+
1001+
@Object # scope.SINGLETON is the default
1002+
def SingletonString(self):
1003+
return StringHolder("There should only be one copy of this string")
1004+
]]></programlisting>
1005+
1006+
<para>To inject a test double for <classname>MovieFinder</classname>, your test code would only have to
1007+
extend the class and override the <methodname>MovieFinder</methodname> method, and replace it with your
1008+
stub or mock object. Now you have a nicely isolated instance of <classname>MovieLister</classname>.</para>
1009+
1010+
<programlisting><![CDATA[
1011+
class MyTestableAppContext(MovieBasedApplicationContext):
1012+
def __init__(self):
1013+
super(MyTestableAppContext, self).__init__()
1014+
1015+
@Object
1016+
def MovieFinder(self):
1017+
return MovieFinderStub()
1018+
]]></programlisting>
1019+
9731020
</section>
9741021

9751022
</chapter>

0 commit comments

Comments
 (0)
X Tutup