最近碰到个这样的需求,需要同一套代码适配个版本数据库(数据库不同,且部分表的字段及关联关系可能会不同),即这套代码配置不同的数据库都能跑。项目采用的框架为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图吧
        

        

三、小结

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

SpringBoot自定义Condition注解的更多相关文章

  1. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  2. Springboot中使用自定义参数注解获取 token 中用户数据

    使用自定义参数注解获取 token 中User数据 使用背景 在springboot项目开发中需要从token中获取用户信息时通常的方式要经历几个步骤 拦截器中截获token TokenUtil工具类 ...

  3. [技术博客] SPRINGBOOT自定义注解

    SPRINGBOOT自定义注解 在springboot中,有各种各样的注解,这些注解能够简化我们的配置,提高开发效率.一般来说,springboot提供的注解已经佷丰富了,但如果我们想针对某个特定情景 ...

  4. 更加灵活的参数校验,Spring-boot自定义参数校验注解

    上文我们讨论了如何使用@Min.@Max等注解进行参数校验,主要是针对基本数据类型和级联对象进行参数校验的演示,但是在实际中我们往往需要更为复杂的校验规则,比如注册用户的密码和确认密码进行校验,这个时 ...

  5. SpringBoot自定义注解

    1.注解的概念 注解是一种能被添加到java代码中的元数据,类.方法.变量.参数和包都可以用注解来修饰.注解对于它所修饰的代码并没有直接的影响. 2.注解的使用范围 1)为编译器提供信息:注解能被编译 ...

  6. SpringBoot 自定义注解 实现多数据源

    SpringBoot自定义注解实现多数据源 前置学习 需要了解 注解.Aop.SpringBoot整合Mybatis的使用. 数据准备 基础项目代码:https://gitee.com/J_look/ ...

  7. SpringBoot自定义注解@YamlPropertySource加载yml或者yaml文件(扩展了@PropertySource)

    1:概述 SpringBoot的@PropertySource注解只支持加载 properties结尾的文件.当使用@ConfigurationProperties 注解配合@EnableConfig ...

  8. SpringBoot 使用 JSR303 自定义校验注解

    JSR303 是 Java EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是hibernate Validator,有了它,我们可以在实体类的字段上标注不同的注解实现对数 ...

  9. 自定义ConditionalOnXX注解

    一.Conditional注解介绍 对SpringBoot有足够了解的小伙伴应该都用过Conditional系列注解,该注解可用在类或者方法上用于控制Bean的初始化. 常用的Conditional注 ...

随机推荐

  1. Lp距离, L1范数, 和L2范数(转载)

    范式可以理解成距离 转载自: https://blog.csdn.net/hanhuili/article/details/52079590 内容如下: 由此可见,L2其实就是欧式距离.工程上,往往不 ...

  2. idea中使用python环境

    idea中使用python环境,需要下载相关的python sdk 可以添加选择自己的python环境

  3. 不使用xftp上传/下载文件到linux

    yum install lrzsz    # 安装软件 window端上传到linux端: 1. window端先压缩需上传的文件 2. linux端运行命令rz 3. 在弹出的窗口选择压缩好的文件, ...

  4. MACbook安装WIN7后亮度调节的办法

     MACbook安装WIN7后亮度调节的办法:1.按WIN+X打开移动中心,第一个就是亮度调节.或者右击托盘区的电池,选择移动中心也可以.2.右击托盘区域的电池,选择电源管理,在界面中调节亮度. 3. ...

  5. 基于paramiko将文件上传到服务器上

    通过安装使用paramiko模块,将本地文件上传到服务器上 import paramiko import datetime import os hostname = '服务器ip' username ...

  6. nginx 配置实例(ssl、proxy、cache、gzip、upstream等优化)

    [root@xxxxxxxxxxxxxx ~]# cat /usr/local/nginx/conf/nginx.conf user nobody; worker_processes ; worker ...

  7. Javascript 笔记:原型和原型链

    一.函数对象和普通对象 凡是通过new Function()创建的都是函数对象,其它的都是普通对象.Function,Object,Array,Number,String,Boolean,Date是J ...

  8. java json解析(转)

    转自:https://www.cnblogs.com/sunnywindycloudy/p/8343013.html 给服务端发送请求后,服务端会返回一连串的数据,这些数据在大部分情况下都是XML格式 ...

  9. Hbase Filter之PrefixFilter

    PrefixFilter PrefixFilter是将rowkey前缀为指定字符串的数据全部过滤出来并返回给用户.例如: Scan scan = new Scan(); scan.setFilter( ...

  10. idea中maven项目打jar包

    从Eclipse换成Idea的小伙伴们可能会找不到Eclipse中Maven项目打jar包的方法,因为eclipse只需要在工程上点击右键,右键菜单中就有Maven打包的相关选项. 然而Idea的右键 ...