On Sat, 1 Sep 2001, Elli Albek wrote:

> Date: Sat, 1 Sep 2001 04:42:23 -0700
> From: Elli Albek <[EMAIL PROTECTED]>
> Reply-To: [EMAIL PROTECTED]
> To: [EMAIL PROTECTED]
> Subject: BeanUtils and class loading + EJB comment
>
> Oops, forgot the plain text.
>
> The beanutils package does not contain any notion of dynamic class loading.
> It is very possible that in an application the beanutils package will be in
> a class loader that is a parent of the beans that it loads.
> In that case, there can potentially be more than one instance of the same
> bean class (coming from different child class loaders).
> Also when the classes are reloading (by replacing the child class loaders),
> the cache still contains instances of the old Class objects.
> This prevents garbage collection of the old class loader. It cannot be
> garbage collected unless all its classes are freed.
>

Thanks for this patch!  I committed a slight variation of it, by making
the descriptor cache itself keyed by the class loader, so that entries for
the same class name loaded by different class loaders are distinct.  I
also added two vaiations of the clear method:

  public static void clearDescriptors();

  public static void clearDescriptors(ClassLoader loader);

so that you can clear all cached descriptors, or only those for the
particular class loader that you are going to throw away.  Using the
latter method can save you some overhead of re-introspecting bean classes
you are *not* reloading.

> As a minimum, the descriptor cache (PropertyUtils.descriptorsCache) should
> use the Class object of the bean as the key to the table and not the name of
> the class (which is a String). There also must be an API function to clear
> the cache, so advanced users can synchronize it with their class loading
> (Doesn't tomcat have similar problem?)
>

Most uses of Beanutils in web apps have been where the BeanUtils classes
themselves, and all the application classes, are loaded by the (single)
web app class loader for that application.  (In other words,
common-beanutils.jar would be placed inside /WEB-INF/lib instead of being
global to the container).  When the servlet container reloaded the app, it
therefore reloaded PropertyUtils as well (which effectively flushed the
previous contents).

Your suggested changes now make it possible to place commons-beanutils.jar
in a public class loader that is not itself thrown away, as long as web
apps do something like what you suggest for EJB applications (a single
call to PropertyUtils.clearDescriptors() somewhere in the webapp).

Craig McClanahan


> I added another advice for EJB users at the end.
>
> The code can be something like:
>
> // In PropertyUtils:
>
>     public static void clear() {
>         descriptorsCache.clear();
>         mappedDescriptorsCache.clear();
>     }
>
>     public static PropertyDescriptor[] getPropertyDescriptors(Object bean) {
>
>       if (bean == null)
>             throw new IllegalArgumentException("No bean specified");
>
>       // Look up any cached descriptors for this bean class
>       PropertyDescriptor descriptors[] = null;
>         descriptors =
>             (PropertyDescriptor[]) descriptorsCache.get(bean.getClass());
>       if (descriptors != null)
>           return (descriptors);
>
>       // Introspect the bean and cache the generated descriptors
>       BeanInfo beanInfo = null;
>       try {
>           beanInfo = Introspector.getBeanInfo(bean.getClass());
>       } catch (IntrospectionException e) {
>           return (new PropertyDescriptor[0]);
>       }
>       descriptors = beanInfo.getPropertyDescriptors();
>       if (descriptors == null)
>           descriptors = new PropertyDescriptor[0];
>         descriptorsCache.put(bean.getClass(), descriptors);
>       return (descriptors);
>
>     }
>
> EJB users that have a class deployed in more than one JAR (and therefore
> more than one instance in the VM) can try that:
> First, do the code change above. This is supposed to work, but still have a
> potential memory leak for not garbage collecting the ClassLoader objects
> (they can be very big).
> Since the classes will be loaded more than once, every time a new class
> loader will load them it will invoke the static initializers.
> You can put in ONE of your EJB classes a static initializer that will get
> the cache hashtable and clear it.
>
> class MyBean implements javax.ejb. .... {
>
>     static{
>         PropertyUtils.clear();
>     }
> // other EJB functions
> }
>
> Make sure that this happens once per jar. Meaning, if your JAR contains 10
> EJBs, only one class should have this static block.
> I did not try that, so this is just a suggestion.
>
> E
>

Reply via email to