springboot小结
ConfigurationProperties(prefix="nxj")
ignoreInvalidFields
@Value
@ConfigurationProperties | @Value | |
---|---|---|
松散绑定 | 支持 | 不支持 |
全部赋值 | 支持 | 不支持(只能一个个赋值) |
JSR303 | 支持 | 不支持 |
SPLE | 不支持 | 支持 |
@ImportResource
@ImportResource(value={"classpath:applicationContext.xml"})
导入Spring的配置文件,让其生效
还有一些注解比如说@Configuration,@Bean等等等等,这些在Spring注解版中都很清楚了,这里就不需要再记录出来了。
配置文件中:
在application.yml或者properties中直接使用${}取值,`name: ${person.name1:hello}`意思就是如果能取到person.name1则取,否则赋值为hello【就是hello字符串】
Profiles
多环境之间需要切换的时候
1.使用application-xxx.properties
2.直接在application.yml中使用 '---' 多文档块分割
使用 spring.profiles.active=dev 进行切换
spring
🐾自动配置原理
起源:
@SpringBootApplication
@EnableAutoConfiguration
@Import(AutoConfigurationImportSelector.class)
其中AutoConfigurationImportSelector是一个selector,为我们加载了类路径下:META-INF、spring.factories
这就是自动配置的起源,正因为把这些AutoConfiguration自动加入到了容器中,后面的自动配置才会开始。
示例:
以其中的一个
HttpEncodingAutoConfiguration
为例进行说明
//这是一个springboot的配置类
//绑定配置文件
所以我们能在配置文件中配置的,都是来自于**Properties这些。
精髓:
springboot在启动的时候会加载大量的自动配置类(这些配置类加载来源于类路径下/META-INF/spring.factories的
org.springframework.boot.autoconfigure.EnableAutoConfiguration
下配置)我们看我们需要的功能springboot有没有默认写好的自动配置类
如果有的话,我们看下自动配置类中配置了那些组件,有没有我们需要的,如果有且满足我们的要求,我们就不需要再来自动配置了
自动配置类在添加组件的时候,会从properties中获取属性,我们可以在配置文件中指定这些属性
xxxAutoConfiguration:自动配置类
xxxProperties:封装配置文件中相关属性
日志
稍后回头再看
整合Mybatis
Mybatis注解版
springboot配置数据源(spring.datasource等)
创建mapper,其中mapper上方标注执行sql方法,并将其加入到容器中@Component
然后在ioc容器中获取【@Autowired】即可使用
//这是一个操作数据库的mapper @Mapper //或者在启动类上标注@MapperScan("") @Component public interface UserMapper { @Select("select * from z1") public List<User> queryAllUser(); @Select("select * from z1 where id=#{id}") public User queryUserById(Integer id); //@Options用来设置id是我的自增主键,我插入的时候,直接返回给我的带自增主键的,否则不写的话,就返回给我null @Options(useGeneratedKeys = true,keyProperty = "id") @Insert("insert into z1 (name,age) values (#{name},#{age})") public int insertUser(User user); }//这是controller类里面的内容 @Autowired UserMapper userMapper; @ResponseBody @GetMapping("/user") public List<User> queryAllUser(){ return userMapper.queryAllUser(); } @ResponseBody @GetMapping("/use/{id}") public User queryAllUser(@PathVariable("id") Integer id){ return userMapper.queryUserById(id); } @ResponseBody @GetMapping("/userinsert") public User insertUser(User user){ userMapper.insertUser(user); return user; }
Mybatis配置文件版
springboot配置数据源(spring.datasource等)
创建mapper
可以创建mybatis的配置文件
创建mapper对应实现的xml
在springboot的配置文件中绑定mabatis的配置文件与mapper.xml文件
从ioc中获取即可调用
1.springboot配置数据源(spring.datasource等)
spring: datasource: url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver2.创建mapper
@Component @Mapper public interface UserXmlMapper { public List<User> queryAllUser(); public User queryUserById(Integer id); public int insertUser(User user); }3.可以创建mybatis的配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--这是mybatis的主配置文件--> </configuration>4.创建mapper对应实现的xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.springmybtis.mapper.UserXmlMapper"> <!--这里就是让这个xml配置文件绑定UserXmlMapper,作为它的实现,我只要把它与Mybatis的配置文件加入到ioc中即可使用了--> <select id="queryAllUser" resultType="com.example.springmybtis.bean.User"> select * from z1 </select> <select id="queryUserById" resultType="com.example.springmybtis.bean.User"> select * from z1 where id=#{id} </select> <insert id="insertUser"> insert into z1 (name,age) values (#{name},#{age}); </insert> </mapper>5.在springboot的配置文件中绑定mabatis的配置文件与mapper.xml文件
mybatis: config-location: classpath:mybatis/mybatis-config.xml #指定全局配置文件的位置 mapper-locations: classpath:mybatis/mapper/*.xml #指定sql映射文件的位置6.从ioc中获取即可调用
@Controller public class UserXmlController { @Autowired UserXmlMapper userXmlMapper; @GetMapping("/all") @ResponseBody public List<User> getAllUser(){ return userXmlMapper.queryAllUser(); } }
springboot启动配置原理
只要看到
getSpringFactoriesInstances
这个方法,它就是从类路径下META-INF/spring.factories下获取相关信息Bootstrapper ApplicationContextInitializer ApplicationListener
1.创建SpringApplication对象
//分别获取ApplicationContextInitializer与ApplicationListener在META-INF/spring.factroies中配置的类的全路径名集合
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources){ this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //推断是是一个WebApplicationType什么类型的(这是个枚举) this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class)); //获取类路径下META-INF/spring.factories下ApplicationContextInitializer配置的Initializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //获取类路径下META-INF/spring.factories下ApplicationListener配置的相关的Listener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }2.执行run方法
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; //设置java.awt相关的,一般我们也不用 configureHeadlessProperty(); //从类路径下的META-INF/spring.factories中获取所有的SpringApplicationRunListener SpringApplicationRunListeners listeners = getRunListeners(args); //回调所有SpringApplicationRunListener的starting方法 listeners.starting(bootstrapContext, this.mainApplicationClass); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); //获取或者创建环境,然后配置管径 //回调SpringApplicationRunListener的environmentPrepared方法 //设置环境中需要忽略的组件信息 configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); //创建ioc容器 context = createApplicationContext(); //设置context的applicationStartup属性 context.setApplicationStartup(this.applicationStartup); //准备上下文 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //设置环境 //注册一些内部组件 //获取所有的ApplicationContextInitializer【上方】,并调用其initialize方法 //回调SpringApplicationRunListener的contextPrepared方法 //全部执行完最后回调SpringApplicationRunListener的contextLoaded方法 //刷新容器,这里就是和spring原理一样,BeanPostProcessors或者组件注册等都在这里 refreshContext(context); //内部无任何实现,留给子类扩充 afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //回调SpringApplicationRunListener的started方法 listeners.started(context); //从ioc容器中获取ApplicationRunner与CommandLineRunner组件 //然后将获取出来这两类组件排序后 //先调用ApplicationRunner的run方法 //再调用CommandLineRunner的run方法 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { //回调SpringApplicationRunListener的running方法 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } //将创建好的ioc容器返回 return context; }
上方小结
可以看出以下需要在类路径下:META-INF/spring.factories中配置
Bootstrapper *ApplicationContextInitializer ApplicationListener *SpringApplicationRunListener而
*
ApplicationRunner
与
*
CommandLineRunner
是从ioc容器中取得【也就是对象创建完了,我们去拿】
调用过程
SpringApplicationRunListener.starting() ↓ SpringApplicationRunListener.environmentPrepared() ↓ ApplicationContextInitializer.initialize() ↓ SpringApplicationRunListener.contextPrepared() ↓ SpringApplicationRunListener.contextLoaded() ↓ SpringApplicationRunListener.started() ↓ ApplicationRunner.run() ↓ CommandLineRunner.run() ↓ SpringApplicationRunListener.running()
应用测试
1.分别创建
ApplicationContextInitializer
与SpringApplicationRunListener
与ApplicationRunner
与CommandLineRunner
的实现类public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { System.out.println("MyApplicationContextInitializer...initialize"+configurableApplicationContext.getApplicationName()); } }public class MySpringApplicationRunListener implements SpringApplicationRunListener { public MySpringApplicationRunListener(SpringApplication application, String[] args) { System.out.println("chushihua"); } @Override public void starting(ConfigurableBootstrapContext bootstrapContext) { System.out.println("starting"); } @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { System.out.println("environmentPrepared"); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("contextPrepared"); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("contextLoaded"); } @Override public void started(ConfigurableApplicationContext context) { System.out.println("started"); } @Override public void running(ConfigurableApplicationContext context) { System.out.println("running"); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { System.out.println("failed"); } }@Component public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("MyApplicationRunner...run"+ Arrays.asList(args)); } }@Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("MyCommandLineRunner...run"+ Arrays.asList(args)); } }
2.在类路径下META-INF下创建spring.factories,内容如下:
org.springframework.context.ApplicationContextInitializer=\ com.example.springmybtis.test.MyApplicationContextInitializer org.springframework.boot.SpringApplicationRunListener=\ com.example.springmybtis.test.MySpringApplicationRunListener
启动主程序,输出顺序如下:
chushihua starting environmentPrepared . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.4.0) MyApplicationContextInitializer...initialize contextPrepared contextLoaded started MyApplicationRunner...run[org.springframework.boot.DefaultApplicationArguments@f446158] MyCommandLineRunner...run[] running
自定义starter
【参考WebMvcAutoconfiguration】 @Configuration //指定这是一个配置类 @ConditionalOnXXX //指定条件生效时自动配置类才生效 @AutoConfigureAfter //指定自动配置类的顺序(这里是在这些写自动配置加载完后,这个类再加载) @Bean //给容器中添加组件 @ConditionalOnProperty //结合xxProperties来绑定属性赋值 @EnableConfigurationProperties //让xxProperties生效并加入到ioc容器中 自动配置类要能生效,源于我们在META-INF/spring.factories下的自动配置,如: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
命名时,我们最好xxx-spring-boot-starter 【启动器只用于一来到日,专门写一个自动配置模块】(这是spring在书写时stater时的规范) 1.我们得代码写在xxx-spring-boot-starter-configure下 2.xxx-spring-boot-starter依赖xxx-spring-boot-starter-configure 3.我们使用xxx-spring-boot-starter
1.创建pom工程起名为nxj-spring-boot-starter
注意这里千万不要因为在其他文件夹下,从而出现parent节点,很容易出问题,导致其他pom引入这个stater出错(unknown)。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>nxj-spring-boot-starter</artifactId> <groupId>org.jd.nxj</groupId> <version>1.0.0</version> <dependencies> <!--引入我的自动配置模块--> <dependency> <groupId>com.jd.nxj</groupId> <artifactId>nxj-spring-boot-starter-configure</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>2.编写nxj-spring-boot-starter-configure
和配置文件属性赋值绑定的XXXProperties
@ConfigurationProperties(prefix = "nxj") public class NxjProperties { private String prefix; private String suffix; public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getSuffix() { return suffix; } public void setSuffix(String suffix) { this.suffix = suffix; } }3.写一个NxjService
public class NxjService { private NxjProperties nxjProperties; public NxjProperties getNxjProperties() { return nxjProperties; } public void setNxjProperties(NxjProperties nxjProperties) { this.nxjProperties = nxjProperties; } public String sayHello(String name){ return nxjProperties.getPrefix()+"-"+name+"-"+nxjProperties.getSuffix(); } }4.自动配置类
@Configuration @ConditionalOnWebApplication @EnableConfigurationProperties(NxjProperties.class) public class NxjServiceAutoConfig { @Autowired NxjProperties nxjProperties; @Bean public NxjService nxjService(NxjProperties nxjProperties){ NxjService nxjService = new NxjService(); nxjService.setNxjProperties(nxjProperties); return nxjService; } }5.要让自动配置类能生效,必须在类路径下:META-INF/spring.factories中配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.jd.nxj.autoconfig.NxjServiceAutoConfig
引入:
1.pom文件引入
<dependency> <artifactId>nxj-spring-boot-starter</artifactId> <groupId>org.jd.nxj</groupId> <version>1.0.0</version> </dependency>2.配置文件中写值,我们可以赋予上去
nxj.prefix=前缀 nxj.suffix=后缀3.编写controller测试
@Controller public class HelloController { @Autowired NxjService nxjService; @GetMapping("/nxj") @ResponseBody public String hello(){ return nxjService.sayHello("nxj"); } }结果:前缀-nxj-后缀