希望大牛加入,共同为项目智能化管理jar包而努力
2016-12-09 16:54
211 查看
想听听大家对于我这个想法的一些看法,喷也好,赞也罢,希望留下您宝贵的建议! 我一直认为java程序员不需要自己去管理项目中依赖的jar,甚至不需要知道jar包的存在。什么,你不知道jar?好吧,下面就来说一说jar包。 就是一种被广泛使用的文件格式,比如你开发了一个牛逼闪闪的小程序,你们公司的其它人也想使用这个小程序,怎么办?一般的解决办法就是将这个程序打包成jar文件,发布到某个可供分享的地方(比如nexus),其它人如果使用maven或者gradle来管理项目的话,只需要加个jar的依赖配置即可,类似maven与Gradle的写法如下: Maven引入外部依赖写法:
Gradle引入外部依赖写法:
看到了吧,当你的程序需要使用第三方封装好的功能时,可以通过引入jar包来实现。 我为什么感觉到没有必要呢?因为我觉得完全可以依赖于某个智能化工具来处理这件事情,也就是智能化引包。想想下面的一些问题吧。 假如我要在项目中添加邮件发送功能并且想通过第三方jar包来实现时,不但要知道相关功能在哪个jar包(幸亏maven也帮助我们引入了三方包的依赖),并且需要准确写出jar包的相关信息,比如唯一名称,版本号等。 假如我使用了hibernate的3.6.7.Final这个版本,那么在新需求开发时,项目还需要用到spring相关的功能,应该怎么做呢?搜索使用spring需要引入哪些依赖包吗?根据本人多年的经验,如果你不查一下与已有Hibernate相关包的兼容性,那起冲突的概率是非常大的。 PS:不要和我说Eclipse,IDEA不是有这个功能吗?我说的不是项目新建的时候,而是在项目开发过程中加入新的三方jar包。 你有遇到过ClassNotFoundException异常吗?我觉得大部分时候出现这种异常都是由于相关jar包引入不全,或者由于版本的问题,某个类并不存在而引起的。这种问题一般在运行项目时才会发现,想想为什么?很简单,你的源代码中肯定没有直接用这个类,项目不报错你当然在编写源代码时发现不了。 以前工作时项目经理让我把两个老项目改造成maven项目,以方便对项目进行jar包管理,项目打包、编译和部署。我查找了这个项目依赖的每一个jar包(包多,非常痛苦),然后转换为maven的<dependency>,那时候想了想,不就是把以前依赖的包转换为maven的写法,让maven来引入不就行了吗?其实事情远没有想像的那么简单,尤其是你的项目依赖的包很多时,非常容易引起冲突。 举个例子,好多的三方jar包会依赖log4j或者logback进行日志记录,maven就会帮助你引入这些三方jar包所依赖的包,那么就有可能引入一些版本不同的日志记录包,也就是项目中出现了好多相同的类,还需要配合<dependency>节点下的<exclude>来排除某些包。 记得曾经struts2的核心包暴露了一个巨大的安全隐患,而你又不幸的在项目中使用了这一版本的包,那么肯定还需要修改依赖配置,引入最新发布的补丁包(你知道补丁包具体的版本号是多少吗)。对于知道的人是这样,对于不知道的人也就那样了。 如果你经历过这些事情,那么假如现在有一个智能管理jar包的工具(暂时命名为autort,意为auto import)为你管理类似下面这一坨的东西,你愿不愿意用上一用呢?
使用时当你再想使用三方依赖的功能,如javamail的邮件发送功能时,可直接查找javamail api,在类中编写相关代码即可。如使用如下的类
运行autort后会引入与当前项目中其它jar包不冲突的,最新稳定版本的javamail相关包。添加上面的信息是为了告诉autort,我需要使用javamail相关的发送功能,如果你去掉了HtmlEmail类及相关引入,那么再次运行管理工具后,相关包也会去除。 不必担心在使用某个api接口时,当前javamail版本是否支持的问题。如果出现了找不到相关方法的提示时,只管调用这个方法,然后重新运行一下autort即可。 如果使用编程工具如Eclipse或IDEA的话项目可能显示红叉或者红色下划线,完全不必在意,需要保证的是你的项目没有语法错误,只是缺少了相关jar包而已。 听着还不错吧,不过要是实现起来可没那么容易。 首先能够想到的问题就一大堆,如何通过扫描用户的源代码准确retrieve出相关依赖信息(这个就够繁琐复杂的,已经快做了两个月了),即使找到了 各种依赖信息,又如何匹配出所有合适的jar包呢?肯定需要在服务端事先对jar包进行大规模的扫描,找出不同版本的不同依赖等等...............太多太多 不过经过2个月的思考,感觉越来越有点眉目了,最近准备好好出个文档,然后整理一下项目,多添加点注释,然后就开源啦!希望感兴趣的朋友一起加入,共同为解放程序员的双手而努力! 最后来一点干货吧,也不枉对这个项目不感兴趣的朋友白来一趟。 Java在调用Get()方法时给其传递了一串字符串引用,如下:
如何正确的分析这串字符串引用是一个关键。autort必须知道这串字符串引用代表的真正意思。可能你会毫不犹豫地说是在cn.autort.core包下的Expression类中的静态变量a。
如果用户编写代码时有良好的编码规范,也许你可以马上对这个字符串进行正确的分解。但是总有一些情况下,这个字符串代表的意思并不是这样。 它可以代表连续的变量引用,cn、autort、core、Expression与a全部为变量
它可以代表所有的类引用,就是内部类嵌套内部类的情况
它可以代表很多,但是有些规则还是需要知道的,那就是变量后面不可能直接跟类名和包名,包后不可能直接跟变量名。 那么如何在某些情况下正确分解出这个字符串代表的信息。我们还是需要基于已有的包信息和类信息进行分解。autort需要扫描所有的包和类,并进行有组织的存储,以便快速进行判断。在这里可以使用Trie树来解决。
如果你不了解什么是Trie树,可以看一看这篇文章。传送门:http://www.cnblogs.com/beiyeqingteng/p/5625540.html 我要做的只是稍加更改一下Trie树,让它适应需求即可。
这是Node结点,每个包名为一个节点。如cn、core等。需要指出的是map中存储的数据。key为类名,如果类中有类的话,以逗号隔开。例如A.B,值就是对应的具体的语法树了。
提供了插入和搜索的方法,并不复杂。不过需要兼容那些没有包路径的类。提供了个小Demo测试一下。建立Trie树并存储包和类的相关信息:Trie trie = new Trie();
Node a1 = trie.insert(new String[]{"cn","autort","core"});
a1.put("Compilation", "ReferenceASTNode");
a1.put("Compilation.A", "ReferenceASTNode"); // 嵌套类Compilation.A
Node a2 = trie.insert(new String[]{"cn","autort","core","expression"});
a2.put("Assignment", "ReferenceASTNode");
a2.put("FieldAccess", "ReferenceASTNode");
运行的结果如下:
以后有时间的话就多码点字,讲一讲autort技术实现上的一些原理和细节。
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.7.Final</version> </dependency>
Gradle引入外部依赖写法:
dependencies { compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final' }
看到了吧,当你的程序需要使用第三方封装好的功能时,可以通过引入jar包来实现。 我为什么感觉到没有必要呢?因为我觉得完全可以依赖于某个智能化工具来处理这件事情,也就是智能化引包。想想下面的一些问题吧。 假如我要在项目中添加邮件发送功能并且想通过第三方jar包来实现时,不但要知道相关功能在哪个jar包(幸亏maven也帮助我们引入了三方包的依赖),并且需要准确写出jar包的相关信息,比如唯一名称,版本号等。 假如我使用了hibernate的3.6.7.Final这个版本,那么在新需求开发时,项目还需要用到spring相关的功能,应该怎么做呢?搜索使用spring需要引入哪些依赖包吗?根据本人多年的经验,如果你不查一下与已有Hibernate相关包的兼容性,那起冲突的概率是非常大的。 PS:不要和我说Eclipse,IDEA不是有这个功能吗?我说的不是项目新建的时候,而是在项目开发过程中加入新的三方jar包。 你有遇到过ClassNotFoundException异常吗?我觉得大部分时候出现这种异常都是由于相关jar包引入不全,或者由于版本的问题,某个类并不存在而引起的。这种问题一般在运行项目时才会发现,想想为什么?很简单,你的源代码中肯定没有直接用这个类,项目不报错你当然在编写源代码时发现不了。 以前工作时项目经理让我把两个老项目改造成maven项目,以方便对项目进行jar包管理,项目打包、编译和部署。我查找了这个项目依赖的每一个jar包(包多,非常痛苦),然后转换为maven的<dependency>,那时候想了想,不就是把以前依赖的包转换为maven的写法,让maven来引入不就行了吗?其实事情远没有想像的那么简单,尤其是你的项目依赖的包很多时,非常容易引起冲突。 举个例子,好多的三方jar包会依赖log4j或者logback进行日志记录,maven就会帮助你引入这些三方jar包所依赖的包,那么就有可能引入一些版本不同的日志记录包,也就是项目中出现了好多相同的类,还需要配合<dependency>节点下的<exclude>来排除某些包。 记得曾经struts2的核心包暴露了一个巨大的安全隐患,而你又不幸的在项目中使用了这一版本的包,那么肯定还需要修改依赖配置,引入最新发布的补丁包(你知道补丁包具体的版本号是多少吗)。对于知道的人是这样,对于不知道的人也就那样了。 如果你经历过这些事情,那么假如现在有一个智能管理jar包的工具(暂时命名为autort,意为auto import)为你管理类似下面这一坨的东西,你愿不愿意用上一用呢?
<dependencies> <dependency> <groupId>org.apache.geronimo.ext.openejb</groupId> <artifactId>javaee-api</artifactId> <version>5.0.3</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> ... </dependencies>
使用时当你再想使用三方依赖的功能,如javamail的邮件发送功能时,可直接查找javamail api,在类中编写相关代码即可。如使用如下的类
HtmlEmail email = new HtmlEmail();还需要手动键入import相关信息,如:
import org.apache.commons.mail.HtmlEmail;
运行autort后会引入与当前项目中其它jar包不冲突的,最新稳定版本的javamail相关包。添加上面的信息是为了告诉autort,我需要使用javamail相关的发送功能,如果你去掉了HtmlEmail类及相关引入,那么再次运行管理工具后,相关包也会去除。 不必担心在使用某个api接口时,当前javamail版本是否支持的问题。如果出现了找不到相关方法的提示时,只管调用这个方法,然后重新运行一下autort即可。 如果使用编程工具如Eclipse或IDEA的话项目可能显示红叉或者红色下划线,完全不必在意,需要保证的是你的项目没有语法错误,只是缺少了相关jar包而已。 听着还不错吧,不过要是实现起来可没那么容易。 首先能够想到的问题就一大堆,如何通过扫描用户的源代码准确retrieve出相关依赖信息(这个就够繁琐复杂的,已经快做了两个月了),即使找到了 各种依赖信息,又如何匹配出所有合适的jar包呢?肯定需要在服务端事先对jar包进行大规模的扫描,找出不同版本的不同依赖等等...............太多太多 不过经过2个月的思考,感觉越来越有点眉目了,最近准备好好出个文档,然后整理一下项目,多添加点注释,然后就开源啦!希望感兴趣的朋友一起加入,共同为解放程序员的双手而努力! 最后来一点干货吧,也不枉对这个项目不感兴趣的朋友白来一趟。 Java在调用Get()方法时给其传递了一串字符串引用,如下:
String a = Get(cn.autort.core.Expression.a);
如何正确的分析这串字符串引用是一个关键。autort必须知道这串字符串引用代表的真正意思。可能你会毫不犹豫地说是在cn.autort.core包下的Expression类中的静态变量a。
如果用户编写代码时有良好的编码规范,也许你可以马上对这个字符串进行正确的分解。但是总有一些情况下,这个字符串代表的意思并不是这样。 它可以代表连续的变量引用,cn、autort、core、Expression与a全部为变量
它可以代表所有的类引用,就是内部类嵌套内部类的情况
它可以代表很多,但是有些规则还是需要知道的,那就是变量后面不可能直接跟类名和包名,包后不可能直接跟变量名。 那么如何在某些情况下正确分解出这个字符串代表的信息。我们还是需要基于已有的包信息和类信息进行分解。autort需要扫描所有的包和类,并进行有组织的存储,以便快速进行判断。在这里可以使用Trie树来解决。
如果你不了解什么是Trie树,可以看一看这篇文章。传送门:http://www.cnblogs.com/beiyeqingteng/p/5625540.html 我要做的只是稍加更改一下Trie树,让它适应需求即可。
class Node { String term; // the character in the node boolean isEnd; // whether the end of the words int count; // the number of words sharing this character LinkedList<Node> childList; // the child list Map<String,Object> map = null; // store class name public Node(String term) { this.childList = new LinkedList<Node>(); this.isEnd = false; this.term = term; this.count = 0; } public Node subNode(String term) { if (childList != null) { for (Node eachChild : childList) { if (eachChild.term == term) { return eachChild; } } } return null; } public void put(String key,Object value){ if(map==null){ map = new HashMap<String,Object>(); } map.put(key, value); } public Object get(String key){ return map.get(key); } }
这是Node结点,每个包名为一个节点。如cn、core等。需要指出的是map中存储的数据。key为类名,如果类中有类的话,以逗号隔开。例如A.B,值就是对应的具体的语法树了。
public class Trie { private Node root; public Trie() { root = new Node("root"); // 第一个节点的字符串为空 } public Node getRoot(){ return root; } public Node insert(String[] terms) { if (searchNode(terms)!=null) return searchNode(terms); Node current = root; for (int i = 0; i < terms.length; i++) { Node child = current.subNode(terms[i]); if (child != null) { current = child; } else { current.childList.add(new Node(terms[i])); current = current.subNode(terms[i]); } current.count++; } current.isEnd = true; return current; } public Node searchNode(String[] terms) { Node current = root; for (int i = 0; i < terms.length; i++) { if (current.subNode(terms[i]) == null){ return null; }else{ current = current.subNode(terms[i]); } } if(current.isEnd){ return current; } return null; } public int[] searchParts(String[] terms) { int[] result = new int[]{-1,-1}; int matchedIndex = -1; Node current = root; for (int i = 0; i < terms.length; i++) { if (current.subNode(terms[i]) == null){ break; }else{ current = current.subNode(terms[i]); if(current.isEnd){ matchedIndex = i; } } } result[0] = matchedIndex; StringBuffer buffer = new StringBuffer(); for(int j=matchedIndex+1;j<terms.length;j++){ buffer.append(terms[j]); Object obj = current.get(buffer.toString()); if(obj!=null){ result[1] = j; } if(j!=terms.length-1){ buffer.append("."); } } return result; } }
提供了插入和搜索的方法,并不复杂。不过需要兼容那些没有包路径的类。提供了个小Demo测试一下。建立Trie树并存储包和类的相关信息:Trie trie = new Trie();
Node a1 = trie.insert(new String[]{"cn","autort","core"});
a1.put("Compilation", "ReferenceASTNode");
a1.put("Compilation.A", "ReferenceASTNode"); // 嵌套类Compilation.A
Node a2 = trie.insert(new String[]{"cn","autort","core","expression"});
a2.put("Assignment", "ReferenceASTNode");
a2.put("FieldAccess", "ReferenceASTNode");
int[] result1 = trie.searchParts(new String[]{"cn","autort","core","Compilation","A","B","a"}); System.out.println(result1[0]+"/"+result1[1]); int[] result2 = trie.searchParts(new String[]{"cn","autort","core","expression","Compilation"}); System.out.println(result2[0]+"/"+result2[1]); int[] result3 = trie.searchParts(new String[]{"ClassA"}); System.out.println(result3[0]+"/"+result3[1]);
运行的结果如下:
2/4 // cn.autort.core为包名,Compilation.A为类名,剩下的B和a就是类内的变量名了 3/-1 // cn.autort.core.expression为包中,Compilation无论做为包名还是类名都不存在 -1/0 // 无包名,ClassA为类名
以后有时间的话就多码点字,讲一讲autort技术实现上的一些原理和细节。
相关文章推荐
- 希望有兴趣的加入,共同为项目智能化管理jar包而努力 第二篇
- 希望有兴趣的加入,共同为项目智能化管理jar包而努力 第一篇
- [转]在项目开发总的一些感受,希望大家共同来探讨项目管理中的一些看法
- 在项目开发总的一些感受,希望大家共同来探讨项目管理中的一些看法
- 在项目开发总的一些感受,希望大家共同来探讨项目管理中的一些看法
- 在项目开发总的一些感受,希望大家共同来探讨项目管理中的一些看法
- 使用Maven管理依赖JAR文件,自定义项目布局,利用ANT生成不同的发布包
- 使用Maven管理依赖JAR文件,自定义项目布局,利用ANT生成不同的发布包
- 新项目管理——改变种群习性的努力
- mvn管理项目jar包
- maven项目pom文件中加入本地jar包
- 项目希望腾讯质量管理(软件测试实习生)二面(复试),HR面
- Hello China操作系统项目已注册到SourceForge上,欢迎OS fans加入共同开发
- 加入log4j.properties项目运行日志管理,将日志文件保存在硬盘文件夹中
- iReaperPlus一个开源的工具项目,旨在获得MSDN学习资料,希望你能加入进来
- SWT学习笔记(一)-在项目中加入swt.jar
- 将项目加入VSS源代码管理中
- 【263期门诊集锦】共同探索.NET开发与项目管理中的精髓 推荐
- 最近开始关注Castle 开源项目,希望与大家共同学习共同进步。
- 项目管理要素:成功取决于三个阶段的努力