SpringBoot -- underlying annotation

preface

This article records the process of learning the SpringBoot framework.

Official website: Spring | Home

edition:

  • Maven: 3.6.1
  • JDK: 1.8
  • SpringBoot: 2.3.4

Project construction:

Create a maven project:

pom.xml configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>helloworld</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

MainApplication main program class:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);
    }
}

Pet class:

public class Pet {

    private String name;

    public Pet() {
    }

    public Pet(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Pet{" +
                "name='" + name + '\'' +
                '}';
    }
}

User class:

public class User {

    private String name;
    private Integer age;

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Bottom annotation

@Configuration

Used to configure class declarations.

Create the configuration class MyConfig in src/main/java/boot/config Directory:

import org.springframework.context.annotation.Configuration;

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

}

explain:

  • Full(proxyBeanMethods = true): how many times each @ Bean method is called and the returned component is guaranteed to be single instance (true by default if not written)
  • Lite(proxyBeanMethods = false): how many times each @ Bean method is called, and the returned component is newly created

@Bean

Register components in the container

Write configuration class MyConfig:

import boot.bean.Pet;
import boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {

    @Bean  //Add components to the container. Take the method name as the id of the component, the return type is the component type, and the returned object is the instance of the component in the container
    public User user01() {
        return new User("zhangsan",18);
    }

    @Bean("tom")  //Specify component id
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

explain:

  • @Bean is written in front of the method to add components to the container (single instance by default). Take the method name as the id of the component; The return type is the component type; The returned object is the instance of the component in the container
  • @Bean("xxx") can specify the component id

MainApplication, main test program:

import boot.bean.Pet;
import boot.bean.User;
import boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApplication {

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

        //2. View the components in the container
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        //3. Get components from container
        User user01 = run.getBean("user01", User.class);
        Pet tom01 = run.getBean("tom", Pet.class);
        Pet tom02 = run.getBean("tom", Pet.class);

        System.out.println("Components:" + user01);
        System.out.println("Components:" + tom01);
        System.out.println("Components:" + tom02);
        System.out.println("Components:" + (tom01 == tom02));
    }
}

The results are as follows:

The configuration class itself is also a component

Write the main program MainApplication:

import boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        //Return to IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);

        //Get component from container
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);
    }
}

The results are as follows:

Component dependency

@The proxyBeanMethods parameter in the Configuration annotation is mainly used in the scenario of component dependency.

Modify the User class, add the Pet variable, and override the getter(), setter() and toString() methods:

public class User {

    private String name;
    private Integer age;
    private 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;
    }

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", pet=" + pet +
                '}';
    }
}

Write configuration class MyConfig:

import boot.bean.Pet;
import boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = true)
public class MyConfig {

    @Bean
    public User user01() {
        User zhangsan = new User("zhangsan",18);
        zhangsan.setPet(tomcatPet());  //Call tomcatPet() component
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

Write the main program MainApplication:

import boot.bean.Pet;
import boot.bean.User;
import boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        //Return to IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);

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

        System.out.println("User's pet:" + (user01.getPet() == tom));

    }
}

Run the main program. If proxyBeanMethods = true, the results are as follows:

User's pet: true

If proxyBeanMethods = false, the result is as follows:

User's pet: false

explain:

  • The difference between single case mode and multi case mode
  • If true, the component will directly create an instance in the container, and other components can directly use the instance
  • false is recommended if one component does not depend on another. Component dependencies will not be scanned at startup, which is faster

Original annotation

annotation

explain

@Component

Used on classes to instantiate beans

@Controller

Used on web tier classes to instantiate beans

@Service

Used on the service layer class to instantiate beans

@Repository

Used on dao layer classes to instantiate beans

@ComponentScan

Used to specify the package that Spring will scan when initializing the container

The original annotations shown in the above table can also be used.

@Import

Add this annotation on the class of any component to import the specified component (the parameter is an array, and multiple components can be imported)

Write configuration class MyConfig:

import boot.bean.Pet;
import boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({User.class})  //Import User component
@Configuration(proxyBeanMethods = true)
public class MyConfig {

    @Bean
    public User user01() {
        User zhangsan = new User("zhangsan",18);
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

Write the main program MainApplication:

package boot;

import boot.bean.Pet;
import boot.bean.User;
import boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

// Main program class
// @Springboot application: This is a springboot application
@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);

        String[] beanNamesForType = run.getBeanNamesForType(User.class);
        System.out.println("====");
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
    }
}

The results are as follows:

Note: the default component name is the full class name

@Conditional

Only when the conditions specified in Conditional are met can component injection be carried out.

Conditional also derives many annotations, as shown in the following figure:

Take @ ConditionalOnBean as an example:

Write configuration class MyConfig:

import boot.bean.Pet;
import boot.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({User.class})
@Configuration(proxyBeanMethods = true)
public class MyConfig {

    @Bean
    public User user01() {
        User zhangsan = new User("zhangsan",18);
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @ConditionalOnBean(name = "user01")  //If the component named user01 is used, the tom component can be registered
    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

Write the main program MainApplication:

import boot.bean.Pet;
import boot.bean.User;
import boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);

        boolean tom = run.containsBean("tom");
        System.out.println("In container tom Components:" + tom);

        boolean user01 = run.containsBean("user01");
        System.out.println("In container user01 Components:" + user01);

    }
}

The test results are as follows:

If the user01 component will not be registered, the user component will not be registered

import boot.bean.Pet;
import boot.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({User.class})
@Configuration(proxyBeanMethods = true)
public class MyConfig {

    //@Bean
    public User user01() {
        User zhangsan = new User("zhangsan",18);
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @ConditionalOnBean(name = "user01")  //If the component named user01 is used, the tom component can be registered
    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

Note: pay attention to the registration sequence of components, otherwise it may become invalid

@ImportResource

Native xml configuration files can be introduced. Add this annotation on the configuration class:

@ImportResource("classpath:xxx")

Configure binding

Use Java to read the content in the properties file and package it into JavaBean s (bind the content of the configuration file to the component). You can use the annotation @ ConfigurationProperties.

There are two binding methods:

Postscript

Dig a hole and remind to see the source code.

Added by remmargorp on Thu, 17 Feb 2022 11:12:24 +0200