首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Spring Boot] Spring Boot 装配实现原理

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

作者头像
架构探险之道
发布2020-01-14 14:37:18
3880
发布2020-01-14 14:37:18
举报
文章被收录于专栏:架构探险之道架构探险之道

[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. 自动装配

.


更多

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构探险之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • [Spring Boot] Spring Boot 装配实现原理
    • 模式注解装配
      • @Enable模块装配
        • 基于注解驱动实现
        • 基于接口驱动实现
      • 条件装配
        • 自动装配
          • 总结
            • 更多
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档