`
mozhenghua
  • 浏览: 319480 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

maven plugin classloader加载class问题

 
阅读更多

1. 写一个基于maven的插件

今天在写基于maven plugin的一个小程序,它的功能是在maven执行package 阶段将已经打好包,从这个包中抽取分布式服务中依赖的类,之后会将这些服务器端依赖的类打成一个包。也就是执行了mvn package之后会在工程的target中生成两个jar包,一个是服务器端部署包,一个是客户端依赖包。客户端依赖包是服务器端包的一个子集。

该插件就是负责抽取服务器端部署包中的类。插件的工程名称是distribute-build,插件开发完成之后,会在具体的项目中使用,我搞了一个实验项目koubei-dian,在koubei-dian 这个分包项目中的pom中增加一个插件的配置节点,如下所示

<project></project>

<modelversion>4.0.0</modelversion>

<build></build>

.。。。。。。。。。

<plugins></plugins>

<plugin></plugin>

<groupid>com.koubei</groupid>

<artifactid>distribute-build</artifactid>

<version>1.0-SNAPSHOT</version>

<configuration></configuration>

<springconfig>dian.application.xml</springconfig>

<port>9999</port>

。。。。。。。。。

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></project>

<modelversion>4.0.0</modelversion>

<build></build>

.。。。。。。。。。

<plugins></plugins>

<plugin></plugin>

<groupid>com.koubei</groupid>

<artifactid>distribute-build</artifactid>

<version>1.0-SNAPSHOT</version>

<configuration></configuration>

<springconfig>dian.application.xml</springconfig>

<port>9999</port>

<dependencies></dependencies>

<dependency></dependency>

<groupid>com.koubei</groupid>

<artifactid>koubei-util</artifactid>

<version>1.0.0</version>

。。。。。。。。。

添加如上蓝色加粗的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包了。

完。。。。

分享到:
评论
2 楼 Phoenix0101 2016-07-15  
Phoenix0101 写道
好像知道你是如何获取的maven的类加载器
我使用文件获取的类加载器是基于当前工程目录的
lib里面的东西动态获取的时候也是找不到class
Xxx.class.getClassLoader();
或者
URL url = new File("xxx").toURI().toURL();

URL url = classRootfile.toURI().toURL();

URLClassLoader loader = new URLClassLoader(new URL[] {url});
这种方式都在加载maven中的引入的jar中的class时候找不到class

是不是一定要导入maven-poject等jar
1 楼 Phoenix0101 2016-07-15  
好像知道你是如何获取的maven的类加载器
我使用文件获取的类加载器是基于当前工程目录的
lib里面的东西动态获取的时候也是找不到class
Xxx.class.getClassLoader();
或者
URL url = new File("xxx").toURI().toURL();

URL url = classRootfile.toURI().toURL();

URLClassLoader loader = new URLClassLoader(new URL[] {url});
这种方式都在加载maven中的引入的jar中的class时候找不到class

相关推荐

Global site tag (gtag.js) - Google Analytics