zoukankan      html  css  js  c++  java
  • Spring Boot 2 实践记录之 条件装配

    实验项目是想要使用多种数据库访问方式,比如 JPA 和 MyBatis。

    项目的 Service 层业务逻辑相同,只是具体实现代码不同,自然是一组接口,两组实现类的架构比较合理。

    不过这种模式却有一个问题,如果 Bean 是按实现类装配,则在切换数据库访问方式时,就需要大量的代码修改。如果按接口装配,则会出现歧义(同一接口有两个实现,无法自动装配)。

    虽然可以使用「首选Bean」或「限定」装配,但是与直接使用实现类装配一样,切换数据库访问地,仍然要大量修改源码。

    经过实验,使用「条件装配」实现了利用配置切换数据库访问方式,不需要修改代码了。

    示例:

    先定义 Service 接口:

    public interface UserServiceInterface {
        ......  
    }

    再定义 MyBatis 实现类:

    @Service
    @Conditional(MybatisCondition.class)
    public class UserServiceMybatisImpl implements UserServiceInterface {
        ......
    }

    注意其中的 @Conditional(MybatisCondition.class),MybatisCondition 类必须实现 org.springframework.context.annotation.Condition 接口,该接口仅有一个 matches 方法,当该方法返回真时,UserServiceMybatisImpl 被装配。

    MybatisCondition 的 matches 方法的逻辑被实现为根据配置文件中的 use.data.access.method 属性是否为 mybatis,来决定是否装配 UserServiceMybatisImpl 类:

    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class MybatisCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment env = context.getEnvironment();
            if (env.getProperty("use.data.access.method").equals("mybatis")) {
                return true;
            }
            return false;
        }
    }

    再定义 SPA 实现类及其 SpaCondition 类,实现方式与 Mybatis 相同,仅在配置项为 spa 时,装配 UserServiceSpaImpl 类:

    @Service
    @Conditional(SpaCondition.class)
    public class UserServiceSpaImpl implements UserServiceInterface {
        ......
    }
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class SpaCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment env = context.getEnvironment();
            if (env.getProperty("use.data.access.method").equals("spa")) {
                return true;
            }
            return false;
        }
    }

    定义一个类,自动装配 UserServiceInterface,并打印其类名:

    public class Test {
        @Autowired
        private UserServiceInterface userServiceInterface;
        
        public void testUserService() {
            System.out.println(userServiceInterface.getClass();
        }
    }      

    现在还不能运行,需要添加配置项。

    先将配置项配置为 mybatis:

    use.data.access.method = mybatis

    运行 Test 类的 testUserService 方法,结果为:

    UserServiceMybatisImpl

    将配置项修改为 spa:

    use.data.access.method = spa

    运行 Test 类的 testUserService 方法,结果为:

    UserServiceSpaImpl

    不过,有个小小的缺憾,就是在 Idea 中,如下代码行:

    @Autowired
    private UserServiceInterface userServiceInterface;

    会有错误提示:

    Could not autowire. There is more than one bean of 'UserServiceInterface' type.
    Beans:
    userServiceMybatisImpl   (UserServiceMybatisImpl.java) 
    userServiceSpaImpl   (UserServiceSpaImpl.java)

    由于配置项是在运行时读取的,Idea 在静态语法检查时,实在没办法搞定这个自动装配的判断。

    没关系,不影响运行!

  • 相关阅读:
    MySQL时间函数
    Linux安装php运行环境
    linux 防火墙配置
    CENTOS启动后网卡启动不了
    价值
    浏览器STATUS_INVALID_IMAGE_HASH报错解决方法
    wordpress更改域名最简单的方法
    Connection to 天mysql failed. [08001] Could not create connection to database server. Attempted ,报错处理方法
    centos实现三个节点高可用
    安装nginx1.16.1版本
  • 原文地址:https://www.cnblogs.com/matchless/p/10389918.html
Copyright © 2011-2022 走看看