问题陈述
众所周知,在 Spring 应用程序中,我们通过“ApplicationContext”提供配置信息。 spring框架提供了多个类来实现这个接口,帮助我们在应用中使用配置信息,ClassPathXmlApplicationContext就是其中之一。通常在这种情况下,所有 bean 定义都配置在一个单独的 xml 文件中,通常称为“application-context.xml”。
在较大的项目结构中,最佳实践是保留多个 spring 配置文件,以便于维护和模块化。在这种情况下,最好的做法是将所有 Spring bean 配置文件组织到一个 XML 文件中,然后将整个文件导入其中。此外,在应用程序上下文中,我们加载这个单个 xml 文件。
现在如果要创建的配置文件数量过大怎么办?比如说,接近 100 或更多?
现在这是一个单调和蜗牛般的工作!是时候找到一条路径来自动化这个过程了。
让我们考虑一个场景,我们在外部源中拥有所有必需的数据,例如,Excel 工作表。现在我们需要从sheet中读取数据,并自发生成近100个spring配置文件。
如何自动化这个过程:JAXB 来救援。
JAXB 有一个绑定编译器。 JAXB XJC 模式绑定编译器将源 XML 模式转换或绑定到Java编程语言中的一组 JAXB 内容类。
- 在要生成的xml中查找需要引用的xml schema-http://www.springframework.org/schema/beans/spring-beans-3.0.xsd。
- 在浏览器中点击这个 url 来获取 xsd。现在将其保存在某个位置(如 spring.xsd)。
- 下载 jaxbri 包并设置环境路径变量。如果是 maven 项目,包括 jaxb-ri 和 jaxb-core 的依赖项。
- 从 spring.xsd 所在的文件夹中执行命令 xjc.exe spring.xsd。
这将生成与 xsd 关联的类。
如果在执行命令时出现“属性已定义”错误,需要做什么?
很可能会收到一个异常,显示“属性已经定义”,如下面的屏幕截图所示。如果是这样,可以通过创建绑定文件来解决该问题,以覆盖引发异常的属性。
绑定文件
春天25
使用以下命令解析架构并生成类:
xjc -b spring25.xjb -verbose -xmlschema
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
生成的类
组织
现在创建一个 Bean 实例并对其进行编组。这将生成具有所需输出的 xml 文件。
示例代码
注意:- 测试类是在 org\springframework\schema\beans 下创建的。
package org.springframework.schema.beans;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import org.springframework.util.CollectionUtils;
import com.hrb.leap.bean.SpringConfigGenerator;
public class Test
{
public static void main(String[] args) throws JAXBException
{
ObjectFactory factory = new ObjectFactory();
JAXBContext context = JAXBContext.newInstance("org.springframework.schema.beans");
/*
* Create the root element 'Beans'
* Set the required schema properties
*/
Beans rootElement = factory.createBeans();
rootElement.getOtherAttributes().put(new QName
("xmlns:xsi"), "http://www.w3.org/2001/XMLSchema-instance");
rootElement.getOtherAttributes().put(new QName
("xsi:schemaLocation"),
"http://www.springframework.org/schema/beans spring-beans-3.2.xsd");
/*
* How to import resources
* How to define list of reference beans
*/
java.util.List resources = new ArrayList<>();
resources.add("ResourceOne");
resources.add("ResourceTwo");
resources.add("ResourceThree");
resources.forEach(resourceName ->
{
Import importResource = new Import();
importResource.setResource(resourceName+".xml");
rootElement.getImportOrAliasOrBean().add(importResource);
});
Bean bean = factory.createBean();
bean.setId("id");
bean.setClazz("java.util.ArrayList");
if (!CollectionUtils.isEmpty(resources))
{
ConstructorArg constructorArgs = factory.createConstructorArg();
org.springframework.schema.beans.List listOfResources =
new org.springframework.schema.beans.List();
resources.forEach(referenceFormName ->
{
Ref refBean = new Ref();
refBean.setBean(referenceFormName);
listOfResources.getBeanOrRefOrIdref().add(refBean);
});
constructorArgs.setList(listOfResources);
bean.getMetaOrConstructorArgOrProperty().add(constructorArgs);
}
rootElement.getImportOrAliasOrBean().add(bean);
/*
* Sample bean definition to show how to store
list of values as a property
*/
Bean simpleBean = factory.createBean();
simpleBean.setId("SimpleBean");
simpleBean.setClazz("com.packagename.ClassName");
PropertyType firstProperty= factory.createPropertyType();
firstProperty.setName("listOfValuesDemo");
java.util.List listOfValues = new ArrayList<>();
listOfValues.add("ValueOne");
listOfValues.add("ValueTwo");
listOfValues.add("ValueThree");
org.springframework.schema.beans.List listToStoreValues
= new org.springframework.schema.beans.List();
listOfValues.forEach(name ->
{
Value value = factory.createValue();
value.getContent().add(name);
listToStoreValues.getBeanOrRefOrIdref().add(value);
});
firstProperty.setList(listToStoreValues);
//Add the property to the bean.
simpleBean.getMetaOrConstructorArgOrProperty().add
(factory.createProperty(firstProperty));
// Add the bean under the root element 'beans'
rootElement.getImportOrAliasOrBean().add(simpleBean);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
createXmlConfiguration(marshaller , "output", rootElement);
}
/*
* Method create the xml under the 'src/main/resources'
folder in the project.
*/
public static void createXmlConfiguration (Marshaller marshaller ,
String fileName, Beans rootElement)
{
try
{
java.net.URL url = SpringConfigGenerator.class.getResource("/");
File fullPathToSubfolder = new File(url.toURI()).getAbsoluteFile();
String projectFolder =
fullPathToSubfolder.getAbsolutePath().split("target")[0];
// TODO - Destination folder to be configured
File outputFile = new File(projectFolder
+ "src/main/resources/" + "/"+fileName+".xml");
if (!outputFile.exists())
{
outputFile.createNewFile();
}
OutputStream os = new FileOutputStream(outputFile);
marshaller.marshal(rootElement, os);
}
catch (URISyntaxException uriException)
{
}
catch (IOException ioException)
{
}
catch (JAXBException jaxbException)
{
}
}
}
输出
输出
按照以下步骤查看示例输出:
- 在浏览器中点击架构 url 以获取 xsd。现在将其保存在某个位置(例如:- spring.xsd)。
- 下载 jaxbri 包并设置环境路径变量。
- 设置 jaxb 库的类路径和当前路径(点),如示例(在 IDE 中执行此命令提示符或等号)
set classpath=C:\folder_name\jaxb-ri\lib;.;
- 解压缩附加到文件夹下运行的命令(从 cmd 中的解压缩文件夹)后,编译“测试”类。
javac org\springframework\schema\beans\Test.java
- 最后运行程序。
java org.springframework.schema.beans.Test
注意:- 如果’createXmlConfiguration(marshaller, “output”, rootElement);’,输出将打印在控制台中替换为“marshaller.marshal(rootElement, System.out);”
优点
- 工作量大大减少。一个人可能至少需要 20-25 天来配置接近 85 个文件(考虑 9 小时/天),这将占 225 小时。上述工具只需不到 3 秒即可完成。
- 如果以后有小的配置改动,我们可以单独拿具体的文件进行修正。
替代方法
如果配置文件的数量非常少,我们可以尝试动态加载包含所有 bean 定义的上下文,而无需生成物理 xml 文件。这可以通过以编程方式加载 spring 上下文并在需要时运行应用程序来实现。
缺点
- 内存消耗高
- 性能低
- 数据源中的小错误会产生很大的影响。
- 在生产环境中动态运行有风险。
- 如果数据源几乎保持不变,则不是一种建议的方法
- 将很难排除故障。