Spring includes a number of factory beans we have not described yet, which can make some container configurations much simpler, or even possible. Note that the usefulness of these factory beans will decrease when Spring implements built-in support of an expression language in the application context, as is scheduled to be completed for Spring 1.3.
PropertyPathFactoryBean is a very useful factory bean that can be used to return the result of evaluating a property path on a target object. While you can set a bean property or constructor argument to the value of another bean in the container via a direct bean reference (ref element), this doesn't help when you need a property of that bean, or a property of a property. PropertyPathFactoryBean lets you get at those nested properties. Let's look at some examples.
In this example, the result of the factory bean is the city property of the address property of the person bean that is pointed to:
<bean ... </bean> <bean > <property name="targetObject"><ref local="person"/></property> <property name="propertyPath"><value>address.city</value></property> </bean>
The following example is equivalent, except that the target bean on which the property is being evaluated has been moved to be an inner bean:
<bean > <property name="propertyPath"><value>address.city</value></property> <property name="targetObject"> <!-- person bean has been moved to be an inner bean --> <bean > ... </bean> </property> </bean>
Here we refer to the target bean by name:
<bean ... </bean> <bean > <property name="targetBeanName"><value>person</value></property> <property name="propertyPath"><value>address.city</value></property> </bean>
And finally, there is a very convenient shortcut form, where the name of the PropertyPathFactoryBean instance is used as the actual property path. Of course, you no longer have any choice in the bean name. This form is very useful for an inner bean:
<bean ... </bean> <bean />
Note that nesting can go to arbitrary levels, not just two deep as in these examples.
This factory bean retrieves the value of a static or non-static class field. The most useful use case is when you need to get a static constant from a class:
<bean > <property name="staticField"> <value>java.lang.Long.MAX_VALUE</value> </property> </bean>
There is a short form that uses the name of the bean as the static field name. This variant will produce the same output, although of course there is no longer any choice as to the bean name:
You may also get a non-static field from another bean:
<bean > <property name="targetObject"><ref local="person"/></property> <property name="targetField"><value>address</value></property> </bean>
MethodInvokingFactoryBean is a factory bean that returns the result of a method invocation as its output. This is useful in two scenarios.
In one scenario, a bean property or constructor argument needs to be set to the result of a method invocation on another bean in the container, or a static method call on some arbitrary class. Spring's factory method support (used via the factory-method attribute as described in the previous chapter) is actually the best way to handle this need for most situations. Factory methods were described in the "Bean Creation Mechanism" section of Chapter 2. You'll still sometimes see MethodInvokingFactoryBean used for this purpose, instead of the factory method mechanism, as the former has been around longer.
The other scenario where this factory bean is useful is when a static method on some arbitrary class needs to be called in order to initialize some component, and that method doesn't have any return value. In this case, the factory-method mechanism is not usable, as it expects the factory method to return a value to be used as the bean. One example of such an initialization scenario is JDBC 1.0 style creation of a DataSource via JDBC's DriverManager..getConnection(). Before using this method, you needto ensure that the JDBC driver has been registered, by calling Class.forName(<db-driver class>), which triggers the JDBC driver to register itself with the DriverManager, as part of its static initialization block. Here's an example of how Class.forName() could be called in this fashion:
<bean > <property name="staticMethod"> <value>java.lang.Class.forName</value> </property> <property name="arguments"> <list><value>oracle.jdbc.driver.OracleDriver</value></list> </property> </bean>
To ensure that this method call is invoked before another bean is initialized, that other bean can refer to this one via the depends-on attribute.