Announcement Announcement Module
Collapse
No announcement yet.
Howto register beans with other beans? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Howto register beans with other beans?

    Consider the following situation: You have a singleton service manager bean that should be the access point for a set of services. Obviously, at some time each service has to be registered with the service manager in order to be accessible to the application. But how should that be done?

    A simple approach would be something like this:

    Code:
    <bean id="ServiceManager" class="...">
        <property name="services">
            <list>
                <value ref="Service1" />
                <value ref="Service2" />
            </list>
        </property>
    </bean>
    
    <bean id="Service1" class="..." />
    <bean id="Service2" class="..." />

    Unfortunately, there are two drawback:
    1. In a large application where bean definitions are divided into several XML files, we cannot add/remove a service without changing the bean definition of the ServiceManager bean. This destroys the modularity of the applications since an application module cannot add a service without a change to the application core (where the ServiceManager belongs). Note also that such a change would add a dependency from the core to the service module effectively "hard linking" the service module to the core.
    2. Again, if the application is split into modules (each with its own bean definitions) all modules that declare services must be loaded at startup so that the service beans can be instantiated prior to the instantiation of the ServiceManager bean.

    So, how do we get around these problems? Is there any support for calling a registration method on another bean when a bean is instantiated?

    So far, the only solution I've come up with is to use MethodInvokingFactoryBean:

    Code:
    <bean id="ServiceManager" class="..." />
    <bean id="Service1" class="..." />
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="ServiceManager" />
        <property name="targetMethod" value="registerService" />
        <property name="arguments">
            <list>
                <ref bean="Service1" />
            </list>
        </property>
    </bean>
    
    <bean id="Service2" class="..." />
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="ServiceManager" />
        <property name="targetMethod" value="registerService" />
        <property name="arguments">
            <list>
                <ref bean="Service2" />
            </list>
        </property>
    </bean>
    This, however, is more of a hack than an actual solution (and also seems far to verbose). There is also another problem that I didn't mention before: If an application module is to be deactivated/removed at runtime (say, in an OSGi environment) this does not say how to unregister the service when the "SubBeanFactory" of the service module is destroyed.

    Enough talk... anyone got some good ideas on how to implement this?

    Best regards,
    Soren Petersen

  • #2
    First off all I think the design of using 1 service manager is already flawed, but that is IMHO of course. I would simply inject the needed services in the beans which needed them and not use a ServiceManager.getInstance().getServiceName(). But that is imho...

    Why do you even inject your beans into your service manager, you could rewrite the service manager to do the lookups (Dependency Pulll). If you would implement ApplicationContextAware, create some logic in the ServiceManager to pull the beans as requested from the application context.

    Another solution could be to let the ServiceManager listen to events from the ApplicationContext. Create a BeanPostProcessor which creates an specific event (Created/Destroyed) and let the ServiceManager act on that.

    Comment


    • #3
      Originally posted by mdeinum View Post
      First off all I think the design of using 1 service manager is already flawed, but that is IMHO of course. I would simply inject the needed services in the beans which needed them and not use a ServiceManager.getInstance().getServiceName(). But that is imho...
      I must partially agree with you. In situations where the service user knows what services to use they should probably be injected directly. However, there are situations where a bean and the application module that contains that bean (and thus its bean definition) doesn't know what service to use.

      Consider this somewhat artificial example: Say that you are building an application that is supposed to communicate with some embedded devices that are distributed across a city. Each device has a unique ID by which it can be located. For practical reasons, these devices are accessible with different kinds of communication technologies depending on their location. They could for instance be connected with GPRS (radio), MOBITEX (radio) and Ethernet (wire). Several beans in the application needs to make socket connections to these devices, but should not be aware of how each device is connected (connection might change for a single device when the device is moved/upgraded). A "ServiceManager" pattern could be used to provide a transparent way to obtain an appropriate communication socket to the device. Moreover, this would enable you to plug in modules that provide new communication technology (a kind of service) as well as rules to decide what communication technology to use for a specific ID (also a kind of service).

      What a messy explanation. I hope you got my point though.

      A similar example can be constructed when handling object persistence across several types of object stores (SQL databases with O/R mappings, Object databases, plaintext files ... ). You need a transparent way to fetch and store objects without any knowledge of where and how that particular object is stored.

      Originally posted by mdeinum View Post
      Why do you even inject your beans into your service manager, you could rewrite the service manager to do the lookups (Dependency Pulll). If you would implement ApplicationContextAware, create some logic in the ServiceManager to pull the beans as requested from the application context.
      I've thought about this and it seams like a good idea except this: The pull mechanism would "register" every bean that implements a certain service interface which might not be desirable. What if we have two separate service managers (instances of the same class) and want to register one set of services with the first and another set with the second one?

      Also, this solution makes the application (or at least the service manager) highly dependent on the BeanFactory framework...

      Originally posted by mdeinum View Post
      Another solution could be to let the ServiceManager listen to events from the ApplicationContext. Create a BeanPostProcessor which creates an specific event (Created/Destroyed) and let the ServiceManager act on that.
      This might be the way to go. A separate BeanPostProcessor would at least remove the dependancy from the ServiceManager to the BeanFactory framework.

      Thanks for your response!!!!

      \Soren

      Comment


      • #4
        Originally posted by sorenp View Post
        ..
        Also, this solution makes the application (or at least the service manager) highly dependent on the BeanFactory framework...
        You may implement "puller" separatly and inject it into the ServiceManager. Then you have no direct dependency from ServiceManager to the bean framework. And this puller may implement diffrent strategies to select services - interface based, wildcard-based etc.

        Comment

        Working...
        X