spring 注释的作用

Spring是一个永不停息的框架。 这是因为它提供了许多不同的解决方案,使我们(开发人员)无需编写数百万行代码即可完成我们的任务。 取而代之的是,我们能够以更具可读性,更标准化的方式进行操作。 在这篇文章中,我将尝试描述最有可能为大家所熟知的功能之一,但我认为其重要性被低估了。 我将要讨论的功能是@Primary批注。

问题

在我从事的几个项目中,我们遇到了一个常见的业务问题–我们有一个进入更复杂逻辑的入口–一些容器,该容器会将其他几个处理器的结果收集到一个输出中(例如map-filter-reduce函数编程中的函数)。 在某种程度上,它类似于Composite模式。 综上所述,我们的方法如下:

  1. 我们有一个容器,其中包含自动实现共同接口的处理器列表
  2. 我们的容器实现了与自动装配列表元素相同的接口
  3. 我们希望使用该容器的客户端类使整个处理工作透明化-他只对结果感兴趣
  4. 处理器具有一些逻辑(谓词),处理器可将其应用于当前输入数据集
  5. 然后将处理结果合并到一个列表中,然后缩减为单个输出

有很多方法可以解决此问题-我将介绍一种使用Spring和@Primary批注的方法。

解决方案

让我们从定义我们的用例如何适应上述前提开始。 我们的数据集是一个Person类,如下所示:

人.java

package com.blogspot.toomuchcoding.person.domain;public final class Person {private final String name;private final int age;private final boolean stupid;public Person(String name, int age, boolean stupid) {this.name = name;this.age = age;this.stupid = stupid;}public String getName() {return name;}public int getAge() {return age;}public boolean isStupid() {return stupid;}
}

没有什么不寻常的。 现在让我们定义合同:

PersonProcessingService.java

package com.blogspot.toomuchcoding.person.service;import com.blogspot.toomuchcoding.person.domain.Person;public interface PersonProcessingService {boolean isApplicableFor(Person person);String process(Person person);
}

如前提条件中所述,PersonProcessingService的每个实现都必须定义合同的两点:

  1. 是否适用于当前人员
  2. 它如何处理一个人。

现在,让我们看一下我们拥有的一些处理器-由于它毫无意义,因此我不会在此处发布代码-您可以稍后在Github或Bitbucket上查看代码。 我们有以下@Component注释的PersonProcessingService实现:

  • AgePersonProcessingService

    • 如果某人的年龄大于或等于18,则适用
  • IntelligencePersonProcessingService
    • 适用于某人是愚蠢的人
  • NamePersonProcessingService
    • 如果某人有名字,则适用

逻辑很简单。 现在,我们的PersonProcessingServices容器将要针对处理器上的给定Person进行迭代,检查当前处理器是否适用(过滤器),如果是这种情况,则将响应处理Person的结果字符串添加到响应列表中(映射–将Person转换为String的函数),并最终以逗号将这些响应合并(减少)。 让我们检查一下它是如何完成的:

PersonProcessingServiceContainer.java

package com.blogspot.toomuchcoding.person.service;import java.util.ArrayList;
import java.util.List;import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;import com.blogspot.toomuchcoding.person.domain.Person;@Component
@Primary
class PersonProcessingServiceContainer implements PersonProcessingService {private static final Logger LOGGER = LoggerFactory.getLogger(PersonProcessingServiceContainer.class);@Autowiredprivate List<PersonProcessingService> personProcessingServices = new ArrayList<PersonProcessingService>();@Overridepublic boolean isApplicableFor(Person person) {return person != null;}@Overridepublic String process(Person person) {List<String> output = new ArrayList<String>();for(PersonProcessingService personProcessingService : personProcessingServices){if(personProcessingService.isApplicableFor(person)){output.add(personProcessingService.process(person));}}String result = StringUtils.join(output, ",");LOGGER.info(result);return result;}public List<PersonProcessingService> getPersonProcessingServices() {return personProcessingServices;}
}

如您所见,我们有一个用@Primary注释的容器,这意味着如果必须注入PersonProcessingService的实现,则Spring将选择要注入的PersonProcessingServiceContainer。 很棒的事情是,我们有一个自动连接的PersonProcessingServices列表,这意味着该接口的所有其他实现都将在那里自动连接(容器不会自动将其自身连接到该列表!)。

现在,让我们检查一下Spock测试 ,这些测试证明我没有在说谎。 如果您尚未在项目中使用Spock,则应立即将其移动。

PersonProcessingServiceContainerIntegrationSpec.groovy

package com.blogspot.toomuchcoding.person.service
import com.blogspot.toomuchcoding.configuration.SpringConfiguration
import com.blogspot.toomuchcoding.person.domain.Person
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
import spock.lang.Unrollimport static org.hamcrest.CoreMatchers.notNullValue@ContextConfiguration(classes = [SpringConfiguration])
class PersonProcessingServiceContainerIntegrationSpec extends Specification {@AutowiredPersonProcessingService personProcessingServicedef "should autowire container even though there are many implementations of service"(){       expect: personProcessingService instanceof PersonProcessingServiceContainer}def "the autowired container should not have itself in the list of autowired services"(){       expect: personProcessingService instanceof PersonProcessingServiceContainerand:!(personProcessingService as PersonProcessingServiceContainer).personProcessingServices.findResult {it instanceof PersonProcessingServiceContainer}}def "should not be applicable for processing if a person doesn't exist"(){given:Person person = nullexpect:!personProcessingService.isApplicableFor(person)}def "should return an empty result for a person not applicable for anything"(){given:Person person = new Person("", 17, false)when:def result = personProcessingService.process(person)then:result notNullValue()result.isEmpty()}@Unroll("For name [#name], age [#age] and being stupid [#stupid] the result should contain keywords #keywords")def "should perform different processing depending on input"(){given:Person person = new Person(name, age, stupid)when:def result = personProcessingService.process(person)        then:keywords.every {result.contains(it)    }where:name  | age | stupid || keywords"jan" | 20  | true   || ['NAME', 'AGE', 'STUPID']""    | 20  | true   || ['AGE', 'STUPID']""    | 20  | false  || ['AGE']null  | 17  | true   || ['STUPID']"jan" | 17  | true   || ['NAME']}
}

测试非常简单:

  1. 我们证明自动接线字段实际上是我们的容器– PersonProcessingServiceContainer。
  2. 然后,我们证明在PersonProcessingService的自动装配实现的集合中找不到对象,该对象属于PersonProcessingServiceContainer类型
  3. 在接下来的两个测试中,我们证明处理器背后的逻辑正在运行
  4. 最后但并非最不重要的一点是Spock最出色的– where子句,它使我们能够创建漂亮的参数化测试。

每个模块的功能

想象一下您在核心模块中定义了接口的实现的情况。

@Component
class CoreModuleClass implements SomeInterface {
...
}

如果您在与核心模块有依赖性的其他模块中决定不想使用此CoreModuleClass并希望在SomeInterface自动连线的任何地方都具有一些自定义逻辑该怎么办? 好吧–使用@Primary!

@Component
@Primary
class CountryModuleClass implements SomeInterface {
...
}

通过这种方式,您可以确保必须自动装配SomeInterface的位置将是您的CountryModuleClass,将其插入到该字段中。

结论

在这篇文章中,您可以看到如何

  • 使用@Primary批注创建类似接口实现的复合容器
  • 使用@Primary批注提供接口的每个模块实现,在自动装配方面,该实现将优先于其他@Components
  • 编写出色的Spock测试:)

代码

您可以在Too Much Coding的Github存储库或Too Much Coding的Bitbucket存储库中找到此处提供的代码。

参考:来自我们的JCG合作伙伴 Marcin Grzejszczak(位于Blog上)的 Spring @Primary注释 适用于编码成瘾者博客。

翻译自: https://www.javacodegeeks.com/2013/12/springs-primary-annotation-in-action.html

spring 注释的作用

spring 注释的作用_Spring的@Primary注释在起作用相关推荐

  1. Spring的@Primary注释在起作用

    Spring是一个永不止息的框架. 这是因为它提供了许多不同的解决方案,使我们(开发人员)无需编写数百万行代码即可完成我们的任务. 取而代之的是,我们能够以更具可读性,更标准化的方式进行操作. 在这篇 ...

  2. 【Python基础学习笔记day05】pycharm注释的作用+单行注释(行注释)+多行注释(块注释)+关于代码规范

    注释 文章目录 注释 目标 01. 注释的作用 02. 单行注释(行注释) 在代码后面增加的单行注释 03. 多行注释(块注释) 什么时候需要使用注释? 关于代码规范 目标 注释的作用 单行注释(行注 ...

  3. C语言的注释形式及作用,C语言注释详解(两种注释方式)

    在编写C语言源代码时,应该多使用注释,这样有助于对代码的理解.在C语言中有两种注释方式: 一种是以/*开始.以*/结束的块注释(block comment): 另一种是以//开始.以换行符结束的单行注 ...

  4. python使用什么注释语句和运算-Python代码注释的用法和意义

    01. 注释的作用 在大多数编程语言中,注释都是一项很有用的功能.在一些简单的程序中只包含Python代码,但随着程序越来越大.越来越复杂,就应在其中添加说明,对你解决问题的方法进行大致的阐述.注释让 ...

  5. python如何注释一段代码_python如何注释

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 我是多行注释1 我是多行注释2 我是多行注释3print(我上面的是多行注释)内 ...

  6. c语言注释含义,C语言编程规范——注释

    前言 制定C语言的编程规范,对代码的清晰.简洁.可测试.安全.程序效率.可移植各个方面有巨大的作用. 良好的注释能让整个代码读起来更加流畅,此乃程序猿出差旅行,通宵熬夜必备良药...... 注释的原则 ...

  7. mysql建表语句增加注释_mysql建表语句加注释

    主表的名称+字符 dtl(detail 缩写) 例如: 采购定单的名称为: po_order, 则采购定单的明细表为: po_orderdtl (7)表必须填写描述信息(使用 SQL 语句建表时... ...

  8. MySQL注释形式_可执行注释语句(/*!...*/)_数据库注释_数据库脚本注释_SQL脚本注释格式_SQL脚本注释分类

    文章目录 单行注释 多行注释 可执行注释 为什么要把可执行的 SQL 语句写在注释里面呢? 注释示例 导入数据时禁止/激活索引 测试禁止索引再导入数据的效率 单行注释 SELECT * from tf ...

  9. 【Java注释:单行 多行 文档注释】

    Java注释:单行 多行 文档注释 注释是程序语言的说明,它有助于开发者之间的交流,方便解释程序. 注释在程序语言中不会被视作代码,不会执行,而被编译器忽视. Java中,注释可分为三类 1.单行注释 ...

最新文章

  1. 5G 在物联网中的需求
  2. Java实现复数Complex的加减乘除运算、取模、求幅角角度
  3. Golang的简明安装指南
  4. #if _MSC_VER 1000 #pragma once #endif
  5. C++ Primer 第二章 学习笔记及习题答案
  6. 常用数字集成电路引脚图
  7. 基于Ajax的模糊查询输入控件(补充)
  8. Wine——在Linux上运行Windows软件
  9. js中apply、bind、call的用法和区别
  10. ipad无法充电怎么办_ipad不能充电怎么办 6种办法快速解决
  11. uvalive 4987 Evacuation Plan 疏散计划
  12. 油/水溶性CdS-ZnS/InP-ZnS/ZnSe-ZnS/CdSe/ZnS量子点的应用
  13. Ubuntu18.04 笔记本合上盖子时不进入休眠
  14. 摊牌了,做为前端,我经常在用的15个国外网站
  15. 中兴微ZXIC方案MF782型4G随身WIFI开启ADB,开启锁频等功能
  16. 界面登录、登陆后才能访问另外页面
  17. 众创美业微信引流系统使用说明
  18. java程序员烂大街了吗?java入坑之前先来看看行情
  19. Top 50 Most Popular APIs on RapidAPI (2018)
  20. Fabric 1.0源代码分析(32) Peer #peer node start命令实现

热门文章

  1. 图解elasticsearch原理转载自
  2. Java中如何实现线程的超时中断
  3. vue-beauty UI库
  4. Spring 整合 Quartz 分布式调度
  5. java之正则表达式
  6. 【Python】有效资源爬取并集
  7. 数组:完成等差等比数列,及其他数列
  8. 最全三大框架整合(使用映射)——Emp.hbm.xml
  9. String与StringBuffer、StringBuilder之间的转换
  10. java读取Resources下文件