今天试着用spring maven hibernate搭建了mvc项目时, dao,service分别作为两个子工程. service调用dao. 但是不太顺利.
dao直接运行mvn test是可以通过的.
当用service调用dao时候, 在service工程运行mvn test时, 报null指针异常. 查了下是因为dao作为jar程序聚合进了service, spring扫面实体类时, 就无法通过普通的方式加载文件了. 因为jar作为独立运行的文件格式. 得到文件目录为 xxxxxxxxxxxxxxxxxx.jar!com/xxx/xxxx/xxx.A.class
这种格式再用File对象是无法读取的.因此需要用到JarURLConnection来遍历jar文件.
String path = packagename.replace(".", "/");
log.debug("以jar方式读取spring文件");
log.debug("Begin scan entity package:" + path);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = classLoader.getResources(path);
URL url = null;
while(resources.hasMoreElements()){
URL resource = resources.nextElement();
String protocol = resource.getProtocol();
if("jar".equals(protocol)){
url = resource;
break;
}
}
JarURLConnection juc = (JarURLConnection) url.openConnection();
JarFile jf = juc.getJarFile();
Enumeration<JarEntry> entrys = jf.entries();
while(entrys.hasMoreElements()){
JarEntry clazz = entrys.nextElement();
String className = clazz.getName();
if(className.endsWith("/")){
continue;
}
log.debug("className="+className);
String shortName = className.substring(StringUtils.lastIndexOf(className, "/")+1,className.length()-6);
log.debug("className="+className);
log.debug("shortName="+shortName);
if(!className.equalsIgnoreCase("com/meijuu/dao/entity/"+shortName+".class")){
// if(className.startsWith("com/meijuu/dao/entity/") && className.endsWith(".class")){
// if(!StringUtils.startsWith(className, "com/meiju/dao/entity/")||!StringUtils.endsWith(className, ".class")){
continue;
}
Class<?> cla = Class.forName(packagename + "." + className);
Entity en = (Entity)cla.getAnnotation(Entity.class);
if(en == null)continue;
Table tab = (Table)cla.getAnnotation(Table.class);
if(tab.name() == null){
throw new FrameException("Entity " + className + " not set table name!");
}
if(tables.contains(tab.name())){
throw new FrameException("Exists same table for entity:" + cla.getName());
}
tables.add(tab.name());
Field[] fields = cla.getDeclaredFields();
for(Field field : fields){
CreateIndex gi = (CreateIndex)field.getAnnotation(CreateIndex.class);
if(gi != null){
SqlKey ck = generatorIndexSql(gi, cla, field);
if(!cache.contains(ck)){
updates.add(ck);
}
}
CreateForeignKey fk = (CreateForeignKey)field.getAnnotation(CreateForeignKey.class);
if(fk != null){
SqlKey ck = generateForeignKey(fk, cla, field);
if(!cache.contains(ck)){
updates.add(ck);
}
}
CodeGroup cg = (CodeGroup)field.getAnnotation(CodeGroup.class);
if(cg != null){
for(CodeItem item : cg.items()){
CodeHelper.add(cg.value(), item.value(), item.text());
}
}
}
}
==================引发新的问题=============================
这样修改后, 理论上service是已经可以读取jar形式的dao工程了. 但是在dao工程运行mvn deploy时, 反而失败了. 因为在build时,会先test, 这个时候由于dao并不是jar, 而是以普通目录形式组织文件, 是要通过File的方式读取文件的. 为了是dao能独立运行, 又能作为子工程给service, 因此把上面代码加了一层try…catch
try{ //优先以jar方式扫面
/******上方代码*****/
}catch(Exception e){ //非jar方式扫描,用于自身子项目扫面
String path = "/" + packagename.replace(".", "/");
System.out.println("以本工程方式扫描spring文件");
System.out.println("Begin scan entity package:" + path);
File dir = new File(this.getClass().getResource(path).getFile().replace("%20", " "));
for(File f : dir.listFiles()){
if(!f.getName().endsWith(".class"))continue;
String className = f.getName();
className = className.substring(0, className.lastIndexOf("."));
Class<?> cla = Class.forName(packagename + "." + className);
Entity en = (Entity)cla.getAnnotation(Entity.class);
if(en == null)continue;
Table tab = (Table)cla.getAnnotation(Table.class);
if(tab.name() == null){
throw new FrameException("Entity " + className + " not set table name!");
}
if(tables.contains(tab.name())){
throw new FrameException("Exists same table for entity:" + cla.getName());
}
tables.add(tab.name());
Field[] fields = cla.getDeclaredFields();
for(Field field : fields){
CreateIndex gi = (CreateIndex)field.getAnnotation(CreateIndex.class);
if(gi != null){
SqlKey ck = generatorIndexSql(gi, cla, field);
if(!cache.contains(ck)){
updates.add(ck);
}
}
CreateForeignKey fk = (CreateForeignKey)field.getAnnotation(CreateForeignKey.class);
if(fk != null){
SqlKey ck = generateForeignKey(fk, cla, field);
if(!cache.contains(ck)){
updates.add(ck);
}
}
CodeGroup cg = (CodeGroup)field.getAnnotation(CodeGroup.class);
if(cg != null){
for(CodeItem item : cg.items()){
CodeHelper.add(cg.value(), item.value(), item.text());
}
}
}
}
}
分别在dao工程上测试mvn deploy, 再在service工程运行mvn test也都测试通过.
================关键点总结========================
1. 这里并不是关心spring如何扫描,所以省略了其他代码. 只列出如何读取jar文件的代码
2. File读取文件的方式不适用于读取jar文件, 这里用的是JarUrlConnection, 应该也可以用JarFile来实现.