Announcement Announcement Module
Collapse
No announcement yet.
Error Handling and Recovery for Optional Beans? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Error Handling and Recovery for Optional Beans?

    We use Spring to configure a number of optional services, e.g., we allow registering JMX data for remote access using the ConnectorServerFactoryBean. However, sometimes there can be port conflicts if more than one server is running on a machine. We would like to recover from this failure to initialize the bean instead of having the failure result in the destruction of the whole bean factory. We'd also like to log an error message (oddly ConnectorServerFactoryBean logs nothing on failure, but has info logging on success).

    Is there a way of telling Spring that a given bean is optional and not to fail if it can't be instantiated? Is there a way to associate error handling logic (e.g., logging) with failure to instantiate? Could Spring AOP do this? (I'm guessing it won't proxy something that wasn't constructed, right?) I know I could write an adapter bean class that just tries to create the underlying object and does error handling in code. Is this the best way?

    Thanks,
    Ron

  • #2
    Is there a way of telling Spring that a given bean is optional and not to fail if it can't be instantiated? Is there a way to associate error handling logic (e.g., logging) with failure to instantiate? Could Spring AOP do this? (I'm guessing it won't proxy something that wasn't constructed, right?) I know I could write an adapter bean class that just tries to create the underlying object and does error handling in code. Is this the best way?
    At the moment, there isn't any. The applicationContex/beanFactory represent a configuration which has to be valid - a bean might be optional but it can be used with some non-optional beans - if the bean is invalid then the whole tree becomes invalid. Adding support for optional beans is not an easy task.
    For your case I would suggest to use FactoryBeans to dynamically create an object - note that you'll always have to return an object so in case of an exception you will have to return null.
    I would put all the logic inside the FactoryBean or inside an init method which will do all the retry logic and then, if everything fails, return a null object or an exception.

    Comment


    • #3
      Thanks Costin. It turns out that we actually have to handle errors in afterPropertiesSet. It's probably possible to do this with Spring AOP, but I ended up just using AspectJ:

      Code:
      public aspect OptionalBeanRecovery {
      
          private boolean OptionalBean.failed = false;
          private String OptionalBean.beanName;
          
          public void OptionalBean.onError(Exception e) {
              logWarn("Unable to initialize "+beanName, e);
          }
          
          public void OptionalBean.setBeanName(String name) {
              beanName = name;
          }
          
          public String OptionalBean.getBeanName() {
              return beanName;
          }
          
          void around(OptionalBean optionalBean) : execution(void afterPropertiesSet()) && this(optionalBean) {
              try {
                  proceed(optionalBean);
              } catch (Exception e) {
                  optionalBean.failed = true;
                  optionalBean.onError(e);
              }
          }
      
          void around(OptionalBean optionalBean) : execution(void destroy()) && this(optionalBean) {
              if (!optionalBean.failed) {
                  proceed(optionalBean);
              }
          }    
                  
      }
      
      public interface OptionalBean extends InitializingBean, BeanNameAware {}
      
      public class OptionalConnectorServerFactoryBean extends ConnectorServerFactoryBean implements OptionalBean {
      
          public void onError(Exception e) {
              logWarn("Unable to set up remote JMX connector. This is often caused by having another server trying to use the same ports. Root cause:", e);
          }
          
          // boilerplate code to provide a hook for advising
          public void afterPropertiesSet() throws JMException, IOException {
              super.afterPropertiesSet();
          }
      
          // boilerplate code to provide a hook for advising
          public void destroy() throws IOException {
              super.destroy();
          }
      
      }

      Comment

      Working...
      X