论坛首页 Java企业应用论坛

Java自动生成Spring配置文件

浏览 2968 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-07-01  
使用Spring有两种方式,一种是annotation,一种是配置。
其实使用annotation是不错的选择,但是annotation分布在系统代码之中不利于管理.
所以现在流行使用最多的,还是xml方式。
但是使用Spring的xml配置实在是麻烦,而且还容易把包名,类名写错。
于是我想:"能不能自已动生成Spring的配置文件";
说明一下:我一直相信代码的自动构建比“人工敲代码”更可靠
凭着这个想法,实现如下:
package org.frame.base.unit;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.frame.base.web.controller.BaseController;
import org.springframework.aop.ClassFilter;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * 自动构建bean配置文件 提供包名,自动生成该包以下的Bean配置文件内容.[包含子包]
 * 		1.	BaseController 如果为这个类的实例,自动生成parent
 *
 * @author yangchunlong.tw
 *
 */
public class GeneratorBean {

	private static final String PROTOCOL_FILE = "file";
	private static final String CLASS_FILE = ".class";
	private static final String BASE_CONTROLLER = "baseController";
	private final String packageName;
	private final ClassFilter filter;// 可以没有classFilter
	private final String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" \" http://www.springframework.org/dtd/spring-beans.dtd \">\n";


	public GeneratorBean(String packageName) {
		this(packageName, null);
	}

	public GeneratorBean(String packageName, ClassFilter filter) {
		this.packageName = packageName;
		this.filter = filter;
	}

	/**
	 * 生成配置串
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public String buildSpringBean() throws IOException {
		List<Class<?>> clazzs = scannerPackage();
		StringBuffer sb = new StringBuffer(header);
		for (Class clazz : clazzs) {
			try {
				if(BaseController.class.isInstance(clazz.newInstance())){
					sb.append("	<bean class=\"").append(clazz.getName()).append("\"").append(" parent=\"").append(BASE_CONTROLLER).append("\" ")
						.append(" />").append("\n");
				}else{
					sb.append("	<bean class=\"").append(clazz.getName()).append("\"")
						.append(" />").append("\n");
				}
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		return sb.toString();
	}

	/**
	 * 生成配置文件
	 * @throws IOException
	 */
	public void  buildSpringXML(String fileName){
		String base = System.getProperty("user.dir");
		FileOutputStream os = null;
		OutputStreamWriter writer = null;
		try {
			 os = new FileOutputStream(base+"/"+fileName);
			 writer = new OutputStreamWriter(os,Charset.forName("UTF-8"));
			 XStream xStream = new XStream(new DomDriver());// 不需要XPP3库
		     xStream.alias("beans", Beans.class);
		     xStream.alias("bean", Bean.class);
		     xStream.useAttributeFor(String.class);
		     xStream.aliasField("default-autowire", Beans.class, "default_autowire");
		     xStream.aliasField("class", Bean.class, "_class");
		     Beans beans = new Beans();
		     List<Class<?>> clazzs = scannerPackage();
		     for (Class clazz : clazzs) {
		    	 Bean bean = new Bean();
		    	 try {
					if(BaseController.class.isInstance(clazz.newInstance())){
							bean.set_class(clazz.getName());
							bean.setParent(BASE_CONTROLLER);
						}else{
							bean.set_class(clazz.getName());
						}
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
				beans.addBean(bean);
		     }
		    writer.write(header);
		    xStream.toXML(beans, writer);
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
//			IOUtils.copy(reader, writer);
			 try {
			    os.close();
				writer.close();
			 } catch (IOException e) {
	                e.printStackTrace();
	         }
		}
	}

	/**
	 * 遍历文件夹下的所有类
	 *
	 * @param packageName
	 * @return
	 * @throws IOException
	 */
	public List<Class<?>> scannerPackage() throws IOException {
		List<Class<?>> list = new ArrayList<Class<?>>();
		Enumeration<URL> en = getClass().getClassLoader().getResources(
				dotToPath(packageName));
		while (en.hasMoreElements()) {
			URL url = en.nextElement();
			if (PROTOCOL_FILE.equals(url.getProtocol())) {
				EncodingUtils parse = new EncodingUtils();
				String fileName = parse.decodeURL(url.getFile(), "UTF-8");
				File root = new File(fileName);
				findInDirectory(list, root, root, packageName);
			}
		}
		return list;
	}

	private void findInDirectory(List<Class<?>> results, File rootDir,
			File dir, String packageName) {
		File[] files = dir.listFiles();
		String rootPath = rootDir.getPath();
		for (File file : files) {
			if (file.isFile()) {
				String classFileName = file.getPath();
				if (classFileName.endsWith(CLASS_FILE)) {
					String className = classFileName.substring(rootPath
							.length()
							- packageName.length(), classFileName.length()
							- CLASS_FILE.length());
					add(results, pathToDot(className));
				}
			} else if (file.isDirectory()) {
				findInDirectory(results, rootDir, file, packageName);
			}
		}
	}

	/**
	 * 添加 某个类名到某架包中 此类必须匹配ClassFilter.[]
	 *
	 * @param results
	 * @param className
	 */
	private void add(List<Class<?>> results, String className) {
		Class<?> clazz = null;
		try {
			clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {
			// 架包中会有些类会加载不到.
			System.out.println("加载类失败:" + className);
			return;
		}
		if (filter == null || filter.matches(clazz))
			results.add(clazz);
	}

	/**
	 * 转包名为路径[. ==> /]
	 *
	 * @param s
	 * @return
	 */
	private String dotToPath(String s) {
		return s.replace('.', '/');
	}

	/**
	 * 转路径为包名[/ ==> .]/[\\ ==> .]
	 *
	 * @param s
	 * @return
	 */
	private String pathToDot(String s) {
		return s.replace('/', '.').replace('\\', '.');
	}

}



以上是实现代码,主要是使用字符串拼凑来实现xml的输出和xstream的面向对象方式来序列化XML,我还是比较喜欢xstream,还可以把xml反序列化为Java对象.

测试代码如下:
package com.frame.base.unit;

import java.io.IOException;

import org.frame.base.unit.GeneratorBean;
import org.springframework.aop.ClassFilter;
import org.springframework.web.servlet.mvc.Controller;


/**
 * 可以自动生成Controler的实例才生成配置文件
 * @author yangchunlong.tw
 *
 */
public class TestGeneratorBean {
	/**
	 * 不需要自动生成的Controller
	 */
	static String[] exps = new String[]{
								"handing.beanName.IndexSpringController"
							   };

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub

		GeneratorBean gg = new GeneratorBean("handing",new ClassFilter(){
			@Override
			public boolean matches(Class clazz) {
				try {
					if(Controller.class.isInstance(clazz.newInstance())){
							for(String exp:exps){
								if(exp.equals(clazz.getName())){
									return false;
								}
							}
							return true;
						}else{
							return false;
						}
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
		});
		System.out.println(gg.buildSpringBean());
		System.out.println(System.getProperty("user.dir"));
		gg.buildSpringXML("beans2.xml");
	}

}



这里定义了自动构建的过程,比如,我可以把包名handing以下的类生成bean,
这里定义了规则;
        1. 此类必须为Controller的实例类。
         2. 此类不在exps 的列表里面
可能有些类不需要生成配置,在这里可以配置。
当然规则是自定义的,我在自动构建的代码里面,也使用了规则,比如实例为"BaseController"的生成parent参数,如果不是的,只需要生成普通的bean.
以下是xstream的实例类:
package org.frame.base.unit;

import java.util.ArrayList;
import java.util.List;

/**
 * <beans default-autowire=\"byName\">
 * 	...
 *  <bean .../>
 * </beans>
 * @author yangchunlong.tw
 *
 */
public class Beans {
	/**
	 * 自动构建方式:默认byName[default_autowire == > default-autowire]
	 */
	private String default_autowire = "byName";

	/**
	 * Spring的bean.
	 */
	List<Bean> beans = new ArrayList<Bean>();

	public String getDefault_autowire() {
		return default_autowire;
	}
	public void setDefault_autowire(String default_autowire) {
		this.default_autowire = default_autowire;
	}
	public List<Bean> getBeans() {
		return beans;
	}
	public void setBeans(List<Bean> beans) {
		this.beans = beans;
	}
	public void addBean(Bean bean){
		beans.add(bean);
	}
}


package org.frame.base.unit;

public class Bean {

	/**
	 * bean_类包名[_class == > class]
	 */
	private String _class;

	/**
	 * bean_父bean
	 */
	private String parent;

	public String get_class() {
		return _class;
	}

	public void set_class(String _class) {
		this._class = _class;
	}

	public String getParent() {
		return parent;
	}

	public void setParent(String parent) {
		this.parent = parent;
	}

}


使用xstream扩展起来比较方便,比如,如果你使用的是CustomSpring扩展的Application.那么使用自己扩展的属性将是相当犀利的哦。
最后输出xml的结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " http://www.springframework.org/dtd/spring-beans.dtd ">
<beans default-autowire="byName">
    <bean class="handing.beanName.screen.home.HomeAuto"/>
    <bean class="handing.beanName.screen.home.AdminAuto" parent="baseController"/>
    <bean class="handing.beanName.screen.IndexAuto"/>
    <bean class="handing.beanName.IndexController"/>
    <bean class="handing.beanName.IndexAdminController"/>
</beans>

这可是相当标准的xml哦,直接复制到运行目标就可以了.
   发表时间:2011-07-12  
楼主试试Maven的Archetype呢
0 请登录后投票
论坛首页 Java企业应用版

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