如何制作多模块弹簧配置?

时间:2023-01-13 12:31:09

I have a multi-module (maven) spring build. All the modules publish some beans, and most also consume beans defined further down the dependency graph. Although most of it is annotation declared beans, almost every module also has one or two xml-declared beans.

我有一个多模块(maven)弹簧构建。所有模块都发布了一些bean,并且大多数模块还使用依赖关系图中进一步定义的bean。虽然它的大多数是注释声明bean,但几乎每个模块都有一个或两个xml声明的bean。

Although we have a half-decent solution, but I am really wondering what is the correct/optimal way to organize the xml files in this scenario? Do you use import between the modules or is there some other way ? Do you put all the xml files in one place or spread them around according to the dependency graph? How does your solution handle partial spring contexts (typical integration tests) ?

虽然我们有一个不太合适的解决方案,但我真的想知道在这种情况下组织xml文件的正确/最佳方式是什么?你在模块之间使用导入还是有其他方法?您是否将所有xml文件放在一个位置或根据依赖关系图将它们分散?您的解决方案如何处理部分弹簧上下文(典型的集成测试)?

I'd also like to have this organized in a way that lets me leverage my IDE's spring support optimally (IDEA and a few eclipse users).

我也希望这种组织方式能够让我最佳地利用IDE的弹簧支持(IDEA和一些eclipse用户)。

2 个解决方案

#1


We use wildcarded imports in the modules to allow other modules contribute beans to the module declaring the import:

我们在模块中使用通配符导入,以允许其他模块为模块声明导入bean:

<import resource="classpath*:com/acme/**/*-core-support.xml" />

Modularity

Modules that want to contribute to the "host" just have to place a correctly named files in src/main/resources/com/acme in this case to be picked up automagically. If you use classpath scanning (by <context:component-scan /> it will become even easier).

想要贡献给“主机”的模块只需要在src / main / resources / com / acme中放置一个正确命名的文件,以便自动获取。如果使用类路径扫描(通过 ,它将变得更加容易)。

Another thing that helps in that regard is some small Spring extension that picks up beans of a given type and republishes them in ApplicationContext again. By doing something like this:

在这方面有帮助的另一件事是一些小的Spring扩展,它接收给定类型的bean并再次在ApplicationContext中重新发布它们。做这样的事情:

<plugin:list id="beanList" class="com.acme.MyCoolPluginInterface" />

<bean class="com.acme.MyPluginHost">
   <property name="plugins" ref="beanList" />
</bean>

In combination with the wildcarded import this will:

结合通配符导入,这将:

  1. Collect all beans found in the ApplicationContext that implement MyCoolPluginInterface and wrap them in a list registered as beanList in the ApplicationContext.
  2. 收集在ApplicationContext中找到的所有实现MyCoolPluginInterface的bean,并将它们包装在ApplicationContext中注册为beanList的列表中。

  3. Allow the MyPluginHost to reference that list.
  4. 允许MyPluginHost引用该列表。

In fact, you now can simply extend your app by adding plugin modules to the classpath (aka dependency in Maven).

实际上,您现在可以通过向类路径添加插件模块(也就是Maven中的依赖项)来扩展您的应用程序。

That tiny Spring extension is called Spring Plugin and published under Apache 2 licence. See http://github.com/SpringSource/spring-plugin for more info. There's also a more advanced sample project at Github, that shows how this works and improves modularity at GitHub. The app is sample code for my "Whoops! Where did my architecture go?" presentation which you can see the slides here or watch a recording here.

这个微小的Spring扩展名为Spring Plugin,并在Apache 2许可下发布。有关详细信息,请参阅http://github.com/SpringSource/spring-plugin。在Github上还有一个更高级的示例项目,它展示了它如何工作并改善了GitHub的模块化。该应用程序是我的“哎呀!我的架构在哪里?”的示例代码。您可以在此处查看幻灯片或在此处观看录制的演示文稿。

Different environments

Usually we configure our apps to run in the target environment (using JNDI lookups and stuff). Of course you would like to use the standard PropertyPlaceholderConfigurer mechanisms to externalize configuration that has to be touched by admins or will change through various environments.

通常我们将应用程序配置为在目标环境中运行(使用JNDI查找和内容)。当然,您希望使用标准的PropertyPlaceholderConfigurer机制来外部化管理员必须触及的配置,或者通过各种环境进行更改。

For integration tests we usually have additional config files in src/main/test that get loaded additionally to the normal config files overriding the critical beans that tie the configuration to the environment. E.g. if you have a datasource in your normal config file

对于集成测试,我们通常在src / main / test中有额外的配置文件,这些配置文件会被加载到正常的配置文件中,从而覆盖将配置绑定到环境的关键bean。例如。如果您的普通配置文件中有数据源

 <jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource" />

you would override this in your test-context.xml by using

您可以使用在test-context.xml中覆盖它

 <bean id="dataSource" class="...DataSource" />
    <!-- config -->
 </bean>

and importing that after the original one in the test class

并在测试类中导入原始的之后

 @ConfigurationContext(locations = {"app-context.xml", "test-context.xml"})
 public FooBarIntegrationtest {
   // ...
 }

#2


We simply create the application context from multiple XML config files based on usage.

我们只是根据用法从多个XML配置文件创建应用程序上下文。

For example, for testing without a server, the context is created by using all the config files in each service module.

例如,对于没有服务器的测试,通过使用每个服务模块中的所有配置文件来创建上下文。

When deployed, we access the services via Spring Remoting, and thus the client uses an application context that is initialized via an XML config which defines the proxy beans that enable remoting. Meanwhile the services are confgured by the same XML files as used by the test cases, but the application context is now loaded by either the DispatcherServlet or an EJB or MDB.

部署时,我们通过Spring Remoting访问服务,因此客户端使用通过XML配置初始化的应用程序上下文,该配置定义了启用远程处理的代理bean。同时,服务由测试用例使用的相同XML文件进行配置,但应用程序上下文现在由DispatcherServlet或EJB或MDB加载。

This setup allows us to tailor the Application Context for each scenario without having to duplicate any information in configuration files, which keeps maintenance much simpler. Also, there is no hard dependency between config files via imports, since that is handled at the layer above that actually creates the ApplicationContext.

此设置允许我们为每个方案定制应用程序上下文,而无需复制配置文件中的任何信息,这使维护更加简单。此外,配置文件之间通过导入没有硬依赖关系,因为它是在实际创建ApplicationContext的上层处理的。

Can't comment on the IDE support since we are not using it yet.

由于我们尚未使用它,因此无法对IDE支持发表评论。

#1


We use wildcarded imports in the modules to allow other modules contribute beans to the module declaring the import:

我们在模块中使用通配符导入,以允许其他模块为模块声明导入bean:

<import resource="classpath*:com/acme/**/*-core-support.xml" />

Modularity

Modules that want to contribute to the "host" just have to place a correctly named files in src/main/resources/com/acme in this case to be picked up automagically. If you use classpath scanning (by <context:component-scan /> it will become even easier).

想要贡献给“主机”的模块只需要在src / main / resources / com / acme中放置一个正确命名的文件,以便自动获取。如果使用类路径扫描(通过 ,它将变得更加容易)。

Another thing that helps in that regard is some small Spring extension that picks up beans of a given type and republishes them in ApplicationContext again. By doing something like this:

在这方面有帮助的另一件事是一些小的Spring扩展,它接收给定类型的bean并再次在ApplicationContext中重新发布它们。做这样的事情:

<plugin:list id="beanList" class="com.acme.MyCoolPluginInterface" />

<bean class="com.acme.MyPluginHost">
   <property name="plugins" ref="beanList" />
</bean>

In combination with the wildcarded import this will:

结合通配符导入,这将:

  1. Collect all beans found in the ApplicationContext that implement MyCoolPluginInterface and wrap them in a list registered as beanList in the ApplicationContext.
  2. 收集在ApplicationContext中找到的所有实现MyCoolPluginInterface的bean,并将它们包装在ApplicationContext中注册为beanList的列表中。

  3. Allow the MyPluginHost to reference that list.
  4. 允许MyPluginHost引用该列表。

In fact, you now can simply extend your app by adding plugin modules to the classpath (aka dependency in Maven).

实际上,您现在可以通过向类路径添加插件模块(也就是Maven中的依赖项)来扩展您的应用程序。

That tiny Spring extension is called Spring Plugin and published under Apache 2 licence. See http://github.com/SpringSource/spring-plugin for more info. There's also a more advanced sample project at Github, that shows how this works and improves modularity at GitHub. The app is sample code for my "Whoops! Where did my architecture go?" presentation which you can see the slides here or watch a recording here.

这个微小的Spring扩展名为Spring Plugin,并在Apache 2许可下发布。有关详细信息,请参阅http://github.com/SpringSource/spring-plugin。在Github上还有一个更高级的示例项目,它展示了它如何工作并改善了GitHub的模块化。该应用程序是我的“哎呀!我的架构在哪里?”的示例代码。您可以在此处查看幻灯片或在此处观看录制的演示文稿。

Different environments

Usually we configure our apps to run in the target environment (using JNDI lookups and stuff). Of course you would like to use the standard PropertyPlaceholderConfigurer mechanisms to externalize configuration that has to be touched by admins or will change through various environments.

通常我们将应用程序配置为在目标环境中运行(使用JNDI查找和内容)。当然,您希望使用标准的PropertyPlaceholderConfigurer机制来外部化管理员必须触及的配置,或者通过各种环境进行更改。

For integration tests we usually have additional config files in src/main/test that get loaded additionally to the normal config files overriding the critical beans that tie the configuration to the environment. E.g. if you have a datasource in your normal config file

对于集成测试,我们通常在src / main / test中有额外的配置文件,这些配置文件会被加载到正常的配置文件中,从而覆盖将配置绑定到环境的关键bean。例如。如果您的普通配置文件中有数据源

 <jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource" />

you would override this in your test-context.xml by using

您可以使用在test-context.xml中覆盖它

 <bean id="dataSource" class="...DataSource" />
    <!-- config -->
 </bean>

and importing that after the original one in the test class

并在测试类中导入原始的之后

 @ConfigurationContext(locations = {"app-context.xml", "test-context.xml"})
 public FooBarIntegrationtest {
   // ...
 }

#2


We simply create the application context from multiple XML config files based on usage.

我们只是根据用法从多个XML配置文件创建应用程序上下文。

For example, for testing without a server, the context is created by using all the config files in each service module.

例如,对于没有服务器的测试,通过使用每个服务模块中的所有配置文件来创建上下文。

When deployed, we access the services via Spring Remoting, and thus the client uses an application context that is initialized via an XML config which defines the proxy beans that enable remoting. Meanwhile the services are confgured by the same XML files as used by the test cases, but the application context is now loaded by either the DispatcherServlet or an EJB or MDB.

部署时,我们通过Spring Remoting访问服务,因此客户端使用通过XML配置初始化的应用程序上下文,该配置定义了启用远程处理的代理bean。同时,服务由测试用例使用的相同XML文件进行配置,但应用程序上下文现在由DispatcherServlet或EJB或MDB加载。

This setup allows us to tailor the Application Context for each scenario without having to duplicate any information in configuration files, which keeps maintenance much simpler. Also, there is no hard dependency between config files via imports, since that is handled at the layer above that actually creates the ApplicationContext.

此设置允许我们为每个方案定制应用程序上下文,而无需复制配置文件中的任何信息,这使维护更加简单。此外,配置文件之间通过导入没有硬依赖关系,因为它是在实际创建ApplicationContext的上层处理的。

Can't comment on the IDE support since we are not using it yet.

由于我们尚未使用它,因此无法对IDE支持发表评论。