AdvancedSpringNotes

This page is mostly a braindump of various "advanced" Spring capabilities and related techniques that might be useful for various things.  Some of it is stuff that is was new to me (since the last time I read the Spring docs) and some other is basically just capabilities that we've never used, but which might be useful.

Autowiring

The container can autowire dependencies into other beans, avoiding the need to explicitly declare those dependencies. 

Auto-wiring is often set directly on the bean to be autowired, e.g. <bean autowire="strategy" />.  Several strategies are available for resolving the candiate bean(s) to wire in:

  1. byName - candidate based on bean name vis-a-via properties on the target.  E.g. if the target bean has a setFoo(...) method, then another bean with id/name of "foo" would be a candiate

  2. byType - candidate based on type.  E.g. if target bean has a setFoo(Bar bar) method, then another bean with a type of Bar is a candidate

  3. constructor - like byType, except for constructor

  4. no - turns off autowiring explicitly

Except for some special collection support, there generally must be at most one autowiring candiate, otherwise it's an error.  However, autowiring candidacy for a bean may be influenced by <bean autowire-candidate="true/false" /> and <bean primary="true/false" />

A default autowiring strategy can also be set on the entire context via <beans default-autowire="strategy" />, taking the same strategy values as autowire.

Ian: I think this may actually be per-configuration-file and not per-context, see for example <dead link removed> para 5.

When using default strategy, the selection of candidates for auto-wiring as dependencies into other beans can be influenced by <beans default-autowire-candidates="candidateList" />.  The candidateList is a comma-separated list of regexes which is matched on bean id/name.

TODO: how do <beans> defaults behave when you create a context based on multiple <beans> files?

BeanPostProcessor

This is an interface for a component which post-processes bean instances.  It can be defined in the context as just another bean, and the context auto-registers it based on its type.  It can have dependencies/collaborators injected into it just like any other bean, which in this case can be used to configure how it works. It has 2 callback methods: 1) called before any init lifecycle methods are invoked 2) called after all init lifecycle methods are invoked.

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

The order of execution can be deterministic by having the processor(s) implement the Ordered interface.

A post processor can wrap the returned bean in a proxy.

This would seem to be a good candidate for effectively auto-wiring things like ProfileRequestContexts or HttpServletRequest/Responses.  The processor could either look for an -Aware interface that we define, or could use full reflection to figure out where/when to wire.

BeanFactoryPostProcessor

This is an interface for a component which post-processes (primarily) BeanDefinitions. It can be defined in the context as just another bean, and the context auto-registers it based on its type.  It can have dependencies/collaborators injected into it just like any other bean, which in this case can be used to configure how it works. It has 1 callback method:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

Other than the BeanDefinitions, It could theoretically modify other aspects of the bean factory handed to it.

Bean Definition Inheritance

This technique essentially allows a <bean> definition to inherit various properties of a parent bean.  Basically it's a way to do templating.  It is implemented by simply declaring a parent bean reference on the bean:

<bean id="foo" class="..." /> <bean id="bar" parent="foo" class="..." />

Parent may also be declared abstract, in which case the container does not instantiate it.  Then it really does just become a "template" for other beans.

As can be seen above, the class relationships between the beans themselves really don't matter.  This is not Java inheritance, it's BeanDefinition inheritance.  So the parent can completely omit the class attribute and just be a template of properties.

Regarding what gets inherited, quoting verbatim:

  • A child bean definition inherits constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any initialization method, destroy method, and/or static factory method settings that you specify will override the corresponding parent settings.

  • The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.

This would seem incredibly useful for eliminating a lot of boilerplate stuff on the bean definitions, albeit at the minor invasive effect of having to declare the parent on each. (The BeanPostProcessor and/or BeanFactoryPostProcessor techniques would avoid that invasiveness, but at the cost of being more auto-magical and making the effective dependency config less obvious to someone looking at it).

Request and Session Scoped Beans

In a web context, in addition to the standard singleton and prototype beans, request and session-scoped beans may by used.  Spring implements this by attaching associating such beans to the HttpServletRequest and HttpSession via the use of a ThreadLocal variable to which is bound the current servlet request instance, managed in their holder context class org.springframework.web.context.request.RequestContextHolder.  The data stored in the ThreadLocal is managed (populated and later cleaned up) by one of three techniques:

  1. (Spring MVC Only) - Their  DispatcherServlet does this internally, when you use Spring MVC.  Declared as as servlet in web.xml

  2. (Servlet 2.4+ web container) - Via a javax.servlet.ServletRequestListener implementation declared in web.xml

  3. (Servlet 2.3 web container) - Via a javax.servlet.Filter implementation

Java-based Config

This used to be in a separate project, but is now since relatively recently in Spring core.  It occupies the middle ground between completely externalized XML-based container config, and completely internalized annotation-based config (where the annotations are invasively placed on the bean classes themselves).  Essentially separate Java classes are used to define the container, the beans within it and so on.  These classes are annotated appropriately.

Dependencies are specified by just having the Java code inject the appropriate instances, although the behavior is more advanced than it appears. The default is still for singleton beans, so unlike what the above implies, each instance of Foo gets the same instance of Bar.  @Scope annotation can be used to influence this.  

Seems this can also be combined with XML-based config and component scanning, which might be pretty powerful.

This is pretty complex, I won't attempt to document it all here.

At first I thought this would be of little use to us.  But on more thought, I suppose it might be. It might be attractive to wire up our dozens or hundreds of action/handler type beans this way, rather than with reams of XML config.

Lookup Method Injection

Used primarily to effectively inject a bean with a shorter lifecycle (e.g. prototype) into a bean with a longer lifecycle (e.g. singleton).   This is accomplished with runtime bytecode generation.

This would be useful if we actually have any cases like this, but I don't personally know of any at the moment.

Arbitrary Method Replacement/Injection

This  can replace an entire method implementation at runtime with generated bytecode.  The method used as the replacement is defined by implementing their interface org.springframework.beans.factory.support.MethodReplacer.

This doesn't seem terribly useful to me at the moment.

 

AOP Scoped Proxies

This technique allows the injection of an automatically bytecode-generated proxy, rather than the actual bean instance itself.  The use case is similar to the lookup method injection use case re: mismatches in bean lifecycles, but the docs discuss it more in the context of scoped beans as dependencies, specifically injecting request and session scope objects into singletons.  It's implemented by just declaring an additional element on the bean which is to be injected:

The type of proxy injected may be either a class-level or interface level proxy.  The former is the default and uses the CGLIB library.  This type of proxy only intercepts public method calls.

A JDK interface-based proxy may instead by used via <aop:scoped-proxy proxy-target-class="false"/>. The proxied bean must implement at least one interface, and the collaborator must call the bean through one of these interfaces.

Static and Instance Factory Methods

These features aren't terribly new or advanced, just noting them for completeness as they may be useful.

A bean may be produced by Spring invoking a static factory method on a class:

 

A bean may also be produced by Spring invoking a factory method on a non-static bean:

Use Cases

Reducing Noise of Injection of ProfileRequestContext

We could "autowire" the profile request context (or whatever it winds up being called) into a whole slew of actions, but reduce the clutter/noise of this common dependency, by any of a number of techniques.

  • Actual Spring autowiring on the whole container could be used, but at the cost of either marking every action with autowire or pretty global container config with default-autowire.  The effect of the latter can be mitigated somewhat with the autowire-default-candidates attribute.

  • Bean definition inheritance is the least auto-magical and makes the dependencies more obvious.  But does require marking all beans with parent.

  • BeanPostProcessor could be used to wire based on either an interface (e.g. action instance of ProfileRequestContextAware) or using Java reflection.  Is auto-magical and makes the dependencies less clear, but also results in a very clean config, with no possibilities for errors due to accidental omissions.

  • BeanFactoryPostProcessor could be used to actually alter the BeanDefinitions.  Need to prove out that this would actually work.  If does, would have mostly the same advantages and disadvantages as BeanPostProcessor.

  • Instead of actually declaring all the action beans in XML, we could possibly consider declaring some or all of them in Java code using the Java-based config technique.  This needs more research.

Injection of HttpServletRequest/Response

HttpSevletRequest/Response are not collaborators in the traditional sense, but are also not our own application domain-specific runtime state that we will manage in our context objects.  Instead, they could be categorized as more of "environmental" runtime state.  Although not a lot of classes (of the classes message handlers and actions) will need access to them, it would clean up some code if we could just get Spring to inject these where appropriate.  This would involve the use of ThreadLocal, similar to how Spring implements support for request and session-scoped beans.  The approach would basically be:

  1. Create a ThreadLocal-based request and/or response holder class, similar to my old example.

  2. Declare either a ServletRequestListener or Filter in web.xml to populate and clean up the ThreadLocal appropriately. A filter-based example is in my old project.

  3. Implement proxy classes for HttpServletRequest and HttpServletResponse that just delegate all methods through to the request or response as obtained from the holder class.

  4. Wire this proxy class to the beans that need it, using any of the above techniques:

    1. explicit dependency injection

    2. bean or bean factory post processors

    3. bean definition inheritance

    4. Java-based config

    5. etc

Auto-Adapting of non-Spring WebFlow Actions

The current notion of using OpenSAML profile actions which are Spring-independent is to wrap them in an Spring-dependent adaptor class.  Instead of doing this declaratively in the beans configuration XML, this could be done auto-magically in a BeanPostProcessor, allowing the beans XML to be simplified and contain only the declaration of the Spring-independent action bean.

 

 

Â