#Summary
What I like best is the SpecificationContext
- it has everything you
need to manipulate the bean factory / registry / context before it is
used. Even if it doesn't have everything, it is headed in the right
direction. In contrast a BFPP can always do everything, but the API
is not as nice and it is a more dangerous opportunity to abuse the
container (e.g. a BFPP always risks causing a cascade of early
initialization if it touches something that it shouldn't).
My top issues are
- Lack of consistency between
@Configuration
and XML. - Unclear semantics wrt ordering and alternatives. When do the feature
specs get executed and why? Why would I use a
FeatureSpecification
and whenContextInitializer
and whenBeanFactoryPostProcessor
? - Lack of support for
BeanFactory
goodies like externalization and DI in XML parser products (e.g. look at theMvcResources
feature).
I'm wondering if ContextInitializer
might be redundant - I would prefer
to do everything I do there in a FeatureSpecification
- or maybe that is
the only choice for strict ordering (it happens before anything else).
In any case there are quite a few CI use cases that would work just as
well as a FS, and they would be easier use becauser they would favour a
declarative approach. Danger is we end up with duplication, so there
would need to be an abstraction that they can share (e.g.
SpecificationContext
).
I have been able to achieve some quite nice results, but the bottom line
is I could have done it with BFPP. That would have allowed me to use DI
and externalization without any trickery. On the other hand, and this
could be important, BFPP always suffer from early initialization
syndrome. If we are stricter about the semantics of the new features
then we can ensure that they are always segregated from the main
ApplicationContext (like in my <bootstrap:context/>
). I can also see
opportunities for late sub-context creation, taking advantage of
parent-child relations.
There are also some major hacks in my parsers. I would like to expose some more utility methods in parser space.
-
I don't really understand why this:
<bean class="com.foo.MyFeatureSpecification"/>
is different to this:
<bean class="com.foo.MyConfiguration"/> @FeatureConfiguration public class MyConfiguration { @Feature public FeatureSpecification specification() { return new MyFeatureSpecification(); } }
(The latter works, the former does not.)
-
With the example above it's annoying because to add a property to
MyFeatureSpecification
I have to add it toMyConfiguration
as well. -
Note:
Environment.getDefaultProfiles()
has no callers, butacceptsProfiles()
does. -
Using a
@Feature
to set up a default profile might work, but doesn't because the<beans/>
sub-elements are parsed before the feature is executed. E.g. this doesn't work<!-- set up the default profile to "bar" --> <bean class="org.springframework.context.EnvironmentConfiguration"/> <beans profile="bar"> <bean class="..."/> ... </beans>
Maybe we need a
default-profile
attribute in<beans/>
anyway?Later: it appears that "" is the default profile. That works, I guess, but it would be nice to be able to declare it somewhere (or make it a bit more obvious).
Later still: actually "" is not a default profile. In fact there is an explicit test for empty string in
DefaultBeanDefinitionReader.doRegisterBeanDefinitions
and those beans are ignored. Odd that because using@ConfigurationLocation
works, but loading the context file directly does not(!?). -
FeatureSpecification
instances are executed by a BFPP (ConfigurationClassPostProcessor
) and that is not registered by default in aGenericXmlApplicationContext
. It suffices to add<context:annotation-config/>
to the context, but no-one would expect to have to do that. Maybe just documentation? -
There seems to be a lack of consistency in the conventions for detecting and using features. A bean definition that resolves to a
@FeatureConfiguration
works, but a@Bean
does not (you have to@Import
it). -
A
ManagedProperties
is aProperties
but doesn't behave like one - it's really a hack taking advantage of the fact thatProperties
is aHashtable
(yuck). To parse a<props/>
and convert to an actualProperties
you therefore have to create aBeanFactory
. There should be a better way? -
A
@Feature
might be a good way to implement the profile validation that a lot of people have asked for (e.g. barf if an active profile is not isted in a white list). -
MapPropertySource
has no public constructor.PropertySource
has some fishy looking public factory methods - all its subclasses get them as well, but they don't create instances of the subclass. Either the conxtructor should be public or the class should be less visible. -
The
GenericFeatureSpecificationParser
could actually execute all instances ofFeatureSpecification
that it finds in its sub-context, instead of returning a single on eto be executed by its base class. It has to get aSpecificationContext
from somewhere.AbstractSpecificationBeanDefinitionParser
has a private method to set up theSpecificationContext
, but would be better as a public static method somewhere else (e.g. utility class). -
A
@Feature
might be a bood way to activate profiles as well. -
The name of a
PropertySource
could be used to locate a property precisely, sinstead of relying on searching the wholeEnvironment
(a bit like JSF/Webflow scope hierarchies). -
There is no easy way to re-use existing reader code to load bean definitions from a fragment of XML (i.e. an
Element
). There is support at theDocument
level, but that's not convenient unless you have the whole thing to parse. There are some vicious hacks inGenericFeatureSpecificationParser
as a result, and it limits the schema choices - you basically have to use<beans/>
to nest child context otherwise there's no way to parse it. -
Writing XML parsers from
FeatureSpecifications
doesn't really work that well. The current implementation of the abstract feature parser does not useBeanDefinitions
to define the content, so it cannot easily accept expressions and placeholders as parameters. E.g. the MVCResourcesBeanDefinitionParser
works around this by having a cachePeriod in the specification of typeObject
(!). WTF? We can do better than this. -
The Javadocs for
FeatureSpecification
suggest really strongly that you use a fluent API for the implementation, but that's so unfriendly for DI that it makes writing the XML parsers too fiddly for me. Is it so bad to write two lines of code instead of one in a@Feature
? There are relaxed rules for setter signatures in the bean factory now, so that helps, but they don't extend to methods not starting with "set".