SpringBoot手动装配,自定义Enable模块

前言

前面我们介绍了简单详细的SpringBoot自动配置原理解析,今天这篇文章主要是介绍下如何是实现手动配置,自定义Enable模块,

基于注解驱动实现

基于注解的驱动实现是最基本的自定义Enable模块,它是不带条件的装配。首先我们来看看如何来实现!

第一步: 定义好配置类

这里定义了配置类SayHelloWorldConfiguration

public class SayHelloWorldConfiguration {
    @Bean
    SayHelloWorld sayHelloWorld() {
        System.out.println("********加载HelloConfig");
        return new SayHelloWorld();
    }
}

这里就是实例化SayHelloWorld类,添加@Bean注解表明该方法实例化的对象会被加载到IOC容器之中。

第二步:定义EnableXXX注解

这里定义EnableHello注解,并且通过@Import注解将SayHelloWorldConfiguration配置类导入并加载到IOC容器。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
//引入HelloConfig配置类
@Import({SayHelloWorldConfiguration.class})
public @interface EnableHello {

}

第三步:在SpringBoot的启动类上添加Enable注解

至此基于注解驱动的手动配置就好了。启动之后我们就可以拿到实例化后的SayHelloWorld对象。但是,他这个是不能带任何条件的。

基于选择器实现的手动配置

与基于注解驱动的不同的是,基于选择器实现的手动配置需要增加一个选择器。步骤如下:

第一步 自定义选择器,实现ImportSelector

public class HelloWorldImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //获取注解上的属性
        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(EnableSelectorHelloWorld.class.getName());
        Boolean isLinux = (Boolean) annotationAttributes.get("isLinux");
        return new String[]{isLinux ? SayHelloWorldConfiguration.class.getName() : SayHelloWorldConfiguration2.class.getName()};
    }
}

这个选择器可以根据注解中传入的参数,返回不同的配置类,如上,当注解中的isLinux为true时,返回的配置类是SayHelloWorldConfiguration,否则,返回的配置类是SayHelloWorldConfiguration2

第二步:定义Enable注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({HelloWorldImportSelector.class})
public @interface EnableSelectorHelloWorld {

    boolean isLinux();
}

这里引入的是我们前面定义的选择器类。
后面的步骤跟基于注解驱动实现一致,在此就不在赘述了。

条件装配

如果某些配置类需要满足一定的条件才能启动,该如何实现呢?这就需要用到条件装配了。条件装配的配置步骤如下:

第一步:定义Condition的实现类

public class OnSystemPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取注解属性
        Map<String, Object> attrs = annotatedTypeMetadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        //获取系统值
        String system = String.valueOf(attrs.get("value"));
        String currentOs = System.getProperty("os.name");
        boolean result = currentOs.contains(system);
        System.out.println("********currentOs=" + currentOs + "匹配结果是=" + result);
        return result;
    }
}

这里的代码也比较简单,就是根据ConditionalOnSystemProperty注解传入的value值,是否包含在当前系统的系统名中,如果是的话则返回true。否则,返回false。返回true的话,则会加载配置类中通过@Bean定义的对象。

第二步:定义配置类

public class SayHelloWorldConfiguration2 {
    /**
     * @return
     */
    @ConditionalOnSystemProperty(value = "Windows")
    @Bean
    SayHelloWorld sayHelloWorld() {
        System.out.println("*********开始装配SayHelloWorld");
        return new SayHelloWorld();
    }
}

定义Enable注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({SayHelloWorldConfiguration2.class})
public @interface EnableConditionHelloWorld {
}

总结

手动装配其实也是很简单的。上面就简单的示例了三种情况下的装配。希望对读者朋友们有所帮助。

源码下载

源码下载


作者:码农飞哥

微信公众号:码农飞哥