Summary of the principle of micro service architecture day08 springboot

Several important event callback mechanisms

ApplicationContextInitializer

  • ApplicationContextInitializer comes from the Spring framework
    • The main function is to refresh the ApplicationContext of ConfigurableApplicationContext type or subtype
    • It allows further setting and processing of the instance of ConfigurableApplicationContext
  • ApplicationContextInitializer interface:
    • Is a callback function executed before the Spring container is refreshed
    • The top note is called before the refresh() method of ConfigurableApplicationContext, that is, to execute ConfigurableApplicationContext's refresh() method inside the Spring framework or run() method of SpringBoot.
    • The function is to initialize the callback interface of Spring's ConfigurableApplicationContext
  • It is usually used in web applications that need to initialize the application context: for example, register properties according to the context or activate the profile
Usage analysis
  • Typical application scenarios of ApplicationContextInitializer interface:
    • Initialize the application context of the web application
    • For example:
      • Register property sources
      • Activate the corresponding profile for the environment information environment of the context
  • In a SpringBoot application:
    • There are many jar packages on the classpath. Some jar packages need to initialize the application context before the refresh() method of ConfigurableApplicationContext is called
    • Therefore, it will provide its own ApplicationContextInitializer implementation class, and then configure it in its own meta-inf / spring In the factories properties file
    • In this way, the corresponding ApplicationContextInitializer implementation class will be found by the initialize() method of SpringApplication
  • The initialize() method of SpringApplication is executed in the constructor of SpringApplication to ensure that it is completed before the run() method of SpringApplication
  • Then, after the application context is created, the preparation phase before the application context refresh is called
SpringBoot built-in ApplicationContextInitializer
  • Use the implementation of ApplicationContextInitializer used by SpringBoot web application by default:
    • DelegatingApplicationContextInitializer:
      • Use environment attribute context initializer. The initialization container initializer specified by classes initializes. If it is not specified, no operation will be performed
      • So that it can be used in application You can customize the implementation class configuration in properties
    • ContextIdApplicationContextInitializer:
      • Set the ID of the Spring application context by referring to the environment attribute
      • The setting of ID value will refer to the environment attribute:
        • spring.application.name
        • vcap.application.name
        • spring.config.name
        • spring.application.index
        • vcap.application.instance_index
        • If none of these attributes exist, use application ID
    • ConfigurationWarningApplicationContextInitializer:
      • For general configuration errors, a warning is given in the log
    • ServerPortInfoApplicationContextInitializer:
      • Write the listening port actually used by the built-in servlet container to the environment attribute
      • This attribute is local server. Port can be directly injected into the test through @ Value or obtained through the environment attribute environment
    • SharedMetadataReaderFactoryContextInitializer:
      • Create a cacheingmetadatareaderfactory object shared by SpringBoot and ConfigurationClassPostProcessor
      • The implementation class is ConcurrentReferrenceCachingMetadataReaderFactory
    • ConditionEvaluationReportLoggingListener:
      • Write the ConditionEvaluationReport to the log
  • ApplicationContextInitializer allows you to perform custom operations before refreshing the context in Spring. If you need to deeply integrate the context of Spring, you can use ApplicationContextInitializer to do a good job
  • There is an annotation org. In the spring test package springframework. test. context. There is a property in contextconfiguration that can specify that ApplicationContextInitializer can customize the preprocessing of context when assisting integration test
Extended implementation
Programming mode
  • Define ApplicationContextInitializer first:
// @Order(66) - @Order is executed earlier if its value is smaller Label on class, not method
@Order(66)
public class customerApplicationContextInitializer implements ApplicationContextInitializer {
	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		// How many bean s are there in the output container
		System.out.println("Bean The quantity of is: " + applicationContext.getBeanDefinitionCount());
		/*
		 * Output the bean names of all beans in the container
		 */
		 System.out.println(applicationContext.getBeanDefinitionCount + "individual Bean Name of:");
		 String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
		 for (String beanName : beanDefinitionNames) {
		 	System.out.println(beanName);
		 }
	}
}
  • Manually add initializer in startup class:
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServer {
	public static void mian(String[] args) {
		SpringApplication springApplication = new SpringApplication(ConfigServer.class);
		// Add an instance of the custom ApplicationContextInitializer implementation class to register the ApplicationContextInitializer
		springApplication.addInitializers(new customerApplicationContextInitializer());
		ConfigurableApplicationContext applicationContext = springApplication.run(args);
		applicationContext.close();
	}
}
Add configuration method
  • The way to add the configuration is to get the application through the initialize() method in the DelegatingApplicationContextInitializer initialization class Context in properties initializer. Class and execute the corresponding initialize() method
  • Just add the class that implements the ApplicationContextInitializer to the application Properties
    • First define a class that implements the ApplocationContextInitializer
    • Then in application Defined in properties:
    context.initializer.class= com.oxford.customerApplicationContextInitializer
    
spring.factories mode
  • ==SpringApplicationRunListener==
    • Applicationcontextinitializer and springapplicationrunlistener need to be configured in meta-inf / spring In factories
  • ==ApplicationRunner==
  • ==CommandLineRunner==
    • Applicationrunner and commandlinerunner need to be placed in the IOC container

Start process

  • Create a SpringApplication object
    • Call the initialize(sources) method to create the object
      • Save main configuration class
      • Judge whether it is currently a web application
      • Find meta-inf / spring.com from the classpath All applicationcontextinitializers configured by factories, and then save them
      • Find meta-inf / spring. From the classpath All applicatlisteners configured by factories
      • Find the main configuration class with main method from multiple configuration classes
  • Run run method
public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();		
        stopWatch.start();		// Stop listening
        ConfigurableApplicationContext context = null;		// Declare an IOC container
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);		
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • Get SpringApplicationRunListeners and download meta-inf / spring.com from the classpath factories
  • Callback all to get springapplicationrunlistener Starting() method
  • Encapsulating command line parameters
  • Prepare the environment prepareEnvironment, and call back springapplicationrunlisteners. Com after creating the environment Environmentprepared(): indicates that the environment preparation is complete
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        listeners.environmentPrepared((ConfigurableEnvironment)environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }

        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }
  • Create ApplicationContext: decide whether to create a web IOC or an ordinary IOC
protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
  • Prepare context: save the environment to IOC and call applyInitializers(): call back the initialize method of all applicationcontextinitializers saved before Then call back the contextPrepared method of SpringApplicationRunListener
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }

        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }

        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        this.load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }
  • Call back the contextLoaded() method of all spring applicationrunlisteners after the prepareContext is run
  • Refresh the container refreshContext and initialize the IOC container The embedded tomcat.com will also be created in the web application Yes, scan in. Refcontext Where all components are loaded (configuration class, component, automatic configuration)
private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

    }
  • Call callRunner() to get all ApplicationRunner and CommandLineRunner from IOC container Callback ApplicationRunner first and then CommandLineRunner
  • Finally, call back the listeners of SpringApplicationRunListeners running(context)
  • After the entire SpringBoot application is started, return to the started IOC container

Event monitoring mechanism

  • ==ApplicationContextInitializer==
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext > {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer...initialize"+configurableApplicationContext);
    }
}

  • ==SpringApplicationRunListener==
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
   @Override
   public void starting() {
       System.out.println("SpringApplicationRunListener...starting...");
   }

   @Override
   public void environmentPrepared(ConfigurableEnvironment environment) {
       Object o=environment.getSystemProperties().get("os.name");
       System.out.println("SpringApplicationRunListener...environmentPrepared...");
   }

   @Override
   public void contextPrepared(ConfigurableApplicationContext context) {
       System.out.println("SpringApplicationRunListener...contextPrepared...");
   }

   @Override
   public void contextLoaded(ConfigurableApplicationContext context) {
       System.out.println("SpringApplicationRunListener...contextLoaded...");
   }

   @Override
   public void started(ConfigurableApplicationContext context) {
       System.out.println("SpringApplicationRunListener...started...");
   }

   @Override
   public void running(ConfigurableApplicationContext context) {
       System.out.println("SpringApplicationRunListener...running...");
   }

   @Override
   public void failed(ConfigurableApplicationContext context, Throwable exception) {
       System.out.println("SpringApplicationRunListener...failed...");
   }
}
  • Applicationcontextinitializer and springapplicationrunlistener need to be configured in meta-inf / spring In factories
org.springframework.context.ApplicationContextInitializer=\
com.web.springboot.listener.HelloApplicationContextInitializer

org.springframework.context.SpringApplicationRunListener=\
com.web.springboot.listener.HelloSpringApplicationRunListener
  • ==ApplicationRunner==
@Component			// Class in container
public class HelloApplicationRunner implements ApplicationRunner {
   @Override
   public void run(ApplicationArguments args) throws Exception {
       System.out.println("ApplicationRunner...run...");
   }
}

==CommandLineRunner==

@Component			// Class in container
public class HelloCommandLineRunner implements CommandLineRunner {
   @Override
   public void run(String... args) throws Exception {
       System.out.println("CommandLineRunner...run"+ Arrays.asList(args));
   }
}
  • Applicationrunner and commandlinerunner need to be placed in IOC container - = = @ Component==

SpringBoot custom starter

  • starter:
    • What are the dependencies of this scenario?
    • How to write automatic configuration?
    @Configuration			// Specifies that this class is an auto configuration class
    @ConditionalOnXxx()		// The automatic configuration class takes effect when the specified conditions are true
    @AutoConfigureOrder() 	// Specifies the order in which classes are automatically configured
    @AutoConfigureAfter()	// Specifies that automatic configuration follows a specific class
    		@Bean			// Add group price to container
    ( @ConfigurationProperties Combined correlation XxxProperties Class to bind related configurations )
    @EnableConfigurationProperties	// Make the XxxProperties class effective and add it to the container
    
    • Configure automatic assembly Bean: put the automatic Configuration class marked @ Configuration under classpath = = meta-inf / spring Factories = = can only be loaded in the file
    org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
    org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
    
    • pattern:
      • Initiator: the initiator is an empty jar file, = = only provides auxiliary dependency management, dependency import = =, and these dependencies are used for automatic assembly or other class libraries
      Official namespace:
      		- prefix: spring-boot-starter-
      		- pattern: spring-boot-starter-Module name
       Custom namespace:
      	    - prefix: -spring-boot-starter-
      		- pattern: Module name-spring-boot-starter
      
      • Write an automatic configuration module
      • The initiator depends on the automatic configuration module, and only the initiator needs to be introduced when it is used

    summary

    • ==Official documents==
    • ==Source code==

Tags: Java Spring

Posted by Gmans on Sun, 17 Apr 2022 08:19:51 +0930