简体   繁体   中英

Alternate method of BeanInfo creation?

I recently moved my spring application from java 1.6 to java 1.8. This has caused the spring bootstrapping to take an order of magnitude longer (20s before, 4mins now). Tracing the cause has led me to the CachedIntrospectionResults class, which is created for every bean. When created it calls,

beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
                        Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
                        Introspector.getBeanInfo(beanClass));

Introspector then creates the bean info, in java 1.6 , it calls

 private BeanDescriptor getTargetBeanDescriptor() {
    // Use explicit info, if available,
    if (explicitBeanInfo != null) {
        BeanDescriptor bd = explicitBeanInfo.getBeanDescriptor();
        if (bd != null) {
            return (bd);
        }
    }
    // OK, fabricate a default BeanDescriptor.
    return new BeanDescriptor(this.beanClass);
}

However in java 1.8 it now calls,

private BeanDescriptor getTargetBeanDescriptor() {
    // Use explicit info, if available,
    if (explicitBeanInfo != null) {
        BeanDescriptor bd = explicitBeanInfo.getBeanDescriptor();
        if (bd != null) {
            return (bd);
        }
    }
    // OK, fabricate a default BeanDescriptor.
    return new BeanDescriptor(this.beanClass, findCustomizerClass(this.beanClass));
}
private static Class<?> findCustomizerClass(Class<?> type) {
    String name = type.getName() + "Customizer";
    try {
        type = ClassFinder.findClass(name, type.getClassLoader());
        // Each customizer should inherit java.awt.Component and implement java.beans.Customizer
        // according to the section 9.3 of JavaBeans&trade; specification
        if (Component.class.isAssignableFrom(type) && Customizer.class.isAssignableFrom(type)) {
            return type;
        }
    }
    catch (Exception exception) {
        // ignore any exceptions
    }
    return null;
}

This method as far as I can see was added with java 1.7, and since I don't define any customizer classes, it searches my full classpath then throws an exception which ends up taking a few hundred ms. The result being that each bean takes ~500ms to init. A huge hit to startup time.

I am now trying to find a way to work around this problem,

The spring documentation says to implement a BeanInfoFactory in order to customize the beanInfo creation. But I can't find anywhere that says how to actaually create BeanInfo for a provided class.

How would I actually do that? Introspector uses a bunch of private constructors to build it up so I can't really follow it, and simply returning an empty BeanInfo blows spring up. What does spring actually want with the beaninfo?

Any ideas?

Normally, when you provide an explicit BeanInfo , the Introspector will gather information automatically whenever the explicit BeanInfo returns null . So there should be no problem providing an empty BeanInfo that only returns a non- null BeanDescriptor to prohibit the automatic Customizer search.

For example:

import java.beans.*;
import java.util.stream.Stream;

public class BeanInfoTest {
    public static void main(String... arg) throws IntrospectionException {
        BeanInfo bi=Introspector.getBeanInfo(TheComponent.class, Object.class);
        System.out.println("properties: ");
        Stream.of(bi.getPropertyDescriptors())
              .map(p->p.getPropertyType().getSimpleName()+' '+p.getName())
              .forEach(System.out::println);
    }
    public static class TheComponent {
        String foo;
        int bar;
        public String getFoo() {
            return foo;
        }
        public void setFoo(String foo) {
            this.foo = foo;
        }
        public int getBar() {
            return bar;
        }
        public void setBar(int bar) {
            this.bar = bar;
        }
    }
    public static class TheComponentBeanInfo extends SimpleBeanInfo {

        /** Overridden to prevent the automated search for a Customizer */
        @Override
        public BeanDescriptor getBeanDescriptor() {
            System.out.println("Providing my explicit BeanDescriptor");
            return new BeanDescriptor(TheComponent.class);
        }
    }
}

will print

Providing my explicit BeanDescriptor
properties: 
int bar
String foo

So it found the properties using automated search while using the explicit BeanDescriptor .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM