Integration between Springboot and various components

Posted by finger on Sun, 06 Feb 2022 03:48:02 +0100

@TOC

Conditional annotation in springboot

@Conditional
The bean is loaded when a specific condition is triggered

There are many sub annotations under this annotation,


@ConditionalOnClass

package org.springframework.boot.autoconfigure.condition;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
    Class<?>[] value() default {};

    String[] name() default {};
}

Case - > > >

@ConditionalOnClass(name="com.mysql.cj.jdbc.Driver")
    @Bean(value = "myUser")
    public User  User1(){
        return new User("Li Si",23);
    }


When modified to
com. mysql. cj. jdbc. When using driverdatasource,

Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myUser' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:872)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344)

When getting the bean, you will be prompted that the bean cannot be found
@ConditionalOnClass(name = "aaa") annotation will only assemble the bean when class aaa is loaded. In fact, this is also reflected in the source code. For example, when we import thmeleaf, we will automatically import relevant configuration dependencies


For example, when freemaker is not introduced,
You can see in the configuration class information in spring boot auto config


This indicates that some configuration classes are not loaded. If we import freemaker at this time, check again


Note when freemaker is not imported, the configuration information about freemaker will not be loaded

Similarly, some other dependencies are the same;
But it also raises the question of whether I want to
@ConditionalOnProperty configuration class:

package com.gavin.config;
import com.gavin.pojo.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @author Gavin
 */
@Configuration(proxyBeanMethods = false)
@Import(value = {User.class} )
public class MyConfig {

    @Bean(value = "myUser")
    @ConditionalOnProperty(name = "server.port" ,havingValue = "8080")
//When there is a server in the configuration Port and the value is 8080, this bean will be loaded
    public User  getUser(){
        return new User("Zhang San",23);
    }

}

@SpringBootApplication
public class ZzyApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(ZzyApplication.class, args);
        User getUser = context.getBean("myUser", User.class);
        System.out.println(getUser);

    }

}

If a similar annotation is on the class, it means that all bean s in the configuration class will be loaded,

@ConditionalOnProperty(name = "server.port" ,havingValue = "8080")
@Configuration(proxyBeanMethods = false)
@Import(value = {User.class} )
public class MyConfig {

Then there will be a problem - the problem of priority
Class annotation has this annotation, and method annotation also has this annotation;
It is found that when the annotation information names are the same but the values are different, an error will be reported, that is, there can only be one same configuration;

@ConfigureProperties
Before annotating this case, first review the way of assembling data before - > > @ value

@AllArgsConstructor
@NoArgsConstructor
@Data
@Component
public class User implements Serializable {
@Value("Wednesday dry")
    private String uName;
@Value("18")
    private Integer uAge;
    private static final long serialVersionUID = -1L;
}


bean injection through configuration file
We know that spring boot will scan yml,yaml and properties configuration files when scanning configuration files, so we can use Properties to complete the injection of property data in the bean -- this needs to be completed by @ ConfigureProperties,

 
@Configuration
public class MyConfig {


application.properties file

user.uName=zzy
user.uAge=29
package com.gavin.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.Serializable;

/**
 * @author Gavin
 */
@AllArgsConstructor
@NoArgsConstructor
@Data

@ConfigurationProperties(prefix = "user")//Match prefix, generally lower case of custom class
@Component//Register bean
public class User implements Serializable {

//@Value("dry on Wednesday")

    private String uName;
//@Value("18")

    private Integer uAge;
    private static final long serialVersionUID = -1L;
}


Of course, we will add annotations to the configuration class as usual
Then the required annotation is changed - > >

@ EnableConfigurationProperties

package org.springframework.boot.context.properties;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EnableConfigurationPropertiesRegistrar.class})
public @interface EnableConfigurationProperties {
    String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";

    Class<?>[] value() default {};
}

case

@EnableConfigurationProperties(User.class)
public class MyConfig {

@AllArgsConstructor
@NoArgsConstructor
@Data
@Component
@ConfigurationProperties(prefix = "user")

public class User implements Serializable {

//@Value("dry on Wednesday")

    private String uName;
//@Value("18")

    private Integer uAge;
    private static final long serialVersionUID = -1L;
}

Summary - > > > if you annotate an entity class - > >
@Component / / register bean
@ConfigureProperties(prefix = "specify prefix"),
Annotation on configuration class - > > > @ configuration
If it is on the configuration class, it is on the entity class
You only need to change the annotation on the configuration class to @ EnableConfigurationProperties(User.class)

Introduce beans in springboot in xml (understand)

Define your own xml configuration file and configure bean s in the file. You need to prepare an xml configuration file in the resources directory

<?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="user" class="com.gavin.pojo.User">
        <property name="UName" value="Li Siwu"/>
        <property name="UAge" value= '18'/>
    </bean>
</beans>

After configuring xml, you also need to scan the file, because YML, yaml and properties files will be scanned by default, so you need to import the xml file through annotation;

@Configuration
@ImportResource(value = "classpath:beans.xml")
public class MyConfig {



You can add @ ComponentScan without any parameters or use @ SpringBootApplication to implicitly include its comments. All your application components (@ Component, @Service, @Repository, @Controller, and others) are automatically registered as Spring Beans.

import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    public MyAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }

    // ...

}


If a bean has multiple constructors, you need to mark the one you want Spring to use

@Autowired:

import java.io.PrintStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    private final PrintStream out;

    @Autowired
    public MyAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
        this.out = System.out;
    }

    public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
        this.riskAssessor = riskAssessor;
        this.out = out;
    }

    // ...

}

Delayed initialization of springboot

Spring application allows application initialization to be delayed. When deferred initialization is enabled, beans are created when needed, not during application startup. Therefore, enabling deferred initialization can reduce the time required for application startup. In Web applications, enabling deferred initialization will cause many Web related beans not to be initialized until they receive an HTTP request.

One disadvantage of delayed initialization is that it delays the discovery of application problems. If a misconfigured bean is delayed in initialization, the failure will not occur during startup, and the problem will become apparent only when the bean is initialized. Care must also be taken to ensure that the JVM has enough memory to hold all the beans of the application, not just those initialized during startup. For these reasons, deferred initialization is not enabled by default. It is recommended to fine tune the heap size of the JVM before enabling deferred initialization.

You can programmatically enable the deferred initialization lazyInitialization method SpringApplicationBuilder or the setLazyInitialization method SpringApplication Alternatively, you can use spring main. The lazy initialization attribute is shown in the following example:
characteristic
yaml

spring.main.lazy-initialization=true

If you disable deferred initialization for some bean s while using deferred initialization for the rest of the application, you can use the @ lazy (false) annotation to explicitly set their deferred properties to false.

Hot plug of springboot

Introduce dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <version>2.6.3</version>
</dependency>

Set up idea

Set registry

Some resources do not necessarily need to trigger a restart when they change. For example, the Thymeleaf template can be edited in place. By default, changing resources / META-INF/maven, /META-INF/resources, /resources, /static, /public, or / templates will not trigger a restart, but will trigger a real-time reload. If you want to customize these exclusions, you can use spring devtools. restart. Exclude property. For example, to exclude only / static and / public, you would set the following properties:
characteristic
yaml

spring.devtools.restart.exclude=static/,public/

If you want to keep these defaults and add additional exclusions, use spring.devtools.restart.additional-exclude It's property. 

Delayed initialization of Springboot

Spring application allows application initialization to be delayed. When deferred initialization is enabled, beans are created when needed, not during application startup. Therefore, enabling deferred initialization can reduce the time required for application startup. In Web applications, enabling deferred initialization will cause many Web related beans not to be initialized until they receive an HTTP request.

One drawback of application initialization latency is that it can be found. If a misconfigured bean is delayed in initialization, the failure will not occur during startup, and the problem will become apparent only when the bean is initialized. Care must also be taken to ensure that the JVM has enough memory to hold all the beans of the application, not just those initialized during startup. For these reasons, deferred initialization is not enabled by default. It is recommended to fine tune the heap size of the JVM before enabling deferred initialization.

You can programmatically enable the deferred initialization lazyInitialization method SpringApplicationBuilder or the setLazyInitialization method SpringApplication Alternatively, you can use spring main. The lazy initialization attribute is shown in the following example:
characteristic
yaml

spring.main.lazy-initialization=true

If you want to disable some bean With deferred initialization for the rest of the application, you can explicitly set their deferred property to false @Lazy(false)Notes. 

Topics: Java Spring Spring Boot