专栏首页架构探险之道[Spring Boot] Spring Boot 装配实现原理

[Spring Boot] Spring Boot 装配实现原理

[Spring Boot] Spring Boot 装配实现原理

简介

本文就 Spring Boot 的配置装配实现方式做了介绍,主要是常用的模式注解、@EnableXXX注解、条件注解和自动装配是如何实现的。


手机用户请横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。

平台

地址

CSDN

https://blog.csdn.net/sinat_28690417

简书

https://www.jianshu.com/u/3032cc862300

个人博客

https://yiyuery.github.io/NoteBooks/


正文

模式注解装配

  • @Component注解的拓展
  • @Service、@Controller、@Repository
  • @Configruation

@Enable模块装配

参考实现

  • EnableWebMvc
  • EnableCaching

基于注解驱动实现

参考EnableWebMvc

  • 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfig.class)
public @interface EnableHello {

}
  • 配置类
@Configuration
public class HelloWorldConfig {

    @Bean
    public World world(){
        return new World();
    }
}
  • 启动类
@SpringBootApplication
@EnableHello
public class BootAutoConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootAutoConfigApplication.class, args);
    }
}
  • 测试用例
@SpringBootTest
public class BootAutoConfigTest {

    @Autowired
    private World world;

    @Test
    public void say2World() {
        System.out.println(world.say());
    }
}

say2World 输出

.

基于接口驱动实现

实现ImportSelector接口,根据判断条件导入配置类,参考@EnableCaching注解

  • 注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({HelloConfigSelector.class})
public @interface EnableHelloSelector {

    boolean isMac() default false;

}
//选择器实现
public class HelloConfigSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        MultiValueMap<String, Object> metaData = importingClassMetadata.getAllAnnotationAttributes(EnableHelloSelector.class.getName());
        Boolean isMac = (Boolean) metaData.get("isMac").get(0);
        if (isMac) {
            return new String[]{HelloWorldConfig.class.getName()};
        }else{
            return new String[]{HelloWorldConfig.class.getName(),HelloFutureConfig.class.getName()};
        }
    }
}
  • 配置类
@Configuration
public class HelloWorldConfig {

    @Bean
    public World world(){
        return new World();
    }
}

@Configuration
public class HelloFutureConfig {

    @Bean
    public Future future(){
        return new Future();
    }
}
  • 启动类
@SpringBootApplication
@EnableHelloSelector
public class BootAutoConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootAutoConfigApplication.class, args);
    }
}
  • 测试用例
@SpringBootTest
public class BootAutoConfigTest {

    @Autowired
    private World world;


    @Test
    public void say2World() {
        System.out.println(world.say());
    }

    @Autowired
    private Future future;

    @Test
    public void say2FutureAndWorld() {
        System.out.println(world.say());
        System.out.println(future.say());
    }
}

say2FutureAndWorld 输出

.

条件装配

  • 条件注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemCondition.class)
public @interface ConditionOnSystem {

    String system();
}
  • 匹配条件
public class OnSystemCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> metaDataMap = metadata.getAnnotationAttributes(ConditionOnSystem.class.getName());
        return "windows".equals(metaDataMap.get("system"));
    }

}
  • 补充条件装配@Bean
@Configuration
@Slf4j
public class HelloFutureConfig {

    @Bean
    public Future future(){
        log.info("future bean init");
        return new Future();
    }

    @ConditionOnSystem(system = "windows")
    @Bean
    public Future future2(){
        log.info("future bean init for windows");
        return new Future();
    }

    @ConditionOnSystem(system = "mac")
    @Bean
    public Future future3(){
        log.info("future bean init for mac");
        return new Future();
    }
}
  • 启动类
@SpringBootApplication
@EnableHelloSelector
public class BootAutoConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootAutoConfigApplication.class, args);
    }
}
  • 日志输出

.

此处同时使用了@Enable自定义装配条件装配

自动装配

  • 定义自动装配配置类
@Configuration
@Import({HelloWorldConfig.class,HelloFutureConfig.class})
public class HelloAutoConfiguration {
}
  • META-INF/spring.factories中填写自动装配类信息

.

  • 启动类中注释掉手动装配的配置,重新启动
@SpringBootApplication
//@EnableHelloSelector
//@EnableHello
public class BootAutoConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootAutoConfigApplication.class, args);
    }
}
  • 查看输出

.

比对可以看出,输出结果和@EnableHelloSelector实现的效果是一致的。

总结

Spring Boot 遵从约定大于配置的规则,提供了很多种方式来实现手动装配和自动装配

  1. 手动装配:
  • 模板注解:@Service 等
  • @Enable注解:基于注解驱动实现(配置定义),基于接口驱动实现(接口定义)
  • 条件装配

.

  1. 自动装配

.


更多

扫码关注架构探险之道,回复『源码』,获取本文相关源码和资源链

本文分享自微信公众号 - 架构探险之道(zacsnz1314),作者:MasterYang

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Security SSO 授权认证(OAuth2)

    我们将讨论如何使用Spring Security OAuth2和Spring Boot实现SSO - 单点授权认证。

    架构探险之道
  • [设计模式] 命令模式

    假定我们定义一个宏命令实现回家后的一个智能操作:包含开灯和开电视,并要求它支持撤销能力。

    架构探险之道
  • [ORM] MyBatis 中是如何运用的代理模式的?

    本文主要介绍设计模式之代理模式,并分析代理模式在 Mybatis 中是如何使用的?

    架构探险之道
  • Spring注解开发

    爱撒谎的男孩
  • Spring Boot 自动配置的 “魔法” 是如何实现的?

    Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

    用户1257393
  • Spring Boot 自动配置的 “魔法” 是如何实现的?

    Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

    三哥
  • Spring Boot 自动配置的“魔法”是如何实现的?

    Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

    Java团长
  • Spring Boot是如何实现自动配置的

    Spring Boot 是 Spring 旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为...

    黄泽杰
  • Springboot自动配置的运行原理(自定义一个自动配置)

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-aut...

    凡人飞
  • 手撸一个自定义starter,它不香吗

    springboot 中有很多的starter 。我们用起来很爽不是吗,之所以这么爽难道不是因为我们少了很多配置吗,之前我们想要使用jdbcTemplete 是...

    程序员爱酸奶

扫码关注云+社区

领取腾讯云代金券