2. Bottom Notes

Keywords: Java Spring Spring Boot

2. Bottom Notes

2.1 Container function

2.1.1. @Configuration

2.2.1.1.Basic Use

User.java

package cn.com.springboot.demo.bean;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
 * User information.
 *
 * @author J
 */
@Setter
@Getter
@ToString
@NoArgsConstructor
public class User {

    /** Full name */
    private String name;

    /** Age */
    private String age;

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

Pet.java

package cn.com.springboot.demo.bean;

import lombok.*;

/**
 * Pet information.
 *
 * @author J
 */
@Setter
@Getter
@ToString
@NoArgsConstructor
public class Pet {

    /**
     * Varieties
     */
    private String breed;

    /**
     * Nickname?
     */
    private String petName;

    public Pet(String breed, String petName) {
        this.breed = breed;
        this.petName = petName;
    }
}

MyConfig01.java

package cn.com.springboot.demo.config;

import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * The first configuration class example.
 *
 * @author J
 */
@Configuration
public class MyConfig01 {

    /**
     * Declare a component with an ID of user01.
     */
    @Bean
    public User user01() {
        return new User("Zhang San", "27");
    }

    /**
     * Declare a component with an ID of myPet.
     */
    @Bean("myPet")
    public Pet pet01() {
        return new Pet("cat", "27");
    }
}

  • @Configuration: Tell spring-boot that this is a configuration class, which is a configuration file
  • @Bean: Register the method as a component and add it to the container
  • Component ID: The method name is the component ID of this component
  • Return value: component instance in container
  • @Bean("myPet"): Component with ID defined as myPet
  • The configuration class itself is a component
  • Registered component, single-instance by default

MainApp.java

package cn.com.springboot.demo;

import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {

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

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

        System.out.println(user01);
        System.out.println(myPet);
    }
}

Run Results

User(name=Zhang San, age=27)
Pet(breed=cat, petName=27)

2.2.1.2.Full Mode and Lightweight Mode

The @Configuration annotation has the following additional properties in spring-boot 2:

...
boolean proxyBeanMethods() default true;
...

The default value is true. If @Configuration(proxyBeanMethods = true), then the method is invoked using a proxy object. spring-boot always checks if the component exists in a container and returns it if it exists to guarantee a single instance of the component. If @Configuration(proxyBeanMethods = false), the above checks are skipped, and each time a component is called, a new component is returned.

  • Full Mode: proxyBeanMethods = true
    • Configured component If there is a dependency, method calls single-instance component
  • Lite Mode: proxyBeanMethods = false
    • Configured components without dependencies skip the checking process to speed up container startup

Sample Code

proxyBeanMethods = true:

MyConfig01.java

package cn.com.springboot.demo.config;

import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * The first configuration class example.
 *
 * @author J
 */
@Configuration(proxyBeanMethods = true)
public class MyConfig01 {

    /**
     * Declare a component with an ID of user01.
     */
    @Bean
    public User user01() {
        return new User("Zhang San", "27");
    }

    /**
     * Declare a component with an ID of myPet.
     */
    @Bean("myPet")
    public Pet pet01() {
        return new Pet("cat", "27");
    }
}

MainApp.java

package cn.com.springboot.demo;

import cn.com.springboot.demo.bean.User;
import cn.com.springboot.demo.config.MyConfig01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {

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

        // Testing Full Mode and Lite Mode for MyConfig01
        MyConfig01 bean = run.getBean(MyConfig01.class);
        User user01 = bean.user01();
        User user02 = bean.user01();
        System.out.println("Full Mode: " + (user01 == user02));
    }
}

Run Results

Full Mode: true

proxyBeanMethods = false:

MyConfig01.java

package cn.com.springboot.demo.config;

import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * The first configuration class example.
 *
 * @author J
 */
@Configuration(proxyBeanMethods = false)
public class MyConfig01 {

    /**
     * Declare a component with an ID of user01.
     */
    @Bean
    public User user01() {
        return new User("Zhang San", "27");
    }

    /**
     * Declare a component with an ID of myPet.
     */
    @Bean("myPet")
    public Pet pet01() {
        return new Pet("cat", "27");
    }
}

MainApp.java

package cn.com.springboot.demo;

import cn.com.springboot.demo.bean.User;
import cn.com.springboot.demo.config.MyConfig01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {

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

        // Testing Full Mode and Lite Mode for MyConfig01
        MyConfig01 bean = run.getBean(MyConfig01.class);
        User user01 = bean.user01();
        User user02 = bean.user01();
//        System.out.println("Full Mode: " + (user01 == user02));
        System.out.println("Lite Mode: " + (user01 == user02));
    }
}

Run Results

Lite Mode: false

2.2.1.3.Other notes of the same type

Notes previously used to register components can also be used, such as:

@Component          // A generic term for a component that is handed over to Spring management
@Controller         // Act on the controller and leave the component to Spring management
@Service            // Acts on a logical implementation class, handing it over to Spring management
@Repository         // Hand over the implementation class of the interface to Spring management on the interface that acts on the persistence layer
@ComponentScan      // Define package scan rules

2.1.2. @Import

2.2.1.1.Basic Use

Imports components of the specified type into a container by calling the parameterless construction of the specified class, which can be passed multiple arrays, such as:

Example

MyConfig01.java

package cn.com.springboot.demo.config;

/**
 * The second configuration class example.
 *
 * Demo@Import
 * @author J
 */

import ch.qos.logback.core.db.DBHelper;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({User.class, DBHelper.class})
@Configuration
public class MyConfig02 {}

MainApp.java

package cn.com.springboot.demo;

import ch.qos.logback.core.db.DBHelper;
import cn.com.springboot.demo.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.Arrays;

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {

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

        // Testing Full Mode and Lite Mode for MyConfig01
//        MyConfig01 bean = run.getBean(MyConfig01.class);
//        User user01 = bean.user01();
//        User user02 = bean.user01();
//        System.out.println("Full Mode: " + (user01 == user02));
//        System.out.println("Lite Mode: " + (user01 == user02));
//        System.out.println("---------------------------------------");

        String[] beans = run.getBeanNamesForType(User.class);
        Arrays.asList(beans).forEach(System.out::println);

        String[] beans2 = run.getBeanNamesForType(DBHelper.class);
        Arrays.asList(beans2).forEach(System.out::println);
    }
}

Run Results

cn.com.springboot.demo.bean.User
ch.qos.logback.core.db.DBHelper
  • Default name of @Import import component: full class name
    • Example: ch.qos.logback.core.db.DBHelper

2.1.3. @Conditional

Components are only injected into containers when certain conditions are met. @Conditional has many derived annotations, such as:

Derived Annotation NameExplain
ConditionalOnWebApplicationThe current project is a Web project
ConditionalOnJavaJava Version Based
ConditionalOnJndiExistence based on JNDI
ConditionalOnWarDeploymentWhen an application is deployed for a traditional WAR
ConditionalOnSingleCandidateWhen a specified Bean is only one in a container, or if there are more than one but a preferred Bean is specified
ConditionalOnPropertyDoes the specified property have a specified value
ProfileThe specified Profile is activated
ConditionalOnMissingBeanWhen no Bean is specified in the container
ConditionalOnCloudPlatformWhen a specified cloud platform is active
ConditionalOnClassWhen there is a specified class under the class path
ConditionalOnMissingClassWhen no class is specified under the class path
ConditionalOnResourceDoes the class path have a specified value
ConditionalOnRepositoryTypeSpecific types of Spring data warehouses enabled
ConditionalOnNotWebApplicationThe current project is not a Web project
ConditionalOnBeanWhen there is a specified Bean in the container
ConditionalOnDefaultWebSecurityWeb Security is available and the user does not have a custom configuration
ConditionalOnEnabledResourceChainCheck that the Spring resource processing chain is enabled. Matches whether WebProperties.Resources.Chain.getEnabled() is true, or whether webjar-locator-core is on the class path
ConditionalOnExpressionBased on SpEL expression

Example (ConditionalOnBean, adding user01 to container when pet03 exists)

MyConfig03.java

package cn.com.springboot.demo.config;

import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * The third configuration class example.
 *
 * Demo@Conditional
 * @author J
 */
@Configuration
public class MyConfig03 {

    /**
     * Declare a component with ID user03.
     * Add user01 to container when pet03 exists
     */
    @ConditionalOnBean(name = "pet01")
    @Bean
    public User user03() {
        return new User("Zhang San", "27");
    }

    /**
     * Declare a component with an ID of pet.
     */
    @Bean("pet")
    public Pet pet03() {
        return new Pet("cat", "coco");
    }
}

MainApp.java

package cn.com.springboot.demo;

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

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {

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

        // Test MyConfig03's @ConditionalOnBean
        System.out.println(run.containsBean("user03"));
    }
}

Run Results

false
  • @ConditionalOnBean(name = "pet01") can be added to methods or classes
    • Method: When the condition is not satisfied, only the current method will not be registered
    • Class: When the condition is not satisfied, components in the entire class will not be registered

2.1.4. @ImportResource

Import a native configuration file. If there was a previous way to configure components using XML or a third-party way to configure components using XML, you need to import such configurations into your project. For example:

Example

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="user04" class="cn.com.springboot.demo.bean.User">
        <property name="name" value="Zhang San" />
        <property name="age" value="21" />
    </bean>

    <bean id="pet04" class="cn.com.springboot.demo.bean.Pet">
        <property name="breed" value="cat" />
        <property name="petName" value="colina" />
    </bean>
</beans>

Myconfig04.java

package cn.com.springboot.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

/**
 * The fourth configuration class example.
 *
 * Demo@ImportResource
 * @author J
 */
@Configuration
@ImportResource("classpath:beans.xml")
public class MyConfig04 {}

MainApp.java

package cn.com.springboot.demo;

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

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {

        ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
        
        // Test @ImportResources for MyConfig04
        System.out.println(run.containsBean("user04"));
        System.out.println(run.containsBean("pet04"));
    }
}

Run Results

true
true

2.1.5. @ConfigurationProperties

Configure bindings. In development, it is common to write changes in properties files, such as DB connection information.

2.1.5.1. @Component + @ConfigurationProperties

Example

Car.java

package cn.com.springboot.demo.bean;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * Vehicle information.
 *
 * @author J
 */
@Setter
@Getter
@ToString
@NoArgsConstructor
@Component
@ConfigurationProperties("car01")
public class Car {

    /** brand */
    private String brand;

    /** Price */
    private String price;

    public Car(String brand, String price) {
        this.brand = brand;
        this.price = price;
    }
}

application.properties

car01.brand=BMW
car01.price=1200000

CarController.java

package cn.com.springboot.demo.controller;

import cn.com.springboot.demo.bean.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CarController {

    @Autowired
    private Car car;

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

Run Results

  • @Component: Register Car as a component to have the functionality provided by spring-boot
  • @ConfigurationProperties: Specify the prefix of the configuration file

2.1.5.1. @ConfigurationProperties

Example

Car.java

package cn.com.springboot.demo.bean;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Vehicle information.
 *
 * @author J
 */
@Setter
@Getter
@ToString
@NoArgsConstructor
// @Component
@ConfigurationProperties("car02")
public class Car {

    /** brand */
    private String brand;

    /** Price */
    private String price;

    public Car(String brand, String price) {
        this.brand = brand;
        this.price = price;
    }
}

application.properties

car02.brand=LEXUS
car02.price=1800000

CarController.java

package cn.com.springboot.demo.controller;

import cn.com.springboot.demo.bean.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CarController {

    @Autowired
    private Car car;

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

MyConfig05.java

package cn.com.springboot.demo.config;

import cn.com.springboot.demo.bean.Car;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * The fifth configuration class example.
 *
 * Demo @EnableConfiguration Properties
 * @author J
 */
@Configuration
@EnableConfigurationProperties(Car.class)
public class MyConfig05 {}

Run Results

  • @ConfigurationProperties: Specify the prefix of the configuration file
  • @EnableConfigurationProperties(${value}):
    • Turn on configuration binding for specified ${value}
    • Register the ${value} component into the container
    • Must be written on configuration class

Posted by a.beam.reach on Sun, 03 Oct 2021 10:16:25 -0700