Java BeanInfo is not used in my work. When I was learning spring source code, I found that SpringBoot will set a genus named “spring.beaninfo.ignore”. This configuration is only available on the web, which means it skipped the Java BeanInfo search and didn’t find anything else, but what is BeanInfo?

JavaBean is introduced

JavaBeans are special classes in Java that encapsulate multiple objects into a single object (bean). It is serializable, provides a no-argument constructor, and provides getters and setters to access properties of objects. The “Bean” in the name is the common name for a reusable software component for Java. To be a JavaBean class, you must follow specific specifications for naming, constructors, and methods. With these specifications, there are tools that can be used, reused, replaced, and connected to JavaBeans. The specification is as follows:

  • There is a public no-argument constructor.
  • Properties can be accessed through get, set, is (which can be used for Boolean properties instead of GET), or other methods that follow a specific naming convention.
  • Serializable.

The following is the definition of a valid JavaBean:

public class PersonBean implements java.io.Serializable {

    /** * name attribute (case sensitive) */
    private String name = null;

    private boolean deceased = false;

    /** No argument constructor */
    public PersonBean(a) {}/** * the Getter method for the name property */
    public String getName(a) {
        return name;
    }

    /** * Setter method * for the name property@param value
     */
    public void setName(final String value) {
        name = value;
    }

    /** * Getter methods for the deceased property * Different forms of Getter methods for the Boolean property (here is used instead of get) */
    public boolean isDeceased(a) {
        return deceased;
    }

    /** * The Setter method for the deceased property *@param value
     */
    public void setDeceased(final boolean value) { deceased = value; }}Copy the code

JavaBean introspection

To illustrate the JavaBean introspection, use a simple SpringMVC user login scenario, where the front end form usually passes a Json string like this:

{
	"username":"xxx"."password":"xxxx"
}
Copy the code

Where the back end accepts forms, it is usually possible to use a JavaBean to receive arguments in the form of a RequestBody:

public void login(@RequestBody LoginRequest request){
     // Do login
}
Copy the code

LoginRequest is similar to the following format:

public class LoginRequest {
    public String getUsername(a) {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword(a) {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    private String username;
    private String password;
}
Copy the code

So how does the front-end Json map to the corresponding properties in the back-end LoginRequest? You can see that the fields in the LoginRequest are private. You cannot set the fields directly (reflection can be set, but it is not appropriate). You can only set the fields through Setter methods. This is where the Introspection mechanism of Javabeans is used.

The JavaBean Introspector tool

Introspector, a Java Introspector tool, is provided in the Java Bean toolkit. This tool can obtain the introspection result of a Java bean BeanInfo (described later) by using the following methods. The process for obtaining BeanInfo is shown in the following figure

// Stop the retrieval in the Object class. You can choose to stop the retrieval in any parent class
BeanInfo beanInfo = Introspector.getBeanInfo(JavaBeanDemo.class,Object.class);
Copy the code

JavaBean introspection result BeanInfo

We can obtain a JavaBean introspection BeanInfo through the getBeanInfo method of Java Introspector. The obtained BeanInfo contains the following attributes:

  • Class-related information about the Bean
  • Event information for the Bean
  • Bean property information
  • Bean method information
  • Additional attribute information
  • Component of the icon

Type of introspection result BeanInfo

BeanInfo is just an introspective result interface, and there are three implementations of this interface in Java:

  1. ApplicationBeanInfo: Apple Desktop-related JavaBean introspection results
  2. ComponentBeanInfo: Introspective results of Java Awt components, such as buttons, etc
  3. GenericBeanInfo: Generic introspection result, of this type in JEE development

In addition, Spring has a custom introspection result type called ExtendedBeanInfo, which is primarily used to identify Setter methods that do not return a null value.

Spring’s BeanUtils copyProperties

Beanutils.copyproperties users copyProperties between two objects. Based on the introspection mechanism of JavaBean, they obtain the read and write methods of the properties of the source and destination objects through introspection, and then call the corresponding methods to copy the properties. The following is the flow of beanutils.copyProperties

BeanUtils optimizes some of the mechanics of Introspection in Javabeans. So far, have you noticed some shortcomings of Introspection in Java?

BeanUtils concurrency problem optimization

The results of Java introspection are cached in ThreadGroupContext, and the cache is locked by the Synchonrized keyword (shown in the red box below), preventing threads in the same thread group from introspecting in parallel.

Spring’s BeanUtils adds a layer of caching on top of Java introspection, implemented using ConcurrentHashMap, which improves introspection.

BeanUtils Setter property recognition optimization

In Java’s default introspection process, the return value of setter methods must be NULL. If it is not NULL, it is not recognized as a valid JavaBean property (shown in red below). Spring has a custom BeanInfo ExtendedBeanInfo to address this problem.

spring.beaninfo.ignore

Going back to the original spring.beaninfo.ignore, this configuration is used to ignore all custom beaninfo class searches.

BeanUtils performance test

Copy the method 10,000 replication times 1 million replication times 100 million replication times
ModelMapper copy 262mills 3875mills 283177mills
BeanUtils copy 3mills 369mills 20347mills
Direct copy Mills is approximately equal to 0 5mills 438mills

As you can see, BeanUtils takes about 50 times more time than direct replication.

public class BeanUtilsPerformanceTest {

    public static void main(String[] args){
        // Preheat the VM
        loopBeanUtils(100000);
        loopCopyByHand(100000);

        // Copy 10,000 times
        System.out.println("\nloop 10000 times:");
        loopBeanUtils(10000);
        loopCopyByHand(10000);

        // Copy 1 million times
        System.out.println("\nloop 1000000 times:");
        loopBeanUtils(1000000);
        loopCopyByHand(1000000);

        // Copy 100 million times
        System.out.println("\nloop 100000000 times:");
        loopBeanUtils(100000000);
        loopCopyByHand(100000000);
    }

    private static void loopBeanUtils(int loopTimes){
        TestBeanDemo source = new TestBeanDemo();
        TestBeanDemo target = new TestBeanDemo();
        long start = System.currentTimeMillis();
        for (int i=0; i<loopTimes; i++){ BeanUtils.copyProperties(source,target); } System.out.println("BeanUtils cost times:"+String.valueOf(System.currentTimeMillis()-start));
    }

    private static void loopCopyByHand(int loopTimes){
        TestBeanDemo source = new TestBeanDemo();
        TestBeanDemo target = new TestBeanDemo();
        long start = System.currentTimeMillis();
        for (int i=0; i<loopTimes; i++){ target.setField1(source.getField1()); target.setField2(source.getField2()); target.setField3(source.getField3()); target.setField4(source.getField4()); target.setField5(source.getField5()); } System.out.println("Copy field one by one times:"+String.valueOf(System.currentTimeMillis()-start));
    }

    @Data
    private static class TestBeanDemo{
        private String field1 = UUID.randomUUID().toString();
        private String field2 = UUID.randomUUID().toString();
        private String field3 = UUID.randomUUID().toString();
        private String field4 = UUID.randomUUID().toString();
        privateString field5 = UUID.randomUUID().toString(); }}Copy the code

I am the god of the royal Fox. Welcome to follow my wechat official account: Wzm2ZSD

This article was first published to wechat public account, all rights reserved, reprint prohibited!