论坛首页 Java企业应用论坛

零配置Service

浏览 6158 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-09-14  
1.不使用 Annotation
2.前提:约定大于配置, Service配置有规则可循
3.实现方式:
在Spring初始化时生成Service XML 配置文件,加载到初始化过程中
4.代码
1.MyXmlWebApplicationContext.java
/**
 * 
 */
package service.utils;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author yangjk
 * @since 2009-9-13
 */
public class MyXmlWebApplicationContext extends XmlWebApplicationContext {

	private static Log LOG = LogFactory.getLog(MyXmlWebApplicationContext.class);

	private Properties getProperties() {
		try {
			return PropertiesLoaderUtils.loadAllProperties("config.properties");
		} catch (IOException e) {
			LOG.error("读取config.properties失败.");
			throw new RuntimeException(e);
		}
	}
	
	public byte[] getGenServiceInputStream() {
		Properties prop = getProperties();
		String path = prop.getProperty("service.path");
		String pkg = prop.getProperty("service.package");
		try {
			File file = ResourceUtils.getFile("classpath:" + path);
			Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
			List list = DomUtils.getChildElementsByTagName(doc.getDocumentElement(), "bean");
			Map map = new HashMap();
			for (int i = 0; i < list.size(); i++) {
				Element ele = (Element) list.get(i);
				map.put(ele.getAttribute("id"), ele.getAttribute("class"));
			}
			Map genMap = this.getPackageService(pkg);
			for (Iterator iterator = genMap.entrySet().iterator(); iterator.hasNext();) {
				Map.Entry entry = (Map.Entry) iterator.next();
				String id = (String)entry.getKey();
				String clazz = (String)entry.getValue();
				if(map.get(id) == null) {
					Element comm = doc.createElement("bean");
					comm.setAttribute("id", id);
					comm.setAttribute("class", clazz);
					doc.getDocumentElement().appendChild(comm);
					if (LOG.isDebugEnabled()) {
						LOG.info("Service Gen XML :" + id +" -> " + clazz);
					}
				}
			}
			DOMSource ds = new DOMSource(doc);
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			StringWriter writer = new StringWriter();
			Result result = new StreamResult(writer);
			transformer.transform(ds, result);
			return writer.toString().getBytes();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null ; 
	}

	private static final String RESOURCE_PATTERN = "**/*.class";

	private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

	public Map getPackageService(String pkg) {
		Map map = new HashMap();
		
		String[] pkgs = pkg.split(",");
		try {
			for (int i = 0; i < pkgs.length; i++) {
				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
						+ ClassUtils.convertClassNameToResourcePath(pkgs[i])
						+ RESOURCE_PATTERN;
				Resource[] resources;
				resources = this.resourcePatternResolver.getResources(pattern);
				MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
				for (Resource resource : resources) {
					if (resource.isReadable()) {
						MetadataReader reader = readerFactory.getMetadataReader(resource);
						String className = reader.getClassMetadata().getClassName();
						String beanId = getBeanId(className);
						if (beanId != null) {
							map.put(beanId, className);
						}
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(
					"Failed to scan classpath for unlisted classes", e);
		}
		return map;
	}

	//约定
	private String getBeanId(String className) {
		if(StringUtils.isNotBlank(className) && className.indexOf('$') == -1) {
			String simpleName = StringUtils.substringAfterLast(className, ".");
			if(simpleName.endsWith("Impl")) {
				simpleName = simpleName.substring(0, simpleName.length()-"Impl".length());
			}
			simpleName = WordUtils.uncapitalize(simpleName);
			return simpleName ; 
		}
		return null ; 
	}
	
	protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
		Resource resource2 = new ByteArrayResource(this.getGenServiceInputStream());
		reader.loadBeanDefinitions(resource2);
	}
}


2.config.properties
#spring service xml path
service.path=conf/service.xml
#spring service package
service.package=service.impl

3.service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
	<!-- add your service here -->
</beans>

4.web.xml
		<context-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
					 /WEB-INF/classes/conf/dataAccessContext-local.xml 
					 /WEB-INF/classes/conf/applicationContext.xml
					 /WEB-INF/classes/conf/controller.xml
			</param-value>
		</context-param>
		<context-param>
			<param-name>contextClass</param-name>
			<param-value>service.utils.MyXmlWebApplicationContext</param-value>
		</context-param>
		

5.按照规则可以随意扩展
   发表时间:2009-09-15  
thinkinperson 写道
请问有这个需要吗?能在什么场景中用这个呢?annocation不好吗?
如果按你的设计。一个接口。两个实现类。你怎么能判断到底是使用了哪个实现类呢?

jdk1.4没有Annotation ,写Annotation有时候觉得多余,能不写就不写
一个接口2个实现类的情况你可以在service.xml 按照getBeanId方法的规则为这个bean取个ID配置,在MyXmlWebApplicationContext.java不会覆盖有这个Id的配置.
0 请登录后投票
   发表时间:2009-09-15  
一个接口。两个实现类。2个实现类的名称一般是不一样的, 会生成2个ID不一样的bean,
按照id去用就行了, 如果是不同package中的名称一样的实现类,按照上面的方法去做就行了.
0 请登录后投票
   发表时间:2009-09-17  
何苦咧~~~
1 请登录后投票
   发表时间:2009-09-18  
satanest 写道
何苦咧~~~

yy 呀.
0 请登录后投票
   发表时间:2009-09-23  
还是应用annotation的方式比较好,语言不可能太智能
1 请登录后投票
   发表时间:2009-09-23  
  各有所好么.
1 请登录后投票
   发表时间:2009-09-27  
支持楼主的 service 零配置方案,可节省大量配置,维护工作 。 现在敏捷设计都趋向 约定大于配置 (CBC).

到处写 Annotation ,本质还是一种配置,而且分散到了类中,这种用法我一直觉得很恶心,对于大型系统,维护难度非常大,很不明智。

“语言不可能太智能”,这句话没错,所以,在包,类命名上尽量遵循 CBC 原则,以减少无聊的机械劳动。
1 请登录后投票
   发表时间:2009-09-27  
raymond2006k 写道
支持楼主的 service 零配置方案,可节省大量配置,维护工作 。 现在敏捷设计都趋向 约定大于配置 (CBC).

到处写 Annotation ,本质还是一种配置,而且分散到了类中,这种用法我一直觉得很恶心,对于大型系统,维护难度非常大,很不明智。

“语言不可能太智能”,这句话没错,所以,在包,类命名上尽量遵循 CBC 原则,以减少无聊的机械劳动。

其实这是为了偶的原始需求, 懒...
0 请登录后投票
   发表时间:2010-04-17  
扩展的思路不错!
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics