1. @Configuration annotations added to the SpringBoot component

1.1. The @Configuration annotation is basically used

The project structure

1. Add two components, a User component and a Pet component

The User class:

package com.lemon.boot.bean;

/ * * *@Author Lemons
 * @createThe 2022-03-07-18:55 * /
public class User {
    private String name;
    private Integer age;

    public User(a){}public User(String name,Integer age){
        this.name = name;
        this.age = age;
    }

    public String getName(a){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }

    public Integer getAge(a){
        return age;
    }

    public void setAge(Integer age){
        this.age = age; }}Copy the code

Pet class

package com.lemon.boot.bean;

/ * * *@Author Lemons
 * @createThe 2022-03-07-18:54 * /
public class Pet {
    private String name;
    public Pet(a){}public Pet(String name){
        this.name = name;
    }


    public String getName(a){
        return name;
    }

    public void setName(String name){
        this.name = name; }}Copy the code

2. Now add these two components to the container in the original native Spring way:

Beans.xml = beans.xml; beans.xml = beans.xml

(2) The previous Spring XML configuration method: use bean tags to add user and PET components to the container, where you can add attributes to the components;


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "user01" class="com.lemon.boot.bean.User">
        <property name = "name" value="Xiao Ming"></property>
        <property name = "age" value="19"></property>
    </bean>

    <bean id = "pet01" class="com.lemon.boot.bean.Pet">
        <property name = "name" value="Fake sophistication"></property>
    </bean>
</beans>
Copy the code

(3) SpringBoot does not write XML configuration files. SpringBoot can use @configuration annotations at the bottom: Create a class and use this annotation at the top of the class. This annotation tells SpringBoot that this is a configuration class, equivalent to the previous configuration file. Instead of adding components to the container using bean tags, we now construct them using methods with @bean annotations at the top, the method name as the component ID, the return type as the component type, and the value (object) returned by the method as the instance of the component in the container.

This class is defined as Myconfig and is placed in the Config package of the main program

@Configuration // Tell SpringBoot that this is a configuration class == configuration file
public class MyConfig {
	// Add a component to the container, using the normal name as the component id,
    The return type is the component type, and the value (object) returned by the method is the instance of the component in the container
    @Bean 
    public User user01(a){
        return new User("Xiao Ming".18);
    }
	// If you do not want the method name to be the component name ID, you can also give a custom name directly in the Bean label
    @Bean("jialaolian") 
    public Pet pet01(a){
        return new Pet("Fake sophistication"); }}Copy the code

④ Verify that there are two components in the container:

  • MainApplication startup class:
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        //2. The container contains all the components of our current application,
        // Check the components in the container, as long as there is our component, the component will work, that is the principle
        String[] names = run. getBeanDefinitionNames();// Get the names of all our component definitions;
        for(String name : names) { System.out.println(name); }}}Copy the code

Run the main program and the result is: you can see that both components exist in the container

(5) The @bean annotation is used in the configuration class to register components in the container method. The default is singleton. This is the same as in the native Spring.

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        //2. The container contains all the components of our current application,
        // Check the components in the container, as long as there is our component, the component will work, that is the principle
        String[] names = run. getBeanDefinitionNames();// Get the names of all our component definitions;
        for (String name : names) {
            System.out.println(name);
        }

        // Get components from the container multiple times
        Pet Caty01 = run.getBean("jialaolian",Pet.class);
        Pet Caty02 = run.getBean("jialaolian",Pet.class);

        System.out.println("Component:"+(Caty01 == Caty02)); // Check whether the component is singleton}}Copy the code

The results of

Components: true,Copy the code

The @configuration class MyConfig is also a component. The Configuration class is also a component in the container.

// Get the MyConfig class object in the container
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
Copy the code

Result: The configuration class is a proxy object generated by CGLIB

com.lemon.boot.Config.MyConfig$$EnhancerBySpringCGLIB$$a3d18d30@61efae4d
Copy the code

1.2. @Configuration annotation source code

1, annotated source code:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor( annotation = Component.class )
    String value(a) default "";
	// Proxy Bean methods
    boolean proxyBeanMethods(a) default true;
}
Copy the code

The Configuration class has a proxyBeanMethods attribute, which defaults to true. This is different from SpringBoot1.0.

2. Now we use this property in our custom configuration class myConfig.class

@Configuration(proxyBeanMethods = true) // Tell SpringBoot that this is a configuration class == configuration file
public class MyConfig {

    @Bean // Add a component to the container, with the normal name as the component ID, the return type as the component type, and the value (object) returned by the method as the instance of the component in the container
    public User user01(a){
        return new User("Xiao Ming".18);
    }

    @Bean("jialaolian") // If you do not want the method name as the component name ID, you can also give a custom name in the Bean tag
    public Pet pet01(a){
        return new Pet("Fake sophistication"); }}Copy the code

The user01 method is called multiple times in MyConfig. Is the object returned by the method taken from the container or is it just a normal method? The verification is as follows:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args){
        // Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        
        // Get the MyConfig class object in the container
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

        // Call the user01 method multiple times in MyConfigUser user = bean.user01(); User user1 = bean.user01(); System.out.println(user == user1); }}Copy the code

The results are as follows:”

true
Copy the code

This means that no matter how many times the external calls are made to the component registration method in the configuration class, it is getting the singleton that was previously registered in the container. @configuration (proxyBeanMethods = true). MyConfig is not a normal object. MyConfig$$EnhancerBySpringCGLIB is actually a proxy object enhanced by SpringCGLIB, that is, we get the proxy object, the proxy object calls user01, The default logic in SpringBoot is that if @Configuration(proxyBeanMethods = True), our class (MyConfig), what we get is the proxy object, the proxy object calls the method, By default, SpringBoot checks the container for components that have already been returned by this method, and if so, retrieves them from the cache, leaving them singleton.

3. If the proxyBeanMethods attribute is changed to false, the running result will be false, which proves that the obtained MyConfig is no longer a proxy object, and the same instance is not obtained by calling the method for many times, that is to say, a new object will be created each time calling the method.

Note: changes to false after SpringBoot5.2 will be marked in red, but will not affect application execution

1.3. Full Mode and Lite Mode

SpringBoot has two configurations in the underlying Configuration:

  • Full Configuration mode (@Configuration(proxyBeanMethods = true) ensures that each @bean method is called how many times and returns a single instance of the component;
  • Lite Lightweight Configuration mode (@Configuration(proxyBeanMethods = false) How many times each @Bean method is called returns components that are newly created.

1.3.1. Component dependencies

The above two patterns easily solve the problem of component dependency, for example, users have pets:

  • Modify the User. The class

       ```java
    Copy the code

public class User { private String name; private Integer age; private Pet pet; // Add pet attributes

Public Pet getPet(){// Provide get/set return Pet; } public void setPet(Pet pet){ this.pet = pet; } public User(){ } public User(String name,Integer age){ this.name = name; this.age = age; } public String getName(){ return name; } public void setName(String name){ this.name = name; } public Integer getAge(){ return age; } public void setAge(Integer age){ this.age = age; }Copy the code

} ` ` `

  • Myconfig. class: Set to Full configuration mode
@Configuration(proxyBeanMethods = true)
public class MyConfig {
    
 @Bean
    public User user01(a){
        User zhangsan = new User("zhangsan".18);
        // The User component depends on the Pet component
        zhangsan.setPet(Cat());
        return zhangsan;
    }

    @Bean("jialaolian")   //@bean adds components to the container
    public Pet Cat(a){
        return new Pet("Fake sophistication"); }}Copy the code
  • MainApplication.class
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args){
        // Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        User user01 = run.getBean("user01",User.class);
        Pet jialaolian = run.getBean("jialaolian",Pet.class);

        System.out.println("Is the pet in the container the same as the pet obtained by calling the method:"+(user01.getPet() == jialaolian)); }}Copy the code

The results show that the user’s pet is the pet in the container

Whether the pet in the container is the same as the pet in the calling method: : trueCopy the code

If proxyBeanMethods = true is changed to false, the running result indicates that the user’s pet is not a pet in the container

Is the pet in the container the same as the pet from calling the method:false
Copy the code

1.3.2 Usage scenarios of the two modes

  • Configure class components without dependencies. Use Lite mode to speed up the container startup process and reduce judgment. ** Create a new build using Lite, because it’s not in the container and doesn’t need to be checked

  • Config class components have dependencies between them. Methods are called to retrieve previously singleton components. Beans can be quickly retrieved, reducing the cost of newly generated instances, reducing JVM garbage collection, and using Full mode.

  • For example, in the user class, the Cat class is an attribute of the user class, so there is a dependency between the user and Cat class

1.4. Summary and matters needing attention

Full mode and Lite mode note the following: Full mode and Lite mode are specific to Spring configuration, not XML configuration.

When to use Lite mode:

  • The class has the @Component annotation
  • There is an @ComponentScan annotation on the class
  • There is an @import annotation on the class
  • There is an @importResource annotation on the class
  • There are no annotations on the class, but there are @Bean methods in the class
  • Class with @Configuration(proxyBeanMethods = false) annotation

Lite summary: The runtime does not need to generate CGLIB subclasses, which improves performance and reduces startup time. It can be used as a common class. But you cannot declare dependencies between @beans

When is Full mode:

  • With a@Configurationor@Configuration(proxyBeanMethods = true)The class is called the configuration class in Full mode.

Summary: Singleton mode can effectively avoid errors in Lite mode, and the performance is not as good as Lite mode

2. @import annotations added by the SpringBoot component

1. Components register additional annotations

In the previous section, we learned about the @Configuration annotation at the bottom of SpringBoot and combined it with the @bean annotation to demonstrate how to add components to SpringBoot. This annotation allows us to understand how to add components to SpringBoot. In addition to these annotations, Annotations like @bean, @Component, @Controller, @Service, and @Repository from previous native Spring can also be used to register components into containers as long as the package scan is correct

Such as @ Bean:

// Add a component to the container. The default component id is the square name, the return type is the component type, and the create object is the instance
@Bean
public User user01(a) {
    return new User("zhangsan".19);
}
Copy the code

Let’s briefly explain what these notes do:

  • The @bean adds a component to the container. By default, the name of the component is the component id, the return type is the component type, and the object is the instance, similar to spring
  • @Component means a Component
  • @Controller indicates a Controller
  • @service represents a business logic component
  • The @repository representation is a database-level component
  • The use of these annotations is the same as before

The @import annotation imports the component

The @import annotation can be used on any component or configuration class to automatically create the component it declares. The component name defaults to the relative path of the class (full class name) : the underlying annotation is an array, so the annotation can write multiple types

Use @import in the MyConfig class

@Import({User.class})
@Configuration // Tell SpringBoot that this is a configuration class == configuration file
public class MyConfig {
	// Add a component to the container, using the normal name as the component id,
    The return type is the component type, and the value (object) returned by the method is the instance of the component in the container
    @Bean 
    public User user01(a){
        return new User("Xiao Ming".18);
    }
	// If you do not want the method name to be the component name ID, you can also give a custom name directly in the Bean label
    @Bean("jialaolian") 
    public Pet pet01(a){
        return new Pet("Fake sophistication"); }}Copy the code

Get a component of type User automatically generated using @import in the main startup class:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
     	// Get components by type
        String[] names = run.getBeanNamesForType(User.class);
        for(String name : names) { System.out.println(name); }}}Copy the code

The results of

com.lemon.boot.bean.User
user01
Copy the code

Explanation: Why are there two component objects of type User?

  • The first component is calledcom.lemon.boot.bean.UserThe component is us@importThe name of the component added to the container by annotation defaults to the relative path of the class (full class name).
  • The second component: is what we use@BeanAnnotations added to the container default to the element name as the component ID,So there are two ways to create components

3, @Conditional Conditional annotation

Conditional assembly note: Component injection occurs when the conditions specified in Conditional are met

  • When the container meets the conditions, the components in the configuration class will take effect.
  • When put on the configuration method, it means that the configuration method takes effect only when the conditions are met.

The @conditionalonbean annotation is a root annotation, from which many new annotations are derived, as shown below: different annotations have different functions, so let’s illustrate @conditionalonbean

Presentation:

First remove the @bean (” Jialaolian “) from MyConfig and make the cat() method a normal one, so we can’t create jialaolian in the container. Then the main program was tested: it didn’t, of course

// Check whether the container contains the pet component
boolean pet = run.containsBean("jialaolian"); //false
System.out.println("Are there PET components?"+ pet);
Copy the code

Of course we have the user01 component, but now suppose we set the user01 component to register with the container only if jialaolian is present: use the following method

@Configuration
public class MyConfig {
    
    // This method takes effect only if there is a component named Jialaolian and the user01 component is injected
    @ConditionalOnBean(name="jialaolian" )
    @Bean 
    public User user01(a){
        return new User("Xiao Ming".18);
    }

    public Pet pet01(a){
        return new Pet("Fake sophistication"); }}Copy the code

Test: get user01 object, program has no output, can not get the object

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // Get components by type
        String[] names = run.getBeanNamesForType(User.class);
        for(String name : names) { System.out.println(name); }}}Copy the code

Labeling @conditionalonBean ona class indicates that this condition must be met for all code in the class to be in effect

@Import({User.class})
@Configuration
@ConditionalOnBean(name = "pet")
public class MyConfig {

    // The following code takes effect only if there is a component named PET
    @Bean
    public User user01(a) {
        return new User("zhangsan".19);
    }

    @Bean("pet22")
    public Pet cat(a) {
        return new Pet("tomcat"); }}Copy the code

Test: No results obtained

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        boolean user = run.containsBean("user01");//false
        System.out.print1n("User01 component in container :"+ user);

        boolean tom22 = run.containsBean("pet22");//false
        System.out.print1n("Pet22 component in container :"+ tom22); }}Copy the code

4, springBoot native configuration file import: @importResource annotation

Steps:

  • To the nativeSpring.xmlThe configuration file is passed@ImportResourceThe importSpringBootParses and registers corresponding components
  • Annotation position: above a configuration class
  • Parameters: Enter the classpath of the configuration file you want to import

Demo: The native configuration file beans.xml is as follows: in classpath classpath: resource


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "user22" class="com.lemon.boot.bean.User">
        <property name = "name" value="Xiao Ming"></property>
        <property name = "age" value="19"></property>
    </bean>

    <bean id = "pet33" class="com.lemon.boot.bean.Pet">
        <property name = "name" value="Fake sophistication"></property>
    </bean>
</beans>
Copy the code

This way of using native XML is definitely not in the container of the two components we created [validation in the main program launch class], but for example, some old projects are written with these native configuration files, you need to convert to the annotation form according to the SpringBoot format, one by one migration is too cumbersome. You can import resources directly by using the @importResource annotation directly above the configuration class

Testing:

The configuration class

@ImportResource("classpath:beans.xml") // Import the native XML file
@Import({User.class})
@Configuration
@ConditionalOnMissingBean(name = "pet")
public class MyConfig {

    // The following code takes effect only when a component named PET does not exist
    @Bean
    public User user01(a) {
        return new User("zhangsan".19);
    }

    @Bean("pet22")
    public Pet cat(a) {
        return new Pet("tomcat"); }}Copy the code

The main launch class tests:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        boolean user = run.containsBean("user01");//true
        System.out.println("User01 component in container :"+ user);

        boolean tom22 = run.containsBean("pet22");//true
        System.out.println("Pet22 component in container :"+ tom22);

        boolean user22 =run.containsBean("user22");
        boolean pet33 = run.containsBean("pet33");
        System.out.println( "user22: "+user22);//true
        System.out.println("pet33:" + pet33);//true}}Copy the code

5. Configure binding –@ConfigurationProperties

How to use Java to read into the properties file and encapsulate it into a JavaBean for ready use; For example, connect to mysql

Previously this operation was required:

In SpringBoot, it becomes very simple as follows:

5.1. Mode 1: @Component + @ConfigurationProperties

Define a Car class:

Note:

  • The created class CAR must be added to the container to take effect
  • Prefix must be lowercase
// Only components in a container have the power provided by SpringBoot
@Component //Component indicates a Component
@ConfigurationProperties(prefix = "mycar")// Specify attributes to match values starting with a prefix in the configuration file
public class Car {
    private String brand;
    private Integer price;
    // Provide get/set/toString methods
}
Copy the code

The corresponding configuration file: appliction.properties file under resource, which contains the following contents

mycar.brand=byd
mycar.price=100000
Copy the code

Start the class test to check whether the binding is successful:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        Car car = run.getBean(Car.class);
        System.out.println(car);//true}}Copy the code

Result: There is an object in the container

Car{brand=byd, price=100000}
Copy the code

Or test it this way: based on the above, enter through a browser

@RestController
public class HelloController {

    @Autowired  // Inject objects into the container
    Car car;

    @RequestMapping("/car")
    public Car hand02(a) {
        return car;
    }

    @RequestMapping("/hello2")
    public String hand01(a) {
        return "Hello world is so big!"; }}Copy the code

Results:

It can be seen from the two printing results:

  • We have created components in our container
  • It is also packaged into Javabeans

5.2, 2: @ EnableConfigurationProperties + @ ConfigurationProperties

Car class:

@ConfigurationProperties(prefix = "mycar")// Specify attributes to match values starting with a prefix in the configuration file
public class Car {
    private String brand;
    private Integer price;
    // Provide get/set/toString methods
}
Copy the code

Corresponding configuration file:

mycar.brand=byd
mycar.price=100000
Copy the code

Start classes use annotations @ EnableConfigurationProperties test see if binding success: :

//1. Enable the Car binding function
//2. Automatically register the CAR component with the container
@EnableConfigurationProperties(Car.class)
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        1. Return our IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        Car car = run.getBean(Car.class);
        System.out.println(car);//true}}Copy the code

Of course, we can also test this in the browser way described above, and this annotation can also be annotated on the configuration class (we usually also annotated on the configuration class), resulting in:

Summary: General usage method 2: This method can ensure that Chinese characters are not garbled