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:
- ApplicationBeanInfo: Apple Desktop-related JavaBean introspection results
- ComponentBeanInfo: Introspective results of Java Awt components, such as buttons, etc
- 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!