h1

Thread-safe code

April 20, 2008

All software is buggy. I am not especially worried about finding bugs in code, but when you identify the same bug rearing its head in multiple places, that’s a cause for concern. How do you satisfy yourself that you have rooted out all instances of the bug? Do you just fix each one as you find them or can you do something about the problem?

So what’s the bug? In any Java Spring application, storing state in a singleton bean is inherently thread-unsafe and a recipe for disaster. Each such instance needs to be considered on its own merit to determine if the code provides thread-safe access to the state. I considered using some sort of static bug-detection tool such as FindBugs to help me find more instances of this bug. And maybe it is possible. I can’t think of any. I also looked at Google’s Singleton Detector, but that deals with another Singleton pattern – not singleton beans in a Spring application.

So I decided to write some code to identify a short-list of candidates that could be inspected manually.

  1. First I load the application context and get a list of singleton beans.
  2. I then filter out all beans that don’t belong to the package I am interested in.
  3. Going through all variables in each bean, I ignore all statics and references to other Spring beans.
  4. I then assume that properties set through the Spring application context are not meant to be mutable state and ignore those fields as well.
  5. This then gives me my candidate list. Unfortunately, this also includes properties assigned through the Spring application context but using constructor arguments, and fields whose names are different from their setters.

I will keep my mind open to refine this, or to approach this from an entirely different angle. For now, here’s the code:

package com.ragstorooks.testing;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Vector;

import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;

public class SpringSingletonStateDetector {
  private static String packageName = "com.ragstorooks";
  private static String applicationContextName = "applicationContext.xml";

  public void testSingletonState() throws Exception {
    ClassPathXmlApplicationContext applicationContext =
      new ClassPathXmlApplicationContext(applicationContextName);
    Collection<Object> beanInstances = new Vector<Object>();

    System.err.println("Spring singleton classes and their fields:");
    System.err.println();
    String[] beans = applicationContext.getBeanDefinitionNames();
    for (String b : beans) {
      Object bean = applicationContext.getBean(b);
      beanInstances.add(bean);
    }

    for (String b : beans) {
      if (applicationContext.isPrototype(b)) continue;

      boolean namePrinted = false;
      Object bean = applicationContext.getBean(b);
      Class<?> beanz = bean.getClass();
      if (beanz.getPackage() == null ||
          !beanz.getPackage().getName().startsWith(packageName))
        continue;

      for (Class<?> clazz = beanz;
          clazz.getPackage() != null &&
          clazz.getPackage().getName().startsWith(packageName);
          clazz = clazz .getSuperclass().getClass()) {
        Field[] beanFields = beanz.getDeclaredFields();
        if (beanFields.length == 0) continue;

        for (Field beanField : beanFields) {
          beanField.setAccessible(true);
          if (Modifier.isStatic(beanField.getModifiers()) ||
              beanInstances.contains(beanField.get(bean)))
            continue;

          // Hopefully properties set via Spring are ok and can be ignored!
          if (applicationContext.getBeanFactory().getBeanDefinition(b).
              getPropertyValues().contains(beanField.getName()))
            continue;

          if (!namePrinted) {
            System.err.println(String.format("%s%s(%s):",
                System.getProperty("line.separator"), b, clazz.getSimpleName()));
            namePrinted = true;
          }
          System.err.println(String.format("\t%s: %s",
              beanField.getName(), beanField.getType().getSimpleName()));
        }
      }
    }

    applicationContext.destroy();
  }

  public static void main(String[] args) throws Exception {
    new SpringSingletonStateDetector().testSingletonState();
  }
}
Advertisements

5 comments

  1. Very cool! Have you thought about posting this to the Spring guys?


  2. No I hadn’t thought about it. But until we remove all necessity of manual intervention, I don’t see that they would be interested. You might be able to eliminate further with the constructor arguments but even then, you are left with manually inspecting code to find out if state is accessed using some concurrency/locking mechanism. Also, the assumption that I have made that fields set by Spring setters are immutable holds true only by coding convention – it shouldn’t be unilaterally assumed.


  3. Very good resource. Make Home Page!


  4. Порно


  5. Man .. Excellent .. Amazing .. I will bookmark your website and take the feeds additionallyI’m glad to search out a lot of useful info right here in the publish, we need develop more techniques in this regard, thanks for sharing. . . . . .



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: