1. 写一个基于maven的插件
今天在写基于maven plugin的一个小程序,它的功能是在maven执行package 阶段将已经打好包,从这个包中抽取分布式服务中依赖的类,之后会将这些服务器端依赖的类打成一个包。也就是执行了mvn package之后会在工程的target中生成两个jar包,一个是服务器端部署包,一个是客户端依赖包。客户端依赖包是服务器端包的一个子集。
该插件就是负责抽取服务器端部署包中的类。插件的工程名称是distribute-build,插件开发完成之后,会在具体的项目中使用,我搞了一个实验项目koubei-dian,在koubei-dian 这个分包项目中的pom中增加一个插件的配置节点,如下所示
<project > <modelVersion>4.0.0</modelVersion> <build> <plugins> <plugin> <groupId>com.koubei</groupId> <artifactId>distribute-build</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <springConfig>dian.application.xml</springConfig> <port>9999</port> </configuration> </plugin> </plugins> </build> </project>
2. 发现问题
然后在dos命令行中敲入下面这个命令:
\koubei-dian>mvn com.koubei:distribute-build:distill |
但是在执行distill这个goal时候出现了错误
java.lang.NoClassDefFoundError: com/koubei/util/Pager at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2427) at java.lang.Class.privateGetPublicMethods(Class.java:2547) at java.lang.Class.getMethods(Class.java:1410) at com.koubei.plugin.distribute.ClassMetaInfo.getAllDepandClass(ClassMet aInfo.java:51) at com.koubei.plugin.distribute.ServiceClassManager.execute(ServiceClass Manager.java:109) at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPlugi nManager.java:483) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(Defa ultLifecycleExecutor.java:678) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandalone Goal(DefaultLifecycleExecutor.java:553) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(Defau ltLifecycleExecutor.java:523) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHan dleFailures(DefaultLifecycleExecutor.java:371) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegmen ts(DefaultLifecycleExecutor.java:332) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLi fecycleExecutor.java:181) |
奇怪!我明明已经在koubeid-dian的pom中的depandance中添加了com/koubei/util/Pager 这个类所在包的依赖呀,为啥当前的classloader还是不能加载这个类呢?直觉告诉我应该是maven的classloader的加载机制的问题。于是还得依赖万能的google,终于我找到了maven reference网站上关于maven类加载机制的说明。http://maven.apache.org/guides/mini/guide-maven-classloading.html
这个文档中说了四种类加载机制,分别是:
1. System Classloader
2. Core Classloader
3. Plugin Classloaders
4. Custom Classloaders
其中我最关心的是plugin classloaders,这个类加载器从类加载的层次关系来看是继承与System classloader 和Core Classloader的,凭我想当然的理解在插件goal执行的时候插件的classloader已经包含的project pom 中申明的依赖包。但是,plugin classloader说明中有这么一句话:
Please note that the plugin classloader does neither contain the dependencies of the current project nor its build output. Instead, plugins can query the project's compile, runtime and test class path from the MavenProject in combination with the mojo annotation requiresDependencyResolution from the Mojo API Specification. For instance, flagging a mojo with @requiresDependencyResolution runtime enables it to query the runtime class path of the current project from which it could create further classloaders. |
翻译一下:
请注意,plugin classloader既不包含当前工程的dependencies,也不包含当前工程的输出目录。但是,如果你现在插件运行的时候想引用当前工程的编译(compile)、运行时(runtime)、测试(test)的classpath,可以通过MavenProject 这个组合在成员对象来调用,这个mojo对象需要有“requiresDependencyResolution”这个annotation |
3. 解决问题
通过以上说明,我知道解决当前maven plugin 不能正常加载类的问题可以通过两个方法解决:
方法1:在plugin配置的时候为plugin配置节点单独配置一个dependacne
<project > <modelVersion>4.0.0</modelVersion> <build> .。。。。。。。。。 <plugins> <plugin> <groupId>com.koubei</groupId> <artifactId>distribute-build</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <springConfig>dian.application.xml</springConfig> <port>9999</port> </configuration> <dependencies> <dependency> <groupId>com.koubei</groupId> <artifactId>koubei-util</artifactId> <version>1.0.0</version> </dependency> </dependencies> </plugin> 。。。。。。。。。 </plugins> </build> </project> |
添加如上蓝色加粗的dependencies节点。
方法2:在plugin类中添加MavenProject 一个成员对象,然后再类级别注释上添加@requiresDependencyResolution runtime注释项
1. /** 2. * @goal extract 3. * @phase package 4. * @requiresDependencyResolution test 5. */ 6. public class ServiceClassManager extends AbstractMojo { 7. 8. /** 9. * @parameter default-value="${project}" 10. * @required 11. * @readonly 12. */ 13. private MavenProject project; 14. 15. public void execute() throws MojoExecutionException { 16. 17. System.out.println(project.getArtifact().getFile().getAbsolutePath()); 18. 19. } 20. }
|
通过以上这种方式就可以达到,不需要在plugin配置节点额外添加配置依赖来达到能够取道pom compile阶段需要依赖的那些jar包了。
完。。。。