@SpringBootApplication核心原理(下)

@SpringBootApplication核心原理(下)

 

在上个章节中,我们提到了@SpringBootApplication核心原理中十分重要的注解@ConditionalOnClass,解释了SpringBoot实现自动装配的关键步骤,其次对核心源码也做了简要介绍,本章将对SpringBoot外部化配置做详细说明。

首先回到上个章节,笔者提出的问题,很多时候我们引入的组件都是需要我们用户自定义的,比如数据库连接、ip、端口,这些是没有办法确定的,但是这些类却需要自动配置到SpringBoot工厂里面去,因此SpringBoot针对这类东西提出了一个解决方案,叫@EnableConfigurationProperties,从名字就可以看出这又是一种自动配置注解,可能大家都不太熟悉这个注解,我们下面还是用案例的方式说明。

首先新建一个属性类,这个类是用来存放配置信息的

package com.example.boot02.autoconfiguration;import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.Map;@ConfigurationProperties(prefix= Properties.HELLO_FORMAT_PREFIX)public class Properties {    public static final String HELLO_FORMAT_PREFIX="com.format";    private Map<String,Object> info;    public Map<String, Object> getInfo() {        return info;    }    public void setInfo(Map<String, Object> info) {        this.info = info;    }}

在新建一个类,这个类是上个章节就创建好的

package com.example.boot02.autoconfiguration;import com.example.boot02.format.FormatProcessor;import com.example.boot02.format.JsonFormatProcessor;import com.example.boot02.format.StringFormatProcessor;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Component;@Componentpublic class FormatAutoConfiguration {    @ConditionalOnMissingClass("com.alibaba.fastjson.JSON")    @Bean    public FormatProcessor stringFormat(){        System.out.println("stringFormat");        return new StringFormatProcessor();    }    @ConditionalOnClass(name = "com.alibaba.fastjson.JSON")    @Bean    public FormatProcessor jsonFormat(){        System.out.println("jsonFormat");        return new JsonFormatProcessor();    }}

最后在创建我们的自动配置类

package com.example.boot02.autoconfiguration;import com.example.boot02.FormatTemplate;import com.example.boot02.format.FormatProcessor;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;@Import(FormatAutoConfiguration.class)@EnableConfigurationProperties({Properties.class})@Configurationpublic class AutoConfiguration {    @Bean    public FormatTemplate FormatTemplate(Properties properties, FormatProcessor formatProcessor){        return new FormatTemplate(properties,formatProcessor);    }}

同样的我们的format接口和实现类

package com.example.boot02.format;public interface FormatProcessor {    <T> String format();}
package com.example.boot02.format;public class JsonFormatProcessor implements FormatProcessor{    @Override    public <T> String format() {        return "JsonFormatProcessor";    }}

 

package com.example.boot02.format;import java.util.Objects;public class StringFormatProcessor implements FormatProcessor{    @Override    public <T> String format() {        return "StringFormatProcessor";    }}

这里在新建一个获取配置信息的类

package com.example.boot02;import com.example.boot02.autoconfiguration.Properties;import com.example.boot02.format.FormatProcessor;public class FormatTemplate {    private FormatProcessor formatProcessor;    private Properties properties;    public FormatTemplate(Properties properties, FormatProcessor formatProcessor) {        this.properties=properties;        this.formatProcessor = formatProcessor;    }    public <T> String doFormat(){        StringBuilder stringBuilder=new StringBuilder();        stringBuilder.append("begin:Execute format").append("<br/>");        System.out.println(properties.getInfo().toString());        return stringBuilder.toString();    }}

这个类是用来打印我们配置信息的,最后我们还是老规矩,在resouces下面的META-INF下面的spring.factories文件里添加下面的内容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\  com.example.boot02.autoconfiguration.AutoConfiguration

然后打包,放在我们的Boot1项目下

@SpringBootApplication核心原理(下)

然后我们修改下Boot1的这个Boot01Application类

package com.example.boot01;import com.example.boot02.FormatTemplate;import com.example.boot02.autoconfiguration.FormatAutoConfiguration;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ApplicationContext;@SpringBootApplication()public class Boot01Application {    public static void main(String[] args) {        ApplicationContext applicationContext = SpringApplication.run(Boot01Application.class, args);        applicationContext.getBean(FormatTemplate.class).doFormat();    }}

然后再配置下我们的属性,在application.properties添加

com.format.info.name=Licom.format.info.age=18

然后我们再测试一下

"C:\Program Files\Java\jdk1.8.0_201\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.5\lib\idea_rt.jar=49255:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\rt.jar;C:\Users\HP\IdeaProjects\Spring\boot01\target\classes;C:\Users\HP\.m2\repository\org\springframework\boot\spring-boot-starter\2.4.1\spring-boot-starter-2.4.1.jar;C:\Users\HP\.m2\repository\org\springframework\boot\spring-boot\2.4.1\spring-boot-2.4.1.jar;C:\Users\HP\.m2\repository\org\springframework\spring-context\5.3.2\spring-context-5.3.2.jar;C:\Users\HP\.m2\repository\org\springframework\spring-aop\5.3.2\spring-aop-5.3.2.jar;C:\Users\HP\.m2\repository\org\springframework\spring-beans\5.3.2\spring-beans-5.3.2.jar;C:\Users\HP\.m2\repository\org\springframework\spring-expression\5.3.2\spring-expression-5.3.2.jar;C:\Users\HP\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.4.1\spring-boot-autoconfigure-2.4.1.jar;C:\Users\HP\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.4.1\spring-boot-starter-logging-2.4.1.jar;C:\Users\HP\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\HP\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\Users\HP\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;C:\Users\HP\.m2\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;C:\Users\HP\.m2\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;C:\Users\HP\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\HP\.m2\repository\org\springframework\spring-core\5.3.2\spring-core-5.3.2.jar;C:\Users\HP\.m2\repository\org\springframework\spring-jcl\5.3.2\spring-jcl-5.3.2.jar;C:\Users\HP\.m2\repository\org\yaml\snakeyaml\1.27\snakeyaml-1.27.jar;C:\Users\HP\IdeaProjects\Spring\boot02\target\classes;C:\Users\HP\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar" com.example.boot01.Boot01Application  .   ____          _            __ _ _ /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/  ___)| |_)| | | | | || (_| |  ) ) ) )  '  |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot ::                (v2.4.1)2020-12-24 10:46:40.943  INFO 4616 --- [           main] com.example.boot01.Boot01Application     : Starting Boot01Application using Java 1.8.0_201 on HP-PC with PID 4616 (C:\Users\HP\IdeaProjects\Spring\boot01\target\classes started by HP in C:\Users\HP\IdeaProjects\Spring)2020-12-24 10:46:40.946  INFO 4616 --- [           main] com.example.boot01.Boot01Application     : No active profile set, falling back to default profiles: defaultstringFormat2020-12-24 10:46:41.274  INFO 4616 --- [           main] com.example.boot01.Boot01Application     : Started Boot01Application in 0.575 seconds (JVM running for 0.983){name=Li, age=18}Process finished with exit code 0

可以看到,我们已经获取到了我们的配置信息,这种操作就好比将数据库连接需要用户配置,然后我们再获取用户的配置信息,已达到实现自定义的功能。然后至于底层逻辑,其实和我们的自动化配置是大差不差的,有兴趣的读者可以自行阅读,这里我就不再深入探究了。小结一下,这三个小的章节对SpringBoot自动配置和外部化配置的核心原理做了详细的介绍,并其核心源码做了简要分析。

上一篇:201. 数字范围按位与


下一篇:BAT机器学习面试题及答案(201-250题)