使用SpringBoot根据配置注入接口的不同实现类(代码演示)

目录
  • 一.引言
  • 二.代码演示
    • 1.问题描述
  • 2.解决方案
    • 2.1使用@Autowired的时候将接口变量名改为实现类的限定名
    • 2.2 使用@Autowired配合@Qualifier指定限定名注入实现类
    • 2.3@ConditionalOnProperty
  • 三.总结

一.引言

我们在使用springboot进行开发的时候经常用到@Autowired@Resource进行依赖注入,但是当我们一个接口对应多个不同的实现类的时候如果不进行一下配置项目启动时就会报错,那么怎么根据不同的需求注入不同的类型就是一个值得考虑的问题,虽然@Autowired@Resource就可以实现,但是我们也可以选择更加灵活的@ConditionalOnProperty注解来实现

二.代码演示

1.问题描述

TestController.java

package com.example.demo.controller;

import com.example.demo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName TestController
 * @Author xuwei
 * @DATE 2022/6/28
 */
@RestController
@RequestMapping("test")
public class TestController {

    //注入需要的service
    @Autowired
    TestService testService;

    @RequestMapping("test")
    public void test(){
        testService.sayHello();
    }
}

TestService.java

package com.example.demo.service;

/**
 * @InterfaceName TestService
 * @Author xuwei
 * @DATE 2022/6/28
 */
public interface TestService {
    /**
     * sayHello方法
     */
    void sayHello();
}

TestService实现类一  TestServiceImplOne.java

package com.example.demo.service.impl;

import com.example.demo.service.TestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @ClassName TestServiceImplOne
 * @Author xuwei
 * @DATE 2022/6/28
 */
@Service
public class TestServiceImplOne implements TestService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplOne.class);
    /**
     * sayHello方法
     */
    @Override
    public void sayHello() {
        LOGGER.info("I am TestServiceImplOne");
    }
}

TestService实现类二 TestServiceImplTwo.java

package com.example.demo.service.impl;

import com.example.demo.service.TestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @ClassName TestServiceImplTwo
 * @Author xuwei
 * @DATE 2022/6/28
 */
@Service
public class TestServiceImplTwo implements TestService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplTwo.class);
    /**
     * sayHello方法
     */
    @Override
    public void sayHello() {
        LOGGER.info("I am TestServiceImplTwo");
    }
}

这时我们的程序启动会报错,大概意思就是找到了两个实现类

***************************
APPLICATION FAILED TO START
***************************
Description:
Field testService in com.example.demo.controller.TestController required a single bean, but 2 were found:
    - testServiceImplOne: defined in file [/Users/xuwei/Desktop/Projects/IdeaProjects/demo/target/classes/com/example/demo/service/impl/TestServiceImplOne.class]
    - testServiceImplTwo: defined in file [/Users/xuwei/Desktop/Projects/IdeaProjects/demo/target/classes/com/example/demo/service/impl/TestServiceImplTwo.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

2.解决方案

2.1使用@Autowired的时候将接口变量名改为实现类的限定名

TestController.java修改为如下

package com.example.demo.controller;

import com.example.demo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName TestController
 * @Author xuwei
 * @DATE 2022/6/28
 */
@RestController
@RequestMapping("test")
public class TestController {

    //修改变量名为实现类的限定名
    @Autowired
    TestService testServiceImplOne;

    @RequestMapping("test")
    public void test(){
        testServiceImplOne.sayHello();
    }
}

我们可以将接口的命名改为对应实现类的限定名,默认为类名且首字母小写,当然我们也可以自己给接口的实现类配置限定名,例如@Service("serviceOne") 之后在引用时使用我们配置的限定名,这样程序都可以自动找到实现类,测试结果如下:

2.2 使用@Autowired配合@Qualifier指定限定名注入实现类

其实这个方法的原理和上面的很相似,@Autowired会默认根据type进行注入,如果type相同会根据id进行注入,也就是我们说的限定名,我们只需要让它找到对应限定名的类即可,上面我们通过修改接口变量名的方式来实现,同时我们还可以配合@Qualifier注解来实现相同的目的

TestController.java修改为如下

package com.example.demo.controller;

import com.example.demo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName TestController
 * @Author xuwei
 * @DATE 2022/6/28
 */
@RestController
@RequestMapping("test")
public class TestController {

    //配合注解指定限定名
    @Qualifier("testServiceImplTwo")
    @Autowired
    TestService testService;

    @RequestMapping("test")
    public void test(){
        testService.sayHello();
    }
}

当然,和上一种方法相同,我们注解中填的值是实现类的限定名,可以使用默认,也可以和上面一样在使用@Service时进行配置,测试结果如下:

2.3@ConditionalOnProperty

以上两种方法都是硬编码方式,在我们需要进行用户配置时很不方便,所以我们可以使用@ConditionalOnProperty注解来实现配置文件控制的功能

在TestController中使用@Resource注入

package com.example.demo.controller;

import com.example.demo.service.TestService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @ClassName TestController
 * @Author xuwei
 * @DATE 2022/6/28
 */
@RestController
@RequestMapping("test")
public class TestController {

    //使用@Resource注入
    @Resource
    TestService testService;

    @RequestMapping("test")
    public void test(){
        testService.sayHello();
    }
}

TestServiceImplOne.java

package com.example.demo.service.impl;

import com.example.demo.service.TestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * @ClassName TestServiceImplOne
 * @Author xuwei
 * @DATE 2022/6/28
 */
@Component
@ConditionalOnProperty(name = "serviceControl",havingValue = "serviceOne")
public class TestServiceImplOne implements TestService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplOne.class);
    /**
     * sayHello方法
     */
    @Override
    public void sayHello() {
        LOGGER.info("I am TestServiceImplOne");
    }
}

TestServiceImplTwo.java

package com.example.demo.service.impl;

import com.example.demo.service.TestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * @ClassName TestServiceImplTwo
 * @Author xuwei
 * @DATE 2022/6/28
 */
@Component
@ConditionalOnProperty(name = "serviceControl",havingValue = "serviceTwo")
public class TestServiceImplTwo implements TestService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplTwo.class);
    /**
     * sayHello方法
     */
    @Override
    public void sayHello() {
        LOGGER.info("I am TestServiceImplTwo");
    }
}

在配置文件中配置我们使用的类

测试结果如下

三.总结

前两种方法都是去寻找接口的限定名,第三种方法中@ConditionalOnProperty(name = "serviceControl",havingValue = "serviceOne")注解的name属性对应配置文件中的key值,而havingValue属性对应的是配置文件中我们上面定义的name属性对应的value值

到此这篇关于SpringBoot根据配置注入接口的不同实现类的文章就介绍到这了,更多相关SpringBoot注入接口实现类内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot接口多实现类选择性注入解决方案

    目录 一.问题的描述 二.相对低级解决方案 2.1.方案一:使用@Primary注解 2.2.方案二:使用@Resource注解 2.3.方案三:使用@Qualifier注解 三.相对高级的解决方案 一.问题的描述 在实际的系统应用开发中我经常会遇到这样的一类需求,相信大家在工作中也会经常遇到: 同一个系统在多个省份部署. 一个业务在北京是一种实现方式,是基于北京用户的需求. 同样的业务在上海是另外一种实现方式,与北京的实现方式大同小异 遇到这样的需求,我们通常会定义一个业务实现的接口,比如:

  • 使用Springboot根据配置文件动态注入接口实现类

    Springboot根据配置文件动态注入接口实现类 需求 最近在做一个Springboot项目,需要面向不同需求的客户,但是为了方便管理分支,需要将不同客户的需求都写到同一套代码中,根据不同客户实例化对应的实现类. 实现 为了尽量不修改代码,少做不必要的逻辑判断,我们考虑为不同客户写不同的Service,然后根据配置参数实例化对应的Service.这样就遇到了需要根据配置文件实现不同类的需求. 针对这一需求大致有两种实现方式.但是针对我的需求,能用的只有第二种,但还是想将第一种一起总结一下. 两

  • 使用SpringBoot根据配置注入接口的不同实现类(代码演示)

    目录 一.引言 二.代码演示 1.问题描述 2.解决方案 2.1使用@Autowired的时候将接口变量名改为实现类的限定名 2.2 使用@Autowired配合@Qualifier指定限定名注入实现类 2.3@ConditionalOnProperty 三.总结 一.引言 我们在使用springboot进行开发的时候经常用到@Autowired和@Resource进行依赖注入,但是当我们一个接口对应多个不同的实现类的时候如果不进行一下配置项目启动时就会报错,那么怎么根据不同的需求注入不同的类型

  • Springboot+Redis实现API接口限流的示例代码

    添加Redis的jar包. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 在application.yml中配置redis spring: ## Redis redis: database: 0 host: 127.0.0.1 p

  • SpringBoot自动配置特点与原理详细分析

    目录 一.SpringBoot是什么 二.SpringBoot的特点(核心功能) 三.SpringBoot的自动配置原理 1. @SpringBootApplication 2. @SpringBootConfiguration 3. @EnableAutoConfiguration 4. @ComponentScan 四.核心原理图 五.常用的Conditional注解 一.SpringBoot是什么 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Sprin

  • SpringBoot同一接口多个实现类配置的实例详解

    SpringBoot项目中可能出现一个接口有多个实现类的情况,如果不进行配置,注入接口时编译器不知道要注入哪个实现类就会报错,因此需要进行配置.以下进行举例: 接口如下: public interface NoticeService { public String noticeUser(Long id); } 两个实现类如下: @Service public class NoticeServiceImpl1 implements NoticeService { public String not

  • springboot使用@value注入配置失败的解决

    目录 springboot使用@value注入配置文件失败 问题解决方向一 问题解决方向二 @Value注入失败,注入值为null的问题 大概就是下面这样 结果不知道为什么,@Value注入一直为空?? 原因如下 解决办法 springboot使用@value注入配置文件失败 遇到的问题原因是:类中注入对象不能用static. 问题解决方向一 1.改为如图示,去掉static 问题解决方向二 1.仍然定义静态变量,但在其set方法上使用@Value进行赋值 2.仍然定义静态变量,同时定义一个普通

  • SpringBoot个性化配置的方法步骤

    在上一篇中我们简单的介绍了SpringBoot项目的创建及其启动方式.在这一篇中我们主要介绍一下SpringBoot项目的个性化配置.因为通过上一篇中知识我们知道SpringBoot项目的默认端口为8080,那如果我要修改这个默认端口,应该怎么改呢?又比如SpringBoot项目在启动时,默认是没有项目名字的,那如果我们想要添加自己喜欢的项目名字又该怎么办呢?这些都在这一篇的内容中.好了,下面我们详细介绍一下怎么修改SpringBoot项目中的默认配置. 修改默认端口 在上一篇的SpringBo

  • springboot基于过滤器实现接口请求耗时统计操作

    Spring Boot中实现一个过滤器相当简单,实现javax.servlet.Filter接口即可. 下面以实现一个记录接口访问日志及请求耗时的过滤器为例: 1.定义ApiAccessFilter类,并实现Filter接口 @Slf4j @WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/*") public class ApiAccessFilter implements Filter { @Ov

  • 解决springboot中配置过滤器以及可能出现的问题

    在springboot添加过滤器有两种方式: 1.通过创建FilterRegistrationBean的方式(建议使用此种方式,统一管理,且通过注解的方式若不是本地调试,如果在filter中需要增加cookie可能会存在写不进前端情况) 2.通过注解@WebFilter的方式 通过创建FilterRegistrationBean的方式创建多个filter以及设置执行顺序: 1.创建两个实现Filter接口的类TestFilter1 .TestFilter2 package com.aoxun.c

  • Idea安装及涉及springboot详细配置的图文教程

    一.安装 1.1 环境配置 idea环境的配置,如果环境有问题,删除文件夹,重新启动 1.2 激活 1.3 常用设置 1.3.1 JDK 退到初始界面 1.3.2 主题,窗体.菜单字体大小 1.3.2 鼠标滑轮修改字体大小 1.3.3 编码 1.3.4 自动编译(idea是默认不勾中的) 1.3.5 快捷键(我还是用eclipse的) 1.3.6 Maven配置 1.3.6.1不会自动关联,都配置上 1.3.6.2自动更新依赖到项目,自动下载源码和文档 1.3.6.3 Maven没提示,更新本地

随机推荐