SpringBoot

SpringBoot case implementation

  • Build the Spring Boot project using Spring Initializr

  • The project structure

    Springboot will then automatically create a project with the following file structure

  • Create a Controller for Web access

  • Run the project

  • Test class writing

Spring Boot hot deployment

1. Adding a spring-boot-starter-test test dependent initiator Add the spring-boot-starter-test test dependent initiator to the PM. XML file of the project with the following code as an example:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>
Copy the code

2 set up the idea

Enable automatic compilation first

Use the combination shortcut key “Ctrl+Shift+Alt+/” in any page of the project to open the Maintenance option box, select and open the Registry page, as shown in the figure below

Found in list “. The compiler. Automake. Allow the when. App. Running “, will check the Value of the Value, after this option is used to specify the IDEA tool in the process of the program is running automatically compile, finally click the “Close” button to complete the setting

Injection of configuration file property values

1 Use @ConfigurationProperties to inject properties

The @ConfigurationProperties annotation provided by Spring Boot is used to quickly and easily batch inject custom property values from a configuration file into multiple corresponding properties of a Bean object. Suppose you now have a configuration file if you use

@Component
@ConfigurationProperties(prefix = "person") // The configuration file says yes
public class Person {
    private int id; //id
    / / get/set methods
}
Copy the code

2 Use @value to inject properties

The @Value annotation is provided by the Spring framework to read property values in configuration files and inject them into the corresponding properties of Bean objects one by one. The Spring Boot framework inherits the @Value annotation by default from the Spring framework. So you can also use this annotation to read and inject configuration file property values within the Spring Boot framework.

@Component
public class Student {
    @Value("${person.id}")
    private int id;
    @Value("${person.name}")
    private String name; / / name
    
    / / the toString method
}
Copy the code

Custom Configuration

(1) Open the Resources directory of the Spring Boot project, create a custom configuration file named test.properties in the classpath of the project, and write configuration properties to be set in the file

MyProperties = MyProperties
test.id=110
test.name=test
Copy the code

(2) Create a configuration class MyProperties that provides the corresponding properties in the test.properties custom configuration file and uses the @propertysource annotation to configure the properties

@Configuration // Customize the configuration class
@PropertySource("classpath:test.properties") // Specify the location and name of the custom profile
@EnableConfigurationProperties(MyProperties.class) // Enable the attribute injection function for the corresponding configuration class
@ConfigurationProperties(prefix = "test") // Specify the config file injection property prefix
public class MyProperties {
    private int id;
    private String name;
    // Omit the property getXX() and setXX() methods
// omit the toString() method

}
Copy the code

Write custom Configuration classes using @Configuration

The @Configuration annotation is typically used to define a Configuration class that Spring Boot automatically scans and identifies to replace the XML Configuration files in the traditional Spring framework.

  • Defining configuration classes

    public class MyService {}Copy the code
    @Configuration
    public class MyConfig {
    
        @Bean(name = "iService") // Add a return value object to the container as a component, indicating that id is the default method name --myService can also specify name=""
        public MyService myService(a){
            return newMyService(); }}Copy the code
  • The test class

    @Autowired
    ApplicationContext context;
    @Test
    public void testmyConfig(a){
        System.out.println(context.containsBean("iService"));
    }
    Copy the code

Random number Settings and references between parameters

When setting properties in the Spring Boot configuration file, in addition to the configuration property values shown in the previous example, you can also set property values using random values and inter-parameter references. The following describes how to set the two attribute values in the configuration file.

1 Random value setting

my.secret=${random.value} // Sets a random value
my.number=${random. Int} // Configures a random integer
my.bignumber=${random.long} // Sets the number of random long types
my.uuid=${random. Uuid} // Sets the number of random UUID types
my.number.less.than.ten=${random.int(10)} // Configures a random integer less than 10
my.number.in.range=${random. Int [1024,65536]} // configures a random integer between [1024,65536]
Copy the code

2 Reference between parameters

app.name=MyApp
app.description=${app.name} is a Spring Boot application
Copy the code

In the example of reference Settings between the above parameters, app.name=MyApp is first set and the app.name attribute value is set to MyApp. Next, in the app.description property configuration, the previous property value is referenced with ${app.name}

Such as configuration

tom.age=The ${random. Int [10, 20]}
tom.description=Tom's age might be ${tom.age}
Copy the code
@Value("${tom.description}")
private String description;
@Test
public void placeholderTest(a) {
    System.out.println(description);
}
Copy the code

The output is: Tom’s age is probably 13

Springboot principle

Dependency management

Question 1: Why do I not need to specify the version when IMPORTING dependency?

In the Spring Boot starter, the project POm. XML file has two core dependencies, spring-boot-starter-parent and spring-boot-starter- Web

It is included in pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>Against 2.4.1</version>
    <relativePath/> <! -- lookup parent from repository -->
</parent>
Copy the code

Enter parent project

Spring – the boot – starter – parent dependency

Contains the

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>Against 2.4.1</version>
</parent>
Copy the code

Spring-boot-dependencies are included in the parent project

<properties>
  <activemq.version>5.16.0</activemq.version>
  <antlr2.version>2.7.7</antlr2.version>
  <appengine-sdk.version>1.9.83</appengine-sdk.version>
  <artemis.version>2.15.0</artemis.version>
  <aspectj.version>1.9.6</aspectj.version>
  <assertj.version>3.18.1</assertj.version>
  <atomikos.version>4.0.6</atomikos.version>
  <awaitility.version>4.0.3</awaitility.version>
  <bitronix.version>2.1.4</bitronix.version>
  <build-helper-maven-plugin.version>3.2.0</build-helper-maven-plugin.version>
  <byte-buddy.version>1.10.18</byte-buddy.version>
  <caffeine.version>2.8.8</caffeine.version>
  <cassandra-driver.version>4.9.0</cassandra-driver.version>* * *</properties>
Copy the code

As can be seen from the source file at the bottom of spring-boot-Dependencies, this file manages the dependencies of some common technical frameworks through the label, such as ActivemQ, Spring, tomcat, etc. Both have versions that match Spring Boot 2.2.2, which is why pom.xml introduces dependency files without needing to annotate the dependency file version number.

Note that if pom. XML imports a dependency file that is not managed by spring-boot-starter-parent, then when pom. XML imports a dependency file, you need to specify the version number of the dependency file with the tag.

Question 2: Spring-boot-starter-parent parent dependency initiator is mainly used for unified version management, so where does the project run dependent JAR package come from?

It is included in pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

The spring-boot-starter-Web dependency contains the related JAR package dependencies

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>Against 2.4.1</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>Against 2.4.1</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>Against 2.4.1</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.2</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.2</version>
    <scope>compile</scope>
  </dependency>
</dependencies>
Copy the code

In addition to the Web-dependent initiators described above, Spring Boot provides many other dependencies for development scenarios. You can go to the Official Spring Boot documentation and search “Starters” for scenariodependent initiators

You can check it out at docs. Spring. IO /spring-boot…

Automatic configuration (startup process)

Question: How exactly does Spring Boot auto-configure, and which components are auto-configured?

To sum up, the steps of automatic configuration at the bottom of SpringBoot are as follows:

  1. Springboot Starts the application.
  2. @springBootApplication works;
  3. @ EnableAutoConfiguration;
  4. @ AutoConfigurationPackage: This combination annotations mainly @ Import (AutoConfigurationPackages. The Registrar. The class), it will through the Registrar class imported into the container, and the Registrar class action is to scan the configuration class directory at the same level and the package, And import the corresponding widgets into the springBoot creation management container;
  5. @ Import (AutoConfigurationImportSelector. Class) : It will by AutoConfigurationImportSelector class imported into the container, AutoConfigurationImportSelector class action is through selectImports method in the process of execution, The internal utility class SpringFactoriesLoader is used to find all jar packages on the classpathMETA-INF/spring.factoriesTo implement the SpringFactory loader for a series of container creation processes

The @springBootApplication annotation function is almost analyzed, which is simply a combination of three annotations:

|- @SpringBootConfiguration
    |- @Configuration // Add components to the IOC container via javaConfig
|- @EnableAutoConfiguration
    |- @AutoConfigurationPackage // Automatic configuration package, with @ComponentScan scanned to add to IOC
    |- @Import(AutoConfigurationImportSelector.class) // Add beans defined in meta-INF/spring.Factories to the IOC container
|- @ComponentScan / / package scans
Copy the code

Custom starter

SpringBoot starter mechanism

SpringBoot consists of many Starter plug-ins (a series of automatically configured Starter plug-ins). The popularity of SpringBoot is also due to Starter plug-ins.

Starter is a very important part of SpringBoot, which can be understood as a pluggable plug-in. It is these starter that enables developers to use a function without paying attention to the processing of various dependent libraries or specific configuration information. Spring Boot automatically finds the required beans from classes in the classpath path and weaves them into the appropriate beans.

For example, if you want to use Reids, you can use spring-boot-starter-redis. If you want to use MongoDB, you can use spring-boot-starter-data-mongodb

Why custom starter

During development, there are often configuration modules that are independent of the business. If we package these functional configuration modules that can be independent of business code into a starter, we only need to reference them in POM and rely on them when reuse, SpringBoot will complete automatic assembly for us

You can define a naming rule for the starter

The starter provided by SpringBoot is named in the spring-boot-starter-xxx format. It is recommended to use the xxX-spring-boot-starter naming rule for the user-defined starter. To differentiate between SpringBoot ecology offers starter

The whole process is divided into two parts:

  • Custom starter
  • Use the starter

Custom starter

(1) Create maven JAR project named zdy-spring-boot-starter, import dependency:

(2) Write javaBean: Simplebean.java

(3) Write the configuration class MyAutoConfiguration

@Configuration
@ConditionalOnClass/*(SimpleBean.class)*/   ConditionalOnClass: automatically configured when there is a specified class in the classpath
public class MyAutoConfiguration {
    @Bean
    public SimpleBean simpleBean(a) {
        return newSimpleBean(); }}Copy the code

Note: on the class to add annotations @ ConditionalOn * * condition such as annotations, such as: @ ConditionalOnClass said the configuration class must ensure that the classpath has the specified class can be initialized, otherwise can’t initialize, there was a null pointer initialization to avoid problems. This is because an exception occurs when the specified class is used in the configuration but not in the container. If no class is specified, the class must be configured automatically by SpringBoot.

(4) Create/meta-inf /spring.factories under resources

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xiewz.config.MyAutoConfiguration
Copy the code

Note: Meta-INF is a manually created directory, and spring.factories is a manually created file in which you configure your own auto-configuration classes

Use a custom starter

(1) Import the dependency of the custom starter

(2) Configure attribute values in the global configuration file

(3) Write test methods

All works

Start using the main method

public static void main(String[] args) {
    SpringApplication.run(Spingboot01Application.class, args);
}
Copy the code

Enter the run method and do two things:

public static ConfigurableApplicationContext run(Class
       [] primarySources, String[] args) {
   // The SpringApplication startup consists of two parts:
   //1. Instantiate the SpringApplication object
   //2. run(args) : call the run method
   return new SpringApplication(primarySources).run(args);
}
Copy the code

Constructing a SpringApplication object does the following:

Initializers are set, and the Listener is finally called to initialize the mainApplicationClass property: the main program launcher class used to infer and set the project main() method to startCopy the code

The things in the run(args) method are:

(1) Get and start listener (2) preconfigure project Environment (3) create Spring container (4) Spring container preprocessing (5) : refresh container (6) : Spring container post-processing (7) send event notification to end execution (8) : Execute Runners (9) to publish application context-ready events and finally return the containerCopy the code

SpringBoot data access

1. Spring Boot integration MyBatis

  • Data preparation

    Create databaseCREATEDATABASE springbootdata; USE springBootData; Create table T_article and insert related dataDROP TABLE IF EXISTS t_article;
      CREATE TABLE t_article (
          id INT ( 20 ) NOT NULL AUTO_INCREMENT COMMENT 'the article id',
          title VARCHAR ( 200 ) DEFAULT NULL COMMENT 'Article Title',
          content LONGTEXT COMMENT 'Article content'.PRIMARY KEY ( id ) 
      ) ENGINE = INNODB AUTO_INCREMENT = 2 DEFAULT CHARSET = utf8;
      INSERT INTO t_article VALUES ('1'.'Spring Boot Basics'.'From entry to mastery... ');
      INSERT INTO t_article VALUES ('2'.'Spring Cloud Basics'.'From entry to mastery... '); Create table T_COMMENT and insert related dataDROP TABLE IF EXISTS t_comment;
      CREATE TABLE t_comment (
          id INT ( 20 ) NOT NULL AUTO_INCREMENT COMMENT 'comment id',
          content LONGTEXT COMMENT 'Comment content',
          author VARCHAR ( 200 ) DEFAULT NULL COMMENT 'Review writer',
          a_id INT ( 20 ) DEFAULT NULL COMMENT 'Associated article ID'.PRIMARY KEY ( id ) 
      ) ENGINE = INNODB AUTO_INCREMENT = 3 DEFAULT CHARSET = utf8;
      INSERT INTO t_comment VALUES ('1'.'Full and detailed'.'luccy'.'1');
      INSERT INTO t_comment VALUES ('2'.'Like one'.'tom'.'1');
      INSERT INTO t_comment VALUES ('3'.'Very detailed'.'eric'.'1');
      INSERT INTO t_comment VALUES ('4'.'Very good. Very detailed.'.'Joe'.'1');
      INSERT INTO t_comment VALUES ('5'.'Very good'.'bill'.'2');
    Copy the code
  • Create the project and import the appropriate initiator

  • Write the entity classes Comment and Article corresponding to the database tables T_COMMENT and T_article

    public class Comment {
        private Integer id;
        private String content;
        private String author;
        private Integer aId;
        // Omit the property getXX() and setXX() methods
        // omit the toString() method
    }
    
    public class Article {
        private Integer id;
        private String title;
        private String content;
        // Omit the property getXX() and setXX() methods
        // omit the toString() method
    }
    Copy the code
  • Writing configuration files

    Configure the database connection in the application.properties configuration file

    MySQL database connection configuration
    spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata? serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=root
    Copy the code

Annotation mode integration Mybatis

(1) Create a CommentMapper interface for t_COMMENT data operations on the database table

@Mapper // Identify the interface as an interface file of Mybatis, and enable SpringBoot to scan the interface, generate the proxy object of the interface, and store it in the container
public interface CommentMapper {
    @Select("SELECT * FROM t_comment WHERE id =#{id}")
    public Comment findById(Integer id);
}
Copy the code

(2) Write test methods

@Autowired
private CommentMapper commentMapper;

@Test
void contextLoads(a) {
    System.out.println(commentMapper.findById(1));
}
Copy the code

The result has no value for aId

We found that underlining is used in the database and the code needs to be converted to camel name, so we need to add the configuration to application.properties

# Enable camel name matching mapping
mybatis.configuration.map-underscore-to-camel-case=true
Copy the code

Integrate MyBatis using configuration files

(1) create an interface for t_article data operation on the database table ArticleMapper

@Mapper
public interface ArticleMapper {
    // Query the corresponding article by id
    public Article selectArticle(Integer id);
}
Copy the code

(2) Create XML mapping files

Create a package mapper for unified management of mapping files under resources directory, and write the mapping file Articlemapper.xml corresponding to the Interface of ArticleMapper under this package


      
<! DOCTYPEmapper PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xiewz.mapper.ArticleMapper">
    <select id="selectArticle" parameterType="int" resultType="com.xiewz.pojo.Article">
    select * from t_article where id = #{id}
   </select>
</mapper>
Copy the code

(3) Configure the XML mapping file path.

Configure the path to the XML configuration file in the global configuration file application.properties:

Configure mybatis XML mapping configuration file path
mybatis.mapper-locations=classpath:mapper/*.xml
Mybatis mapping configuration file entity category name
mybatis.type-aliases-package=com.xiewz.pojo
Copy the code

After the alias is set, the configuration in the XML can be: resultType=”article”

(4) Write unit tests to test interface methods

@Autowired
private ArticleMapper articleMapper;

@Test
void articleMapperTest(a) {
    System.out.println(articleMapper.selectArticle(1));
}
Copy the code

Finally: after annotating the startup class with @mapperscan (“com.xiewz.mapper”), there is no need to add @mapper to every Mapper interface.

2 Spring Boot Integrate JPA

(1) Add Spring Data JPA dependent initiator.

<! --Spring Data JPA dependent initiator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Copy the code

(2) Write ORM entity classes.

@Entity
@Table(name = "t_comment")
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String content;
    private String author;
    @Column(name = "a_id")
    private Integer aId;
    / / get/set/toString omitted
}
Copy the code

(3) Write Repository interface: CommentRepository

public interface CommentRepository extends JpaRepository<Comment.Integer> {}Copy the code

(4) Test

// Test the JPA integration
@Autowired
private CommentRepository commentRepository;

@Test
public void commentRepositoryTest(a){
    Optional<Comment> byId = commentRepository.findById(1);
    // if(byId.isPresent()){}
    System.out.println(byId.get());
}
Copy the code

3 Spring Boot Integrate Redis

(1) Add Spring Data Redis dependent initiator.

<! --Spring Data Redis relies on initiators -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Copy the code

(2) Write entity classes.

@RedisHash(value = "persons") // Specifies the storage space of the entity-class object in Redis
public class Person {

    @Id // The string hashkey used to identify the primary key of the entity class identifies the unique entity class object ID
    private String id;
    @Indexed // a secondary index is generated for the corresponding attribute in Redis
    private String firstname;
    @Indexed
    private String lastname;
    private Address address;
    / / get/set/toString omitted
}

public class Address {
    @Indexed
    private String city; / / the city
    @Indexed
    private String country; / / country
    / / get/set/toString omitted
}
Copy the code

(3) Write the Repository interface.

public interface PersonRepository extends CrudRepository<Person.String> {
    // Query the corresponding person according to the city information
    List<Person> findByAddress_City(String name);
}
Copy the code

Only the underlying CrudRepository can be inherited, not JpaRepository. Because JpaRepository is the interface to JPA integration

(4) Redis database connection configuration.

#redis server address
spring.redis.host=127.0.0.1
# Redis server connection port
spring.redis.port=6379
Redis server connection password
spring.redis.password=
Copy the code

(5) Write unit tests to test interface methods

// Test the Redis integration
@Autowired
private PersonRepository personRepository;
@Test
public void savePerson(a){
    Person person = new Person();
    person.setFirstname("Zhang");
    person.setLastname("Three");

    Address address = new Address();
    address.setCity("Beijing");
    address.setCountry("China");
    person.setAddress(address);

    // Add data to redis database
    personRepository.save(person);

}
@Test
public void personRepositoryTest(a){
    List<Person> list = personRepository.findByAddress_City("Beijing");
    for(Person person : list) { System.out.println(person); }}Copy the code

After the savePerson() method is executed, the data is saved in Redis and can be viewed using the visualization tool RedisDesktopManager