Configured Rulebase Modules

In the previous examples we've only used one rulebase to build our object graph, however, a key feature of Configured is the ability to wire logically distinct parts of your application using independent rulebases - you don't need to have one huge rulebase to take care of everything.

Configured determines a rulebase to use for every object it encounters in the object graph it's currently wiring by delegating to a RulebaseManager, the default implementation of which uses the following logic:

Rulebase resolution Activity Diagram

The best way to explain this is probably by an example. Below we show a partial definition of TestClassA, which specifies that it's to be configured by a rulebase named "example".

When Configured processes TestClassB, it will see that there is a dependency on TestClassA, find that TestClassA specifies a rulebase, and consequently, it will use that rulebase.

When Configured processes TestClassC, it will see that there is a dependency on TestClassA, but it will also see that TestClassC has specified a rulebase to use for its TestClassA dependency ("other_rulebase"), and so it will use that.

    // in general, Configured is going to use
    // the rulebase: "example" to build 
    // this object...
    @ConfiguredByRule(rulebase="example")
    public class TestClassA {
    
        // class body omitted
    }
    
    public class TestClassB {    
        
        // the rulebase "example" will be used
        // to initialize this dependency
        private TestClassA testClassA;    
        
        // class body omitted
    }
    
    public class TestClassC {
    
        // here we've overidden the default
        // rulebase for TestClassA
        @ConfiguredByRules(rulebase="other_rulebase")
        private TestClassA testClassA;
    
    }
    

Now here's a slightly more complex example, this time where the dependency is on an abstract type (i.e on an interface).

    public interface TestService {
    
        // interface definition omitted...
    }
    
    @ConfiguredByRules(rulebase="example")
    @ServiceProvider(service=TestService.class)
    public class TestServiceImpl implements TestService {  
         
        
        // class body omitted
    }
    
    public class TestClassD {    
                
        private TestService testService;
    
    }
    
    public class TestClassE {    
    
        @ConfiguredByRules(rulebase="other_rulebase")
        private TestService testService;
    
    }    
    

This works exactly the same way as before - once the concrete implementation of TestService has been resolved to be TestServiceImpl, the annotation is processed and the example rulebase will be used in TestClassD, but override in TestClassE.

To set up a modular rulebase, you do something like the following example where we've create an autowiring service with 3 different rulebase modules -default (a rulebase called default is required), rulebase_b and rulebase_c.

    <bean id="autowiringService"
        class="net.sourceforge.configured.spring.factory.SpringModularBeanGraphAutowiringServiceFactory">
        <property name="dependencyResolutionRules">
            <map>
            <!-- an entry called "default" is required -->
                <entry key="default">
                    <set>
                        <bean
                            class="net.sourceforge.configured.rules.standard.InstantiationRule">
                            <property name="instantiatedSuperTypes">
                                <set>
                                    <value>net.sourceforge.configured.spring.TestClassA</value>
                                </set>
                            </property>
                            <property name="precedence" value="1" />
                        </bean>                        
                    </set>
                </entry>
                <entry key="rulebase_b">
                    <set>
                        <bean
                            class="net.sourceforge.configured.rules.standard.InstantiationRule">
                            <property name="instantiatedSuperTypes">
                                <set>
                                    <value>net.sourceforge.configured.spring.TestClassB</value>
                                </set>
                            </property>
                            <property name="precedence" value="1" />
                        </bean>                        
                    </set>
                </entry>
                <entry key="rulebase_c">
                    <set>
                        <bean
                            class="net.sourceforge.configured.rules.standard.InstantiationRule">
                            <property name="instantiatedSuperTypes">
                                <set>
                                    <value>net.sourceforge.configured.spring.TestClassC</value>
                                </set>
                            </property>
                            <property name="precedence" value="1" />
                        </bean>
                    </set>
                </entry>
            </map>
        </property>
        <property name="ignoredDependencyTypes">
            <set>
                <value>org.springframework.context.ApplicationContext</value>
            </set>
        </property>
    </bean>