SpringBoot自定义Condition注解

    最近碰到个这样的需求,需要同一套代码适配个版本数据库(数据库不同,且部分表的字段及关联关系可能会不同),即这套代码配置不同的数据库都能跑。项目采用的框架为SpringBoot+Mybatis。经过一番思考,思路如下:
    (1)在业务层(service)和数据访问层(Mapper)之间添加一层适配层,用来屏蔽数据库的差异
    (2) 适配层中代码均采用接口加实现类的方式,不同的数据库用的实现类不同
     (3)业务层(service)中全部采用面向接口编程
     (4)项目启动后只实例化和数据库相匹配的适配层实现类
    实现上面的一个关键点是对bean的实例化添加一个条件判断来控制。其实SpringBoot里面新增了很多条件注解,能实现这个功能。但是都有些局限性,最终是采用自定义条件注解的方案。

一、SpringBoot自带的注解ConditionalOnProperty

          这个注解不做过多的解释,只说通过这个注解怎么实现我们的功能。
假设我们application.properties中配置一个配置项为
#bean实例化条件配置项
conditionKey=1.0
2
 
1
#bean实例化条件配置项
2
conditionKey=1.0
    那么只需要加上@ConditionalOnProperty的name和havingValue就能实现,只有配置文件中name对应的配置项的值和havingValue内容一致才实例化这个对象。
针对我们上面配置的application.properties的内容,@ConditionalOnProperty的使用案例如下面代码所示
// 仅当conditionKey==1.0的时候实例化这个类
@Component
@ConditionalOnProperty(name = "conditionKey", havingValue = "1.0")
public class Manage1Impl  implements  MyManage{

    @Override
    public void sayHello() {
        System.out.println("我是实现类01");
    }

    @PostConstruct
    public void init() {
        this.sayHello();
    }
}
15
 
1
// 仅当conditionKey==1.0的时候实例化这个类
2
@Component
3
@ConditionalOnProperty(name = "conditionKey", havingValue = "1.0")
4
public class Manage1Impl  implements  MyManage{
5
 
          
6
    @Override
7
    public void sayHello() {
8
        System.out.println("我是实现类01");
9
    }
10
 
          
11
    @PostConstruct
12
    public void init() {
13
        this.sayHello();
14
    }
15
}
    这个注解的局限性 这个注解的havingValue里面只能配置一个值。
    由于项目个性化需求,希望这个havingValue可以配置多个值, name对应的配置项的Value只要满足havingValue里面多个值的就表示匹配正确。即,havingValue里面可以配置多个值,name对应配置项的值来和havingValue匹配时,采用逻辑或匹配,满足一个值就算匹配正确。

二、自定义条件注解

(1)思路
          注解里面有2个属性,具体如下
      • name:String类型,用来接受application.properties的配置项的key
      • havingValue:String数组类型,用来和name对应key的Value进行匹配
(2)定义注解
package com.zxy.config;

import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
/**
 * 自定义条件注解
 * @author ZENG.XIAO.YAN
 * @version 1.0
 * @Date 2019-04-15
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(CustomOnPropertyCondition.class)
public @interface CustomConditionalOnProperty {

    /**
     * 条件变量的name
     */
    String name() default "";

    /**
     * havingValue数组,支持or匹配
     */
    String[] havingValue() default {};

}
28
 
1
package com.zxy.config;
2
 
          
3
import org.springframework.context.annotation.Conditional;
4
import java.lang.annotation.*;
5
/**
6
 * 自定义条件注解
7
 * @author ZENG.XIAO.YAN
8
 * @version 1.0
9
 * @Date 2019-04-15
10
 */
11
@Retention(RetentionPolicy.RUNTIME)
12
@Target({ElementType.TYPE, ElementType.METHOD})
13
@Documented
14
@Conditional(CustomOnPropertyCondition.class)
15
public @interface CustomConditionalOnProperty {
16
 
          
17
    /**
18
     * 条件变量的name
19
     */
20
    String name() default "";
21
 
          
22
    /**
23
     * havingValue数组,支持or匹配
24
     */
25
    String[] havingValue() default {};
26
 
          
27
}
28
 
          
(3)定义注解的匹配规则
package com.zxy.config;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;

/**
 * 自定义条件注解的验证规则
 * @author ZENG.XIAO.YAN
 * @version 1.0
 * @Date 2019-04-15
 */
public class CustomOnPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Map<String, Object> annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(CustomConditionalOnProperty.class.getName());
        String propertyName = (String) annotationAttributes.get("name");
        String[] values = (String[]) annotationAttributes.get("havingValue");
        if (0 == values.length) {
            return false;
        }
        String propertyValue = conditionContext.getEnvironment().getProperty(propertyName);
        // 有一个匹配上就ok
        for (String havingValue : values) {
            if (propertyValue.equalsIgnoreCase(havingValue)) {
                return true;
            }
        }
        return false;
    }
}
x
 
1
package com.zxy.config;
2
 
          
3
import org.springframework.context.annotation.Condition;
4
import org.springframework.context.annotation.ConditionContext;
5
import org.springframework.core.type.AnnotatedTypeMetadata;
6
import java.util.Map;
7
 
          
8
/**
9
 * 自定义条件注解的验证规则
10
 * @author ZENG.XIAO.YAN
11
 * @version 1.0
12
 * @Date 2019-04-15
13
 */
14
public class CustomOnPropertyCondition implements Condition {
15
 
          
16
    @Override
17
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
18
        Map<String, Object> annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(CustomConditionalOnProperty.class.getName());
19
        String propertyName = (String) annotationAttributes.get("name");
20
        String[] values = (String[]) annotationAttributes.get("havingValue");
21
        if (0 == values.length) {
22
            return false;
23
        }
24
        String propertyValue = conditionContext.getEnvironment().getProperty(propertyName);
25
        // 有一个匹配上就ok
26
        for (String havingValue : values) {
27
            if (propertyValue.equalsIgnoreCase(havingValue)) {
28
                return true;
29
            }
30
        }
31
        return false;
32
    }
33
}
34
 
          
(4)使用案例
    直接参考下面2图吧
          1222688-20190528124147126-998854181.png

          1222688-20190528124147863-727858945.png

三、小结

    自定义Condition注解,主要就2步
(1)定义一个条件注解
(2)定义一个条件的校验规则

转载于:https://www.cnblogs.com/zeng1994/p/8c10310d8a042d56eddd40635afb6e93.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,我们可以自定义异常类来处理应用程序中的异常情况。以下是一个简单的示例: 首先,定义一个自定义异常类,例如`CustomException`,继承自`RuntimeException`或其子类: ```java public class CustomException extends RuntimeException { private String errorCode; public CustomException(String errorCode, String message) { super(message); this.errorCode = errorCode; } public String getErrorCode() { return errorCode; } } ``` 然后,在需要使用自定义异常的地方,可以通过抛出该异常来处理异常情况。例如,在一个Controller中: ```java @RestController public class MyController { @GetMapping("/doSomething") public void doSomething() { // 某些条件下抛出自定义异常 if (someCondition) { throw new CustomException("ERROR_CODE", "出错了"); } // 其他业务逻辑 } } ``` 最后,我们可以定义一个全局异常处理器来捕获并处理自定义异常。创建一个`@ControllerAdvice`注解标记的类,例如`GlobalExceptionHandler`: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(CustomException.class) public ResponseEntity<ErrorResponse> handleCustomException(CustomException ex) { ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode(), ex.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } } ``` 在上述代码中,`handleCustomException`方法用于处理`CustomException`异常,并返回一个自定义的错误响应对象`ErrorResponse`。 这样,当应用程序中抛出`CustomException`异常时,全局异常处理器会捕获该异常并返回相应的错误响应。 希望这个示例对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值