zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Spring Boot条件化自动装配

SpringBoot自动 条件 装配
2023-06-13 09:12:41 时间

1、 Class条件注解

Class条件注解有一对语义相反的注解,@ConditionalOnClass和@ConditionalOnMissClass分别表达"当指定类存在时"和"当指定类不存在时"的语义。

源码:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

	/**
	 * The classes that must be present. Since this annotation is parsed by loading class
	 * bytecode, it is safe to specify classes here that may ultimately not be on the
	 * classpath, only if this annotation is directly on the affected component and
	 * <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
	 * use this annotation as a meta-annotation, only use the {@link #name} attribute.
	 * @return the classes that must be present
	 */
	Class<?>[] value() default {};

	/**
	 * The classes names that must be present.
	 * @return the class names that must be present.
	 */
	String[] name() default {};

}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnMissingClass {

	/**
	 * The names of the classes that must not be present.
	 * @return the names of the classes that must not be present
	 */
	String[] value() default {};

}

2、案例:

如果工程中有Jackson时,使用JSON序列化,没有使用String.valueOf()格式化

2.1、增加Jackson依赖到pom.xml,保持为true

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.3</version>
            <optional>true</optional>
        </dependency>

2.2、新增JSON Formatter实现

public class JsonFormatter implements Formatter {

    private final ObjectMapper objectMapper;
    
    public JsonFormatter(){
        this.objectMapper=new ObjectMapper();
    }
		//将对对象转换为json字符串
    public String format(Object obj) {
        try{
            return objectMapper.writeValueAsString(obj);
        }catch (JsonProcessingException e){
            throw new IllegalArgumentException(e);
        }
    }
}

2.3、新增JsonFormatter Bean声明到FormatterAutoConfiguration

@Configuration
public class FormatterAutoConfiguration {

    @Bean
    @ConditionalOnMissingClass(value = "com.fasterxml.jackson.databind.ObjectMapper")//如果classpath下没有ObjectMapper时
    public Formatter defaultFormatter(){
        return new DefaultFormatter();
    }

    @Bean
    @ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")//如果classpath下有ObjectMapper时
    public Formatter jsonFormatter(){
        return new JsonFormatter();
    }
}

2.4、重新构建formatter-spring-boot-starter

 mvn -Dmaven.test.skip -U clean install

2.5、加入formatter-spring-boot-starter

        <dependency>
            <groupId>com.tyschool</groupId>
            <artifactId>formatter-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

3、Bean条件注解

Bean条件注解也是成对出现的,例如@ConditionalOnBean和@ConditionalOnMissBean。ConditionOnBean仅匹配应用上下文中已处理的BeanDefinition。ConditionalOnMissBean逻辑相反。

源码:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {


	Class<?>[] value() default {};


	String[] type() default {};


	Class<? extends Annotation>[] annotation() default {};


	String[] name() default {};


	SearchStrategy search() default SearchStrategy.ALL;


	Class<?>[] parameterizedContainer() default {};

}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {


	Class<?>[] value() default {};


	String[] type() default {};


	Class<?>[] ignored() default {};


	String[] ignoredType() default {};


	Class<? extends Annotation>[] annotation() default {};


	String[] name() default {};


	SearchStrategy search() default SearchStrategy.ALL;


	Class<?>[] parameterizedContainer() default {};

}

4、Json格式化案例

  • 当前ObjectMapper Class不存在时,Bean为DefaultFormatter实例,其名称为"defaultFormatter"
  • 当前ObjectMapper Class 不存在时且具有Bean不存在时,BeanJsonFormatter默认构造器创建ObjectMapper实例,其名称为"jsonFormatter"
  • 当ObjectMapper Class 存在且其Bean也存在时,Bean为JsonFormatter构造器注入ObjectMapperBean,其名称为"objectMapperFormatter"

提示:

ObjectMapper Bean的初始化需要满足以下条件:

  • ObjectMapper必须存在于Class Path中
  • Jackson2ObjectMapperBuilder必须在Class Path中,源于org.springframework:spring-web 4.1.1,工程需依赖spring-boot-strater-web 1.2.0及以上版本
  • ObjectMapper Bean必须在所有Spring 应用上下文中

4.1、增加Jackson2ObjectMapperBuilder Maven依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.2.6.RELEASE</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.3</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

4.2、增加JsonFormatter构造器

    private final ObjectMapper objectMapper;

    public JsonFormatter(){
        this(new ObjectMapper());
    }
    
    public JsonFormatter(ObjectMapper objectMapper){
        
        this.objectMapper=objectMapper;
    }

4.3、新增JsonFormatterBean

@Configuration
public class FormatterAutoConfiguration {

    @Bean
    @ConditionalOnMissingClass(value = "com.fasterxml.jackson.databind.ObjectMapper")//如果classpath下没有ObjectMapper时
    public Formatter defaultFormatter(){
        return new DefaultFormatter();
    }

    @Bean
    @ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")//如果classpath下有ObjectMapper时
    @ConditionalOnMissingBean(Servlet.class)
    public Formatter jsonFormatter(){
        return new JsonFormatter();
    }

    @Bean
    @ConditionalOnBean(Servlet.class)//如果classpath有Servlet时
    public Formatter objectMapperFormatter(ObjectMapper objectMapper){
        return new JsonFormatter(objectMapper);
    }
}

4.4、重新构建formatter-spring-boot-starter

 mvn -Dmaven.test.skip -U clean install

4.5、引入formatter-spring-boot-starter

        <dependency>
            <groupId>com.tyschool</groupId>
            <artifactId>formatter-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency> 

4.6、重构引导类

@SpringBootApplication
public class FormatterBootStrap {

    public static void main(String[] args) {
        //创建Spring上下文
        ConfigurableApplicationContext context = new SpringApplicationBuilder(FormatterBootStrap.class)
                .web(WebApplicationType.SERVLET)
                .run(args);
        final Map<String, Object> map = new HashMap<String, Object>();
        map.put("name","tyschool");
        //获取bean
        Map<String, Formatter> beans = context.getBeansOfType(Formatter.class);
        //格式化数据
        beans.forEach((beanName,formatter)->{
            System.out.println(beanName+" "+formatter.getClass().getSimpleName()+" "+formatter.format(map));
        });
        context.close();
    }
}