- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
绝大多数教程都处理退化的情况,即只有一个实现用于要注入(inject)的接口(interface)。然而,我很茫然,到目前为止还没有找到任何关于如何构建应用程序的线索,其中几个专用部分提供了要注入(inject)公共(public)部分的公共(public)接口(interface)的几种不同实现(又名策略模式,又名控制反转)。
在我的现实生活中,我有一台 Tomcat 服务器,上面部署了一个应用程序,其中多个部分向外界提供不同的接口(interface)。在此应用程序中,在一个专用 @Configuration
中为通用接口(interface)
定义一个@Bean
始终会导致其他专用部分接收相同的 @Bean
即使它们(只是表面上?)独立的 @Configuration
定义了不同的 @Bean
。
举一个最小的例子,我尝试编写一个 Spring-boot 应用程序,它表现出相同的行为并具有相同的通用架构:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@FunctionalInterface
interface Service { boolean test(); }
class CommonProcess {
@Autowired
Service service;
public boolean test() { return this.service.test(); }
}
@Configuration
class BaseConfig {
@Bean
CommonProcess commonProcess() { return new CommonProcess(); }
}
@Configuration
class ConfigA {
@Bean
CommandLineRunner processA() {
return new CommandLineRunner() {
@Autowired
private CommonProcess process;
@Override
public void run(String... args) throws Exception {
System.out.println(this.process.test());
}
};
}
@Bean
Service service() { return () -> false; }
}
@Configuration
class ConfigB {
@Bean
CommandLineRunner processB() {
return new CommandLineRunner() {
@Autowired
private CommonProcess process;
@Override
public void run(String... args) throws Exception {
System.out.println(this.process.test());
}
};
}
@Bean
Service service() { return () -> true; }
}
@SpringBootConfiguration
@Import(value = { BaseConfig.class, ConfigA.class, ConfigB.class })
class App {
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(App.class, args)));
}
}
此代码背后的意图如下:
ConfigA
和 ConfigB
都导入 BaseConfig,因为它们的进程使用相同的 CommonProcess
。ConfigA
和 ConfigB
都定义了其特定的、专用的 Service
实现,以提供来自不同来源的通用值App
类是我将部署在 Tomcat 服务器上的 Servlet 的替代品。显然,应用程序必须知道(提供)服务器应提供的所有接口(interface),因此应用程序必须@Import
ConfigA
和ConfigB
。< br/>据我了解,应用程序抽象层的“叶节点”的这种“收集点”需要存在,以便将它们全部暴露给世界现在,可以观察到以下行为:
false false
或 true true
,但绝不会打印预期的 false true
或 true false
;App
中删除 @Import
可以预见会导致应用无法运行任何内容。而预期的行为是:
ConfigA
调用 CommonProcess
时,它使用 ConfigA
的 service
ConfigB
调用 CommonProcess
时,它使用 ConfigB
的 service
问题:产生预期行为的规范方法是什么?
(首选基于注释的解决方案)
作为引用,纯 Java 中的工作示例:
import java.util.Arrays;
import java.util.List;
@FunctionalInterface
interface Service { boolean test(); }
class CommonProcess {
public static final CommonProcess INSTANCE = new CommonProcess();
public boolean test(Service service) { return service.test(); }
}
class ProcessA implements Runnable {
// specific project knows generic project -> no need to inject
private static final CommonProcess commonProcess = CommonProcess.INSTANCE;
private static final Service service = () -> false;
public void run() {
// generic project does not know specific project -> specifics are injected
System.out.println(this.commonProcess.test(this.service));
}
}
class ProcessB implements Runnable {
// specific project knows generic project -> no need to inject
private static final CommonProcess commonProcess = CommonProcess.INSTANCE;
private static final Service service = () -> true;
public void run() {
// generic project does not know specific project -> specifics are injected
System.out.println(this.commonProcess.test(this.service));
}
}
class PlainApp {
private static final List<Runnable> processes = Arrays.asList(new ProcessA(), new ProcessB());
public static void main(String[] args) {
for (Runnable process : processes)
process.run();
}
}
这里的输出确实符合预期false true
。
最佳答案
你对 Spring IoC 的思考过多并且令人困惑 @Configuration
与 ApplicationContext
(实际的 IoC 容器)。
@Configuration
在现有容器的范围内进行处理。还有docs一旦声明:
@Import
represents JavaConfig's equivalent of XML configuration's<import/>
element. One configuration class can import any number of other configuration classes, and their bean definitions will be processed as if locally defined.
也就是说,所有导入和发现的@Configurations都会加载到同一个容器中。
之后所有单例 bean 都被创建。然后将它们连接在一起。
在一个容器内,您可以拥有多个相同类型的 bean,但不能具有相同的名称。在 JavaConfig 中,bean 名称源自工厂方法名称或类名称。如果是Service
只有一个名字,service
,因此只有一个 Service
类型的 bean 。如果仔细观察,您会看到一条启动消息,内容为“Overriding bean definition for bean 'service' with a different definition: replacing [factoryBeanName=ConfigA; factoryMethodName=service; defined in ConfigA] with [factoryBeanName=ConfigB; factoryMethodName=service; defined in ConfigB]
”
唯一的service
然后连接到需要的任何地方(在 commonProcess
、 configA
和 configB
中)。
根据您的具体情况,您可以通过传递 Service
来解决它至CommonProcess.test()
就像在普通的 Java 版本中一样,并为每个 Service
指定一个唯一的名称实例(例如 serviceA
和 serviceB
):
@FunctionalInterface
interface Service {
boolean test();
}
class CommonProcess {
public boolean test(Service service) {
return service.test();
}
}
@Configuration
class BaseConfig {
@Bean
CommonProcess commonProcess() {
return new CommonProcess();
}
}
@Configuration
class ConfigA {
@Bean
CommandLineRunner processA(@Named("serviceA") Service service) {
return new CommandLineRunner() {
@Autowired
private CommonProcess process;
@Override
public void run(String... args) throws Exception {
System.out.println(this.process.test(service));
}
};
}
@Bean
Service serviceA() {
return () -> false;
}
}
@Configuration
class ConfigB {
@Bean
CommandLineRunner processB(@Named("serviceB") Service service) {
return new CommandLineRunner() {
@Autowired
private CommonProcess process;
@Override
public void run(String... args) throws Exception {
System.out.println(this.process.test(service));
}
@Bean
Service serviceB() {
return () -> true;
}
};
}
@Autowired
ApplicationContext applicationContext;
@PostConstruct
public void printBeans() {
System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));
}
@Bean
Service serviceB() {
return () -> true;
}
}
@SpringBootConfiguration
@Import(value = { BaseConfig.class, ConfigA.class, ConfigB.class })
class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
我还建议查看 bean scopes ,尤其是工厂范围。
最后,Spring Boot 支持 hierarchy of ApplicationContext's ,它本质上允许您在一个可执行文件中创建子应用程序。这边ConfigA
和ConfigB
每个人都可以有自己的Service
名为 service
的实例。此功能很少使用。
@SpringBootConfiguration
@Import(value = { BaseConfig.class })
class App {
public static void main(String[] args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(App.class);
app.child(ConfigA.class).run(args);
app.child(ConfigB.class).run(args);
}
}
关于java - 在一个最小的例子中,Spring IoC 实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52523103/
我在Windows 10中使用一些简单的Powershell代码遇到了这个奇怪的问题,我认为这可能是我做错了,但我不是Powershell的天才。 我有这个: $ix = [System.Net.Dn
var urlsearch = "http://192.168.10.113:8080/collective-intellegence/StoreClicks?userid=" + userId +
我有一个非常奇怪的问题,过去两天一直让我抓狂。 我有一个我试图控制的串行设备(LS 100 光度计)。使用设置了正确参数的终端(白蚁),我可以发送命令(“MES”),然后是定界符(CR LF),然后我
我目前正试图让无需注册的 COM 使用 Excel 作为客户端,使用 .NET dll 作为服务器。目前,我只是试图让概念验证工作,但遇到了麻烦。 显然,当我使用 Excel 时,我不能简单地使用与可
我开发了简单的 REST API - https://github.com/pavelpetrcz/MandaysFigu - 我的问题是在本地主机上,WildFly 16 服务器的应用程序运行正常。
我遇到了奇怪的情况 - 从 Django shell 创建一些 Mongoengine 对象是成功的,但是从 Django View 创建相同的对象看起来成功,但 MongoDB 中没有出现任何数据。
我是 flask 的新手,只编写了一个相当简单的网络应用程序——没有数据库,只是一个航类搜索 API 的前端。一切正常,但为了提高我的技能,我正在尝试使用应用程序工厂和蓝图重构我的代码。让它与 pus
我的谷歌分析 JavaScript 事件在开发者控制台中运行得很好。 但是当从外部 js 文件包含在页面上时,它们根本不起作用。由于某种原因。 例如; 下面的内容将在包含在控制台中时运行。但当包含在单
这是一本名为“Node.js 8 the Right Way”的书中的任务。你可以在下面看到它: 这是我的解决方案: 'use strict'; const zmq = require('zeromq
我正在阅读文本行,并创建其独特单词的列表(在将它们小写之后)。我可以使它与 flatMap 一起工作,但不能使它与 map 的“子”流一起工作。 flatMap 看起来更简洁和“更好”,但为什么 di
我正在编写一些 PowerShell 脚本来进行一些构建自动化。我发现 here echo $? 根据前面的语句返回真或假。我刚刚发现 echo 是 Write-Output 的别名。 写主机 $?
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我将一个工作 View Controller 类从另一个项目复制到一个新项目中。我无法在新项目中加载 View 。在旧项目中我使用了presentModalViewController。在新版本中,我
我对 javascript 很陌生,所以很难看出我哪里出错了。由于某种原因,我的功能无法正常工作。任何帮助,将不胜感激。我尝试在外部 js 文件、头部/主体中使用它们,但似乎没有任何效果。错误要么出在
我正在尝试学习Flutter中的复选框。 问题是,当我想在Scaffold(body :)中使用复选框时,它正在工作。但我想在不同的地方使用它,例如ListView中的项目。 return Cente
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我有一个组合框,其中包含一个项目,比如“a”。我想调用该组合框的 Action 监听器,仅在手动选择项目“a”完成时才调用。我也尝试过 ItemStateChanged,但它的工作原理与 Action
你能看一下照片吗?现在,一步前我执行了 this.interrupt()。您可以看到 this.isInterrupted() 为 false。我仔细观察——“这个”没有改变。它具有相同的 ID (1
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我正在尝试在我的网站上设置一个联系表单,当有人点击发送时,就会运行一个作业,并在该作业中向所有管理员用户发送通知。不过,我在失败的工作表中不断收到此错误: Illuminate\Database\El
我是一名优秀的程序员,十分优秀!