SpringBoot

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 可以用于跨项目的扫描规则

image-20230322204401403

   转载规则


《SpringBoot》 熊水斌 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录