组团学

Spring Boot条件化自动装配

阅读 (4544629)

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(); } }
需要 登录 才可以提问哦