S p r i n g B o o t SpringBoot SpringBoot
下面是我们用SpringXML的方式向容器中添加组件的方法:
下面是使用SpringBoot来声明组件类的方式:
@Configuration翻译为配置。
将一个类设置为配置文件,将该类下面的方法设置为Bean组件
//告诉SpringBoot这是一个配置类 == 配置文件
//相当于 (Spring配置文件)MyConfig.xml
@Configuration
public class MyConfig {
//给容器中添加组件.以方法名作为组件的id ↓
//相当于
@Bean
public Cat cat01(){
return new Cat();
}
/*相当于
*/
@Bean
public Pet tomcat(){
return new Pet("奔驰A200L");
}
}
自定义Bean的id
此处创建的Bean组件默认是单例的,无论从容器中获得多少次都一样。
id错误的错误信息
获得自定义的配置Bean类对象实例(默认单例)
配置类也是IOC中的Bean对象组件
SpringBoot2后@Configuration新增的注解–>@proxyBeanMethods
@proxyBeanMethods:代理bean的方法。
下面是控制台输出的配置类对象:
com.atguigu.boot.config.MyConfig E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBf59b6e0c@8dfe921
可以看到该配置类是SpringCGLIB创建的加强过的代理类。
这相当于我们获取到的本身就是代理对象,然后代理对象调用注册组件方法,SpringBoot默认逻辑:如果@Configuration(proxyBeanMethods = true)。
那就是代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
保持组件单实例,如果把proxyBeanMethods设置为false,则调用的方法返回的对象不再是同一个,并且获得到的配置类也不再是代理对象↓
该注解和组件依赖有很大的关系,如果一个类依赖了另外一个类,在该类中直接调用获得对方类实例的方法时,如果proxyBeanMethod是true,则获取的是正确的,如果是false则对应不上,看如下截图
如果是true,则用户的宠物就是容器中的宠物,如果是false,则用户的宠物不是容器中的宠物,每次调用获得宠物对象的方法都会获得不同的宠物实例。
默认是全模式,也就是默认为true,代理对象调用方法,创建的对象都是单例的。
设置建议
如果只是单纯注册组件,并且组件之间没有依赖,则推荐设置为false。
在底层中,使用轻量级模式较多。
//@Import注解可以创建出下面两个类型的无参构造器,用以调用
//相当于给容器中,自动创建出这两个类型的组件
@Import({Cat.class, DBHelper.class})
ch.qos.logback.core.db.DBHelper@415e0bcb
可以看到,IOC容器里确实有了通过@Import注解所声明的对象组件了。
条件装配:满足Conditional指定的条件,则进行组件注入
@Condition注解派生了很多注解,这些注解用来具体指定功能
常见的@Conditional注解派生注解
@ConditionalOnBean:当容器中存在我们指定的Bean时,我们才干某些事情
@ConditionalMissingBean:当容器没有这个Bean组件的时候,我们才干某些事情
@ConditionalOnClass:当容器中有某一个类的时候,我们才干某些事情
@ConditionalMissingClass:当容器没有这个类的时候,我们才干某些事情
@ConditionalOnResource:项目路径中,存在一个资源,我们才干某些事情
@ConditionalOnJava:是指定的Java版本号时,我们才干某些事情
@ConditionalOnWebApplication:当我们的应用是Web应用时,我们才干某些事情
@ConditionalOnNotWebApplication:当我们的应用不是Web应用时,我们才干某些事情
@ConditionalOnSingleCandidate:当我们指定的实例在容器中只有一个时,我们才干某些事情
@ConditionalOnProperty:当配置文件中配置了某个属性的时候,我们才干某些事情
@ConditionOnBean注解
上卖弄的API是判断容器中是否包含该Bean组件,此处我们注释了BenChi的@Bean注解,所以是false
使用OnBean注解来判断
@ConditionalOnBean(name = "tom")
@Bean("Tomcat")
public Cat cat01(){
return new Cat();
}
@ImportResource
该注解翻译为导入资源
如果我们写了beans.xml,也就是Spring形式的IOC容器配置文件,此时如果只是beans.xml文件的话,SpringBoot是无法识别该配置文件的,我们需要用到@ImportResource注解,注解传入配置文件的路径
增加@ImportResource注解
@ImportResource("classpath:beans.xml")
public class MyConfig {
如果我们需要让Java类的值和配置文件的值进行绑定,在传统的做法中则是获得配置文件的输入流,然后进行遍历和字符串拼接,比较麻烦,尤其是在配置条目非常多的时候,而SpringBoot则可以通过注解非常迅速的完成这些操作。
//组件标识注解 --> 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
@RestController
public class HelloController {
@Autowired
Car car;//使用自动注入
@RequestMapping("/car")
public Car car(){
return this.car;
}
该注解的使用总结:创建一个POJO类,在该类上标识该注解,在注解中传入要赋值对应前缀的配置文件属性前缀,设置后在控制器里进行该类定义和自动装配,然后输出该类即可,只要有配置文件就可以自动装配。
使用@EnableConfigurationProperties注解将Car类开启属性绑定,并自动注册到容器中
为什么要这么做,我们不是有@Component注解将Car类标识为了容器组件了吗?这么做会不会多此一举呢?
并不会,如果是第三方Jar包的类,我们怎么可能给这个类标记上@Component呢,所以我们尽量要用@EnableConfigurationProperties注解来自动绑定和注册,并且该注解直接传入类的class对象即可。如下展示。
基于增加@EnableConfigurationProperties注解的改动
这样做的泛用性更高一些,比较推荐,注意,上面的修改并没有去掉@ConfigurationProperties(prefix = “mycar”)注解,只是删除了@@Component注解,然后在配置类增加了@EnableConfigurationProperties注解。
上面两种组合都可以完成,但是推荐第二种。
首先我们前面有说到:
@SpringBootApplication是由3个注解组合而成,也就是说,我们在使用@SpringBootConfiguration时,也可以写组成该注解的那3个注解,效果一致,只是@SpringBootApplication包含了这3个注解
三个注解如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
@SpringBootConfiguration的作用是表示这是一个配置类
@ComponentScan就是包扫描
@EnableAutoConfiguration是核心功能的注解,下面将详细介绍该注解。
英文翻译 --> EnableAutoConfiguration:启用自动配置
该注解是组成@SpringBootApplication注解的核心注解,该注解也是其他注解组成而成,它的组成注解如下:
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
AutoConfigurationPackage:自动配置包
AutoConfigurationImportSelector:自动配置导入选择器
@AutoConfigurationPackage
自动配置包,指定了默认的包规则
源码:
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
@Import注解就是给容器导入一个组件,这里Import注册了一个组件:Registrar类,该类表示的是批量注册。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
利用Registrar给容器导入一系列组件
//该方法传入了两个参数
//AnnotationMetadata表示注解的元信息
//
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
方法体根据注解获得包名,相当于得到了主类所在的包名,把这个包名封装到了一个String数组里,然后AutoConfigurationPackages.register()注册进去,相当于Registrar类把某一个包下的所有组件批量注册起来
也就是说组成
@EnableAutoConfiguration
注解的第一个注解@AutoConfigurationPackage的功能就是利用批量注册类来批量注册组件,根据元注解信息获得包路径,然后批量注册该包路径下的组件(该包路径是SpringBootApplication所在的包)
@EnableAutoConfiguration的第二个组成注解:
@Import({AutoConfigurationImportSelector.class})
核心源码
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
调用List
利用Spring的加载工厂来加载这些组件。
上面方法最终得到加载所有的组件。
从META-INF/spring.factories位置来加载一个文件
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
上面的包里也有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器加载的所有配置。
按需开启:
虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是最终会按需配置:
可以看到AOP类里开启了满足条件再执行的注解,只有导入了AOP的包,该组件下面的代码只会执行,执行了这些代码,自动配置才会生效。
批处理也不能生效,因为没有导入这些包,也就是没有满足这些定义的条件。
这些类都没有导入,都是爆红了的,所以它们都没有生效。
虽然这些类都一股气的导入了,但是要按照SpringBoot的按需加载来实际的注册。
总结:按需加载,条件装配
在自动配置中,matchIfMissing是默认认为配置的意思,就算没有也认为你有,此处的AOP功能,上面的条件不符合,但是有一处简单的AOP场景符合了条件,如下。
**AutoConfiguration是SpringBoot定义的一种自定义配置类的规则。
底层帮我们配置好了SpringMVC
当传入文件解析器对象时,如果文件名不符合规范,则SpringBoot会纠正,重新返回给容器,因为方法名是规范的,以方法注入组件,不设置Bean注解的值时,则默认使用方法名作为容器中Bean组件的id。
编码配置
SpringMVC解决编码问题。
修改默认配置
SpringBoot默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先
因为@ConditionlOnMissingBean注解,该注解表示,当容器中没有这个东西的时候才会自动配置。
上面相当于自定义了编码过滤器,此时容器不再是没有编码过滤器,那么SpringBoot也就不会再默认自动配置编码过滤器。
总结
在我们定义的SpringBoot统一配置文件中,写如下配置:
注意这个文件名必须是英文的,还有就是bug.jpg也不行,比较奇怪?
#默认值是 banner.jpg 我们可以把我们的文件修改为banner.jpg 这样可以直接找到
#spring.banner.image.location=classpath:banner.jpg
#自定义↓
spring.banner.image.location=classpath:222.jpg
首先我们在pom文件中则,增加一组依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
去插件市场下载lombok插件
如果搜索不到Lombok,就需要设置一下:
插件市场旁边有个设置按钮,点击它在展开的选项中点击 HTTP Proxy Settings
在打开的页面中点击“Check connection”,意思是检查连接,然后点击该按钮进行设置。
输入插件网站的地址
http://plugins.jetbrains.com/
我们找到先前的Car POJO类,删除该类里的getter和setter方法,还有toString方法。
在该类上增加@Data注解↓
热更新,没什么卵用
导入依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
加入后,按Ctrl+F9,表示项目重新编译,编译后devtools会帮我们重写部署。
已亲测,请自行测试!
总结:没用