Spring Dynamic Modules测试框架源码分析

公西国发
2023-12-01

 

一.问题描述

在用spring-dm对某bundle进行测试时,报了如下错误。于是便对spring-osgi-test.jar中的几个测试类做了下研究。

 

	java.io.FileNotFoundException: C:\Users\boy\.m2\repository\org\aopalliance\com.springsource.org.aopalliance\1.0.0\com.springsource.org.aopalliance-1.0.0.jar (系统找不到指定的路径。)
		at java.io.FileInputStream.open(Native Method)
		at java.io.FileInputStream.<init>(FileInputStream.java:106)
		at org.springframework.core.io.FileSystemResource.getInputStream(FileSystemResource.java:110)
		at org.springframework.osgi.test.AbstractOsgiTests.installBundle(AbstractOsgiTests.java:323)
		at org.springframework.osgi.test.AbstractOsgiTests.startup(AbstractOsgiTests.java:253)
		at org.springframework.osgi.test.AbstractOsgiTests.prepareTestExecution(AbstractOsgiTests.java:374)
		at org.springframework.osgi.test.AbstractOsgiTests.runBare(AbstractOsgiTests.java:203)
		at org.springframework.osgi.test.AbstractOsgiTests$1.protect(AbstractOsgiTests.java:184)
		at junit.framework.TestResult.runProtected(TestResult.java:124)
		at org.springframework.osgi.test.AbstractOsgiTests.run(AbstractOsgiTests.java:181)
  

二.spring dm对bundle的集成测试

在使用spring dm框架时,其中的spring-osgi-test.jar这个bundle对集成测试提供了很好的支持。其中最重要的几个类如下

(1)AbstractOsgiTests.java

(2)AbstractConfigurableOsgiTests.java

(3)AbstractDependencyManagerTests

(4)AbstractConfigurableBundleCreatorTests

1.AbstractOsgiTests类

下面说下该类中比较重要的一个方法,在这个方法中定义了bundle的加载过程。

 

	
	private Resource[] locateBundles() {
			//获取测试框架所需的bundle
			Resource[] testFrameworkBundles = getTestFrameworkBundles();
			//获取要测试的bundle.
			Resource[] testBundles = getTestBundles();
	
			if (testFrameworkBundles == null)
				testFrameworkBundles = new Resource[0];
			if (testBundles == null)
				testBundles = new Resource[0];
	
			Resource[] allBundles = new Resource[testFrameworkBundles.length + testBundles.length];
			System.arraycopy(testFrameworkBundles, 0, allBundles, 0, testFrameworkBundles.length);
			System.arraycopy(testBundles, 0, allBundles, testFrameworkBundles.length, testBundles.length);
			return allBundles;
		}
	
  

    其中的getTestFrameworkBundles()方法和getTestBundles()方法都由子类进行实现。对于getTestFrameworkBundles()方法,需要获取到测试框架所需的bundle。而对于getTestBundles()方法需要获取到要被测试的bundle.

2.AbstractDependencyManagerTests类

AbstractDependencyManagerTests是AbstractOsgiTests的子类,在其中提供了对getTestFrameworkBundles()方法的实现。

 

		protected Resource[] getTestFrameworkBundles() {
				return locateBundles(getTestFrameworkBundlesNames());
		}
 

在这个getTestFrameworkBundlesNames()方法中,会获取测试框架所需的bundle名称.默认情况下,会加载spring-osgi-test.jar中的boot-bundles.properties文件中指定的bundle.如果子类要更换测试框架所需的bundle,可重载AbstractDependencyManagerTests中的getTestingFrameworkBundlesConfiguration()方法。

 

		
		protected Resource[] locateBundles(String[] bundles) {
				if (bundles == null)
					bundles = new String[0];
		
				Resource[] res = new Resource[bundles.length];
				for (int i = 0; i < bundles.length; i++) {
					res[i] = locateBundle(bundles[i]);
				}
				return res;
		}
  
		
		protected Resource locateBundle(String bundleId) {
				Assert.hasText(bundleId, "bundleId should not be empty");
		
				// parse the String
				String[] artifactId = StringUtils.commaDelimitedListToStringArray(bundleId);
		
				Assert.isTrue(artifactId.length >= 3, "the CSV string " + bundleId + " contains too few values");
				// TODO: add a smarter mechanism which can handle 1 or 2 values CSVs
				for (int i = 0; i < artifactId.length; i++) {
					artifactId[i] = StringUtils.trimWhitespace(artifactId[i]);
				}
				//获取本地的maven仓储。
				ArtifactLocator aLocator = getLocator();
		
				return (artifactId.length == 3 ? aLocator.locateArtifact(artifactId[0], artifactId[1], artifactId[2])
						: aLocator.locateArtifact(artifactId[0], artifactId[1], artifactId[2], artifactId[3]));
			}

 

在上面的方法中,测试框架会默认到本地的maven仓储中加载所需的bundle. 对于默认的maven仓储,如果用户没有修改过maven的setting.xml中的这项值<localRepository>/path/to/local/repo</localRepository> ,则默认路径是:

${user.home}\.m2\repository这个目录下,对于我的机器则是C:\Users\boy\.m2\repository下。由于我修改了setting.xml中localRepository为 <localRepository>c:\repository</localRepository>,系统在加载bundle时还是会去C:\Users\boy\.m2\repository中寻找,我本地的maven仓储已经不是这个目录了,当然就会出现开头说的错误信息。

三.问题解决

对于上面的错误,我们已经知道了原因,最简单的一种修改方法是将maven中的setting.xml中的localRepository配置改回默认配置。但对于我而言,个人比较喜欢比较简短的文件路径,不想修改回默认的配置,哪就只好想别的办法。

在AbstractDependencyManagerTests类中,

 

	protected ArtifactLocator getLocator() {
		return locator;
	}
 

该方法是允许子类扩展的。Spring dm对ArtifactLocator提供的默认实现类是LocalFileSystemMavenRepository类。

该类不允许对maven中的repositoryHome进行设置。如果能有另一个实现ArtifactLocator接口的类且允许自已指定repositoryHome路径也可以灵活的解决上面的问题。下面是自定义的maven仓储定位器的实现:

 

	public class ConfigLocalFileSystemMavenRepository implements ArtifactLocator {
	
		/** discovered local m2 repository home */
		private String repositoryHome;
	
		public ConfigLocalFileSystemMavenRepository(String repositroyHome) {
			this.repositoryHome = repositroyHome;
		}
	
		//其它方法省略,省略的方法参见 LocalFileSystemMavenRepository中的实现。

	}
  

四.完整的测试代码如下:

 

	
	public class SpringDmSampleTest extends AbstractConfigurableBundleCreatorTests {
	
		@Override
		protected String[] getTestBundlesNames() {
			return new String[] { "com.mango.cache, cache.core, 1.0.0" };
		}
	
		@Override
		protected Resource getTestingFrameworkBundlesConfiguration() {
			return new InputStreamResource(SpringDmSampleTest.class
					.getResourceAsStream("boot-bundles.properties"));
		}
	
		@Override
		protected ArtifactLocator getLocator() {
			ArtifactLocator locator = new ConfigLocalFileSystemMavenRepository(
					"c:/repository");
			return locator;
		}
	
	}
 

对于要测试的bundle,一定要注意将它install到本地maven仓储中。

 

 

 

 

 

 

 

 

 

 

 

 

 

 类似资料: