依赖注入是Java(以及许多其他编程语言)中广泛使用的软件设计模式,用于实现控制反转 。 它提高了可重用性,可测试性,可维护性,并有助于构建松耦合的组件。 如今,依赖注入是将Java对象连接在一起的事实上的标准。

诸如Spring或Guice之类的各种Java框架可以帮助实现依赖注入。 从Java EE 6开始,还有一个正式的Java EE API用于依赖关系注入: 上下文和依赖关系注入 (CDI)。

我们使用依赖注入来注入服务,存储库,与域相关的组件,资源或配置值。 但是,以我的经验,依赖注入也可以用来注入域对象,这常常被忽略。

一个典型的例子是在Java许多应用程序中获取当前登录用户的方式。 通常,我们最终会向登录用户询问某些组件或服务。

此代码看起来可能类似于以下代码片段:

public class SomeComponent {@Injectprivate AuthService authService;public void workWithUser() {User loggedInUser = authService.getLoggedInUser();// do something with loggedInUser}
}

此处,将AuthService实例注入SomeComponent。 SomeComponent的方法现在使用AuthService对象来获取已登录用户的实例。

但是,除了注入AuthService之外,我们还可以将登录用户直接注入SomeComponent中。

可能看起来像这样:

public class SomeComponent {@Inject@LoggedInUserprivate User loggedInUser;public void workWithUser() {// do something with loggedInUser}
}

在这里,User对象直接注入SomeComponent中,不需要AuthService实例。 如果存在多个类型为User的(托管)bean,则使用自定义批注@LoggedInUser来避免冲突。

Spring和CDI都可以进行这种类型的注入(并且配置实际上非常相似)。 在下一节中,我们将看到如何使用Spring注入域对象。 在此之后,我将描述使用CDI进行相同操作所需的更改。

使用Spring进行域对象注入

要注入上面示例中所示的域对象,我们只需要做两个小步骤。

首先,我们必须创建@LoggedInUser批注:

import java.lang.annotation.*;
import org.springframework.beans.factory.annotation.Qualifier;@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface LoggedInUser {}

请注意@Qualifier批注,它将@LoggedInUser变成自定义限定符。 如果有多个相同类型的bean可用,Spring会使用限定符来避免冲突。

接下来,我们必须在我们的Spring配置中添加一个bean定义。 我们在这里使用Spring的Java配置,也可以使用xml配置来完成。

@Configuration
public class Application {@Bean@LoggedInUser@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)public User getLoggedInUser() {// retrieve and return user object from server/database/session}
}

在getLoggedInUser()内部,我们必须检索并返回当前登录用户的实例(例如,通过从第一个代码片段中询问AuthService)。 使用@Scope,我们可以控制返回对象的范围。 最佳范围取决于域对象,并且在不同的域对象之间可能有所不同。 对于代表登录用户的User对象, 请求会话范围将是有效的选择。 通过用@LoggedInUser注释getLoggedInUser(),我们告诉Spring应该在每次注入用户类型为@LoggedInUser的bean时使用此bean定义。

现在,我们可以将登录用户注入其他组件:

@Component
public class SomeComponent {@Autowired@LoggedInUserprivate User loggedInUser;...
}

在这个简单的示例中,实际上不需要限定符注释。 只要只有一个类型为User的bean定义可用,Spring可以按类型注入已登录的用户。 但是,在注入域对象时,很容易发生您具有相同类型的多个bean定义。 因此,使用附加的限定符注释是一个好主意。 限定词凭借其描述性名称也可以充当文档(如果命名正确)。

简化Spring bean定义

注入许多域对象时,最终有可能在bean配置中一遍又一遍地重复作用域和代理配置。 在这种情况下,可以在自定义注释上使用Spring注释。 因此,我们可以简单地创建自己的@SessionScopedBean批注,以代替@Bean和@Scope:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public @interface SessionScopedBean {}

现在我们可以简化bean的定义:

@Configuration
public class Application {@LoggedInUser@SessionScopedBeanpublic User getLoggedInUser() {...}
}

Java EE和CDI

CDI的配置几乎相同。 唯一的区别是我们必须用javax.inject和CDI注释替换Spring注释。

因此,@LoggedInUser应该使用javax.inject.Qualifier进行注释,而不是org.springframework.beans.factory.annotation.Qualifier进行注释(请参阅: 使用Qualifiers )。

Spring bean定义可以用CDI Producer方法代替。 可以使用适当的CDI范围注释代替@Scope。

在注入点,可以将Spring的@Autowired替换为@Inject。

请注意,Spring还支持javax.inject注释。 如果将javax.inject依赖项添加到Spring项目中,则还可以使用@Inject和@ javax.inject.Qualifier。 这样做实际上是一个好主意,因为它可以减少Java代码中的Spring依赖关系。

结论

我们可以使用自定义注释和作用域bean将域对象注入到其他组件中。 注入域对象可以使您的代码更易于阅读,并且可以导致更清晰的依赖关系。 如果仅注入AuthService来获取登录用户,则实际上取决于登录用户而不是AuthService。

不利的一面是,它使您的代码更牢固地依赖于依赖注入框架,该框架必须为您管理bean范围。 如果要保持在Dependency Injection容器之外使用类的能力,则可能会遇到问题。

哪种类型的域对象适合注入在很大程度上取决于您正在处理的应用程序。 好的候选对象是您经常使用的领域对象,它不依赖于任何方法或请求参数。 当前登录的用户是可能通常适合注入的对象。

  • 您可以在GitHub上找到所示示例的源代码。

翻译自: https://www.javacodegeeks.com/2014/10/injecting-domain-objects-instead-of-infrastructure-components.html

注入域对象而不是基础结构组件相关推荐

  1. 组件注入 # 注入的属性_注入域对象而不是基础结构组件

    组件注入 # 注入的属性 依赖注入是Java(以及许多其他编程语言)中广泛使用的软件设计模式,用于实现控制反转 . 它提高了可重用性,可测试性,可维护性,并有助于构建松耦合的组件. 如今,依赖注入是将 ...

  2. 依赖注入模式中,为什么用对象而不是用数组传递?

    依赖注入(Dependence Injection, DI) 依赖注入是控制反转的一种设计模式.依赖注入的核心是把类所依赖的单元的实例化过程,放到类的外面去实现.依赖注入的实现离不开反射. 依赖注入( ...

  3. tp5模型能实现事务吗_实现工作单元-通过事务模型处理域对象

    tp5模型能实现事务吗 Even in the most basic scenario you can picture, where the logic of an application's cor ...

  4. SpringMVC视图及如何在域对象中共享数据

    SpringMVC 回顾原生Servlet 获取请求参数 通过 Servlet API 获取 案例 通过控制器方法的形参获取请求参数 设置字符编码格式 CharacterEncodingFilter ...

  5. 在kotlin companion object中读取Bean,注入Bean对象

    在kotlin companion object中读取Bean,注入Bean对象 在使用kotlin时,或多或少地会使用到一些公共组件,如 http. mongo. redis相关的组件.   使用组 ...

  6. Java-Web JSP、Cookie和Session域对象

    一.JSP入门 1.什么是JSP JSP(Java Server Pages)是JavaWeb服务器端的动态资源.它与html页面的作用是相同的,显示数据和获取数据. 2.JSP的组成 JSP = h ...

  7. 转发和重定向和request域对象

    利用请求域传递对象(request域对象) 重定向和转发的区别(转发)(*****)* 域对象ServletContext:服务器一启动,为每个web应用创建一个ServletContext对象,所有 ...

  8. orika 映射非空字段_Orika:将JAXB对象映射到业务/域对象

    orika 映射非空字段 这篇文章着眼于使用Orika将JAXB对象映射到业务域对象. 本月初, 我使用基于反射的Dozer讨论 了相同的映射用例 . 在本文中,我假设需要映射相同的示例类,但是它们将 ...

  9. 在Spring MVC中处理域对象

    最近,我惊讶于一个代码库在其所有域实体中都具有公共默认构造函数(即零参数构造函数),并且所有字段都具有getter和setter. 当我深入研究时,我发现域实体之所以如此,主要是因为该团队认为Web ...

最新文章

  1. 通用机器学习流程与问题解决架构模板
  2. 视频直播:Windows中各类画面源的截取和合成方法总结
  3. word样式基准_「word技巧」简单的排版技巧—给word文档添加各种样式边框线
  4. 2019牛客暑期多校训练营(第一场) - B - Integration - 数学
  5. js怎么调用wasm_对于WebAssembly编译出来的.wasm文件js如何调用
  6. relativelayout常用属性
  7. Android 蓝牙扫描
  8. 惠普打印机驱动下载安装后不能使用,驱动人生解决方案
  9. 传送门骑士修改服务器数据,《传送门骑士》怎么刷资源 修改存档获取资源方法...
  10. 温度对免疫代谢调节和癌症进展的影响
  11. 一文了解互联网运营核心指标(产品、运营人员必知)
  12. 网络安全一哥的奇安信发布了全球高级可持续威胁年度报告 值得学习
  13. android ems具体意义?
  14. 在智能手机上跟踪ADS-B系统的飞机航线信息
  15. 项目管理软件Redmine
  16. vue2.6.11版本源码运行报错问题处理
  17. 对持久层、持久性、持久化的讨论
  18. UCOSIII 系统内部任务
  19. Unity 代码实现形成圆形及形成球形
  20. 贵州六盘水市新农合一卡通工作启动

热门文章

  1. 分布式锁之Redis6+Lua脚本实现原生分布式锁
  2. JSP 获得服务器时间和浏览器时间
  3. php access allow,PHP标头不适用于Access-Control-Allow-Origin
  4. 转:Tomcat启动失败 提示Server Tomcat v7.0 Server at localhost failed to start.六种解决方法
  5. java并发编程实践(1)intro
  6. cuba 平台_CUBA平台:TypeScript SDK和REST API
  7. cassandra可视化_容器化Spring Data Cassandra应用程序
  8. java面试spring_针对Java程序员的二十大Spring REST面试问题答案
  9. jboss 配置上下文路径_为单个Web应用程序配置多个上下文根– JBoss
  10. junit jndi_使用Spring创建用于JUnit测试的JNDI资源