Spring Python i merge’owanie kontekstów
Miłym ficzerem Spring Pythona jest merge’owanie kontekstów utworzonych w różnych składniach, czyli możliwe jest utworzenie części kontekstów korzystając ze składni Pythona, części w XML-u, a części, powiędzmy, w YAML-u (co jest nowością w Spring Pythonie 1.1).
Możemy więc mieć np. taką strukturę plików:
. |-- ctx-merging.py |-- standard_ctx.py `-- dynamic-ctx.xml
- ctx-merging.py – kod źródłowy naszej aplikacji,
- standard_ctx.py – stały kontekst naszej aplikacji, zapisany w składni Pythona,
- dynamic-ctx.xml – kontekst XML-owy zmieniający się w trakcie działania aplikacji, np. trzymane są tutaj różne ustawienia aplikacji, które userzy mogą zmieniać.
Poniżej jest kod źródłowy plików, nieważne, że konteksty niczego mądrego w tych przykładach nie przechowują, chodzi tylko o zilustrowanie zasady:
ctx-merging.py
# -*- coding: utf-8 -*- # Spring Python from springpython.context import ApplicationContext from springpython.config import XMLConfig # Nasz własny, stały, kontekst aplikacyjny. from standard_ctx import StandardApplicationContext # Kontekst w Pythonie. standard_ctx = StandardApplicationContext() # Kontekst w XML-u, dynamicznie update'owany przez aplikację. dynamic_ctx = XMLConfig("./dynamic-ctx.xml") # Zmerge'owane konteksty, zarówno ten w Pythonie jak i XML-owy. container = ApplicationContext([standard_ctx, dynamic_ctx]) # Pobranie obiektów z kontenera IoC. factory = container.get_object("factory") my_int = container.get_object("my_int") # Wyświetlenie obiektów. print factory print my_int
standard_ctx.py
# -*- coding: utf-8 -*-
from springpython.config import PythonConfig
from springpython.config import Object
from springpython.context import scope
class StandardApplicationContext(PythonConfig):
def __init__(self):
super(StandardApplicationContext, self).__init__()
@Object(scope.PROTOTYPE)
def my_int(self):
return 11
dynamic-ctx.xml
<?xml version="1.0" encoding="UTF-8"?>
<objects xmlns="http://www.springframework.org/springpython/schema/objects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/springpython/schema/objects
http://springpython.webfactional.com/schema/context/spring-python-context-1.0.xsd">
<object id="factory"
class="springpython.database.factory.Sqlite3ConnectionFactory"
scope="prototype">
</object>
</objects>
Cały trick polega na tym, że w standard_ctx.py możemy w wygodnej, czytelnej dla nas, postaci kodu źródłowego Pythona trzymać część kontekstu, która nie zmienia się. Lepiej trzymać to w postaci Pythona, bo przecież jest to postać najczytelniejsza, po co męczyć się i edytować XML? W dynamic-ctx.xml trzymamy z kolei to, co może zmieniać się i do czego raczej nie będziemy sami zaglądali, żeby edytować. Lepiej jest więc to trzymać w XML-u, bo dzięki temu mamy łatwą serializację.
Co, jeśli więcej niż jeden kontekst trzymają dwa tak samo obiekty? Np. w obydwu kontekstach byłby obiekt ‘factory’? Wynik jest wtedy niezdefiniowany. Oczywiście zawsze można zajrzeć do źródeł i mieć jasność
ale i tak będzie oznaczało to poleganie na nieudokumentowanej funkcjonalności.
Jeszcze raz zwracam uwagę na YamlConfig – od wersji 1.1 Spring Pythona dostępna będzie bajecznie czytelna postać, która bije konfigurację XML-ową bez mrugnięcia okiem.
