SpringBoot
自动配置
全部加载 127 自动配置类(预先写死)
按照条件装配规则,按需注入
@ConditionalOnClass 注解
保证了在类路径下发现某个类,才会注入Bean对象。而这个“某个类”,需要导入一些特定的包。因此导入了特定的依赖,就会自动注入
@ConditionalOnProperty 注解
配置文件中是否出现某个字段,配置了则生效
@ConditionalOnBean 注解
判断容器中是否存在某种类型或某个名字的 Bean 组件。这种时候可以先在主启动类下查询容器中是否注入了这个 Bean 对象(按类型或按名字,getBeanDefinitionNames 方法)
帮助用户的 Bean 规范化,以用户配置的 Bean 优先
以 AopAutoConfiguration
为例,介绍其条件装配的设计。
@ConditionalOnClass
和@ConditionalOnMissngClass
注解本质上相同,但是折磨人的设计,``@ConditionalOnClass中有
Class[]而
@ConditionalOnMissingClass中没有
Class[]`。导致前者可以直接使用 Class,而后者却要写死字符串
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
@Bean
static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
return (beanFactory) -> {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
};
}
}
}
@ConditionalOnBean + @ConditionalOnMissingBean 搭配使用
如果没有手动注入一个特定类型的对象(例如:MultipartResolver),那么由于@ConditionalOnBean的限制,那么底层也不会自动注入。但是如果用户手动注入了一个对象,但是 name 是用户任意定义的,同时框架底层可能还依赖这个 name,那么@ConditionalOnMissingBean就发挥了作用,将用户定义的这个 Bean 取一个预先定义好的别名。(这个别名是框架底层依赖的)
这种设计挺巧妙,但是意义在哪里呢?如果不允许使用者在框架外面自定义多个相同类型的 Bean,那么框架底层实现时,使用getBeanByType即可,根本没必要取预先定义好的别名,这样多此一举。但是假如允许用户在框架外面自定义多个相同类型的 Bean,最终生效的是哪一个呢?
这种设计的意义在于,Spring 集成别的框架时,可能这个别名是别的框架规定死的,而不是 Spring 框架对其进行了限制。使用这种设计,框架的使用者不需要知道这个规定死的字段
面试题
SpringBoot 接口开发的常用注解有哪些?
注解 | 作用 |
---|---|
@Controller |
标记此类是一个控制器,可以返回视图解析器指定的 html 页面,通过搭配 @ResponseBody 可以将结果返回 json、xml 等数据 |
@RestController |
相当于 @Controller + @ResponseBody |
@RequestMapping |
定义接口地址,可以标记在类上,也可以标记在方法上 |
@RequestBody |
定义在方法上,用于将前端传入的 JSON 串转化成 Java 对象 |
@PathVariable |
接收请求路径中的占位符的值 |
@ApiOperation |
Swagger 注解,对接口方法进行说明 |
@Api |
Swagger 注解,对接口类进行说明 |
@Autowired |
基于类型注入 |
@Resource |
默认基于名称注入,如果失败则转为基于类型注入 |
@ComponentScan
可以用于跨项目的扫描规则
