`
liuxuehua12
  • 浏览: 6073 次
  • 来自: ...
最近访客 更多访客>>
社区版块
存档分类
最新评论

插件运行时动态加载jar--解决jet2模板动态添加问题

阅读更多

昨天在编写代码生成器时遇到一个问题:用JET2模板引擎不能够动态编译代码模板文件,也就意味着我不能都动态的添加自定义代码模板,这和我希望的开放式式的代码生成器不符合。我最看中的就是jet2模板里能由模板编写者自己控制生成哪些代码文件,很开发灵活。如果放弃jet2的话我还没找到更好的代替者,所以我只能想方设法使代码生成器能动态加载用户添加的模板。想到的办法是:让用户编写好代码模板后,将模板文件和编译好的模板类一起打包成jar,然后由代码生成运行时动态加载。

插件动态加载jar方法:自定义类加载器继承URLClassLoader,重写addURl方法使之变为public,方便多次添加jar。

代码:

public class DynamicClassLoader extends URLClassLoader {
	
	/**
	 * 类加载器实例化后,再添加单个jar
	 */
	@Override
	public void addURL(URL url) {
		super.addURL(url);
	}

	static final URL[] EMPTY_URLS = new URL[]{};

	public DynamicClassLoader(){
		super(EMPTY_URLS);
	}
	
	public DynamicClassLoader(URL[] urls){
		super(urls ,(Thread.currentThread().getContextClassLoader() == null ||
	                Thread.currentThread().getContextClassLoader() == ClassLoader.getSystemClassLoader())?
	                Compiler.class.getClassLoader():Thread.currentThread().getContextClassLoader());
	}

	public DynamicClassLoader(ClassLoader parent){
		super(EMPTY_URLS,parent);
	}
	
	/**
	 * 创建类加载器
	 * @param urls 待加载的jarUrl集合
	 * @param parent 父类加载器
	 */
	public DynamicClassLoader(URL[] urls, ClassLoader parent){
		super(urls,parent);
	}

}
 

在需要的地方实例化调用(如插件启动时实例化),调用代码如下:

代码:

	/**
	 * 动态加载指定jar
	 * @param jarURL
	 */
	public void loadJar(File jar){
		if(jar != null){
			try {
				dynamicClassLoader.addURL(jar.toURI().toURL());
			} catch (MalformedURLException e) {
				LogUtil.logError(e.getMessage(),e);
			}
			setPathToTemplateClassMapByJar(jar);
		}
	}

	/**
	 * 根据模板jar文件设置代码模板路径和类映射集合
	 * @param jar 模板jar文件,必须包含模板源码和编译后的模板类
	 */
	public void setPathToTemplateClassMapByJar(File jar){
		if(jar == null){
			return;
		}
		try {
			JarFile jf = new JarFile(jar);
			final Enumeration<JarEntry> entries = jf.entries();
			//保存所有模板源文件
			List<String> templatePathList = new ArrayList<String>();
			//保存编译的模板类名和类全路径映射集合
			Map<String, String> classMap = new HashMap<String, String>();
	        while (entries.hasMoreElements()) {
	            final JarEntry entry = entries.nextElement();
	            final String entryName = entry.getName();
	            if (entryName.startsWith("templates")) {
	            	templatePathList.add(entryName);
	            }else if(entryName.endsWith(".class")){
	            	int lastspindex = entryName.lastIndexOf("/"); 
	            	String key = entryName.substring(lastspindex + 1, entryName.length() - 6);
	            	String className = entryName.substring(0, entryName.length() - 6).replace("/", ".");
	            	classMap.put(key, className);
	            }
	        }
	        
	        for(String templatePath : templatePathList){
	        	int lastspindex = templatePath.lastIndexOf("/"); 
	        	int lastpoindex = templatePath.lastIndexOf("."); 
	        	String key = "_jet_"+templatePath.substring(lastspindex + 1, lastpoindex).replace(".", "");
	        	String className = classMap.get(key);
	        	if(className != null){
	        		pathToTemplateClassMap.put(templatePath, className);
	        	}
	        }

		} catch (IOException e) {
			LogUtil.logError(e.getMessage(),e);
		}
	}
 

 

还要修改代码生成器插件的jet2扩展中的模板加载器类,使之能根据模板路径用自定义类加载器来实例化模板对象。

代码如下:

/**
 * 自定义模板加载器
 * CreatorTemplateLoader
 */
public class CreatorTemplateLoader implements JET2TemplateLoader,
        JET2TemplateLoaderExtension {

    private JET2TemplateLoader delegate = null;

     /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jet.JET2TemplateLoader#getTemplate(java.lang.String)
     */
    public JET2Template getTemplate(final String templatePath) {
        final String ordinal = CodeGenActivator.pathToTemplateClassMap.get(templatePath);
        if(ordinal != null) {
        	try {
				return (JET2Template)CodeGenActivator.getDefault().getDynamicClassLoader().loadClass(ordinal).newInstance();
			} catch (InstantiationException e) {
				LogUtil.logError(e.getMessage(), e);
			} catch (IllegalAccessException e) {
				LogUtil.logError(e.getMessage(), e);
			} catch (ClassNotFoundException e) {
				LogUtil.logError(e.getMessage(), e);
			}
        }
        return this.delegate != null ? this.delegate.getTemplate(templatePath) : null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jet.JET2TemplateLoaderExtension#getDelegateLoader()
     */
    public JET2TemplateLoader getDelegateLoader() {
        return this.delegate;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.jet.JET2TemplateLoaderExtension#setDelegateLoader(org.eclipse
     * .jet.JET2TemplateLoader)
     */
    public void setDelegateLoader(final JET2TemplateLoader loader) {
        this.delegate = loader;
    }
}
 

隔了好久才记起这个文章没写完,今天记起后赶紧补充完整了。

0
3
分享到:
评论

相关推荐

    动态加载jar包

    动态加载jar包是一种在程序运行时按需引入外部库或者组件的技术,这使得应用程序更加灵活,可以适应不同的环境和需求。这种技术广泛应用于插件系统、框架开发以及服务升级等场景,因为它允许程序在不重启的情况下...

    java 动态加载jar包

    在Java编程语言中,动态加载jar包是一种常见的需求,它允许程序在运行时根据需要加载新的功能或更新现有的模块,增强了软件的灵活性和可扩展性。动态加载jar包技术主要涉及Java的反射机制、类加载器和插件系统。下面...

    Java 动态加载jar文件示例

    在Java编程语言中,动态加载jar文件是一种关键的特性,它允许程序在运行时加载新的类库或组件,而不是在编译时静态地链接。这种技术对于实现插件式开发或者模块化系统至关重要,因为它提供了灵活性和可扩展性。下面...

    jarjar-1.4.jar

    总之,jarjar-1.4.jar是解决Java开发中jar包冲突问题的一个有效工具。通过合理使用规则文件,我们可以对jar包进行定制化处理,从而更好地管理和优化我们的项目。在实践中,不断探索和学习jarjar的用法,能够帮助我们...

    JAVA动态加载JAR zip包

    在Java编程中,动态加载JAR或ZIP包是一项重要的技术,它允许程序在运行时根据需求加载外部库,而不是在编译时静态地链接。这种技术对于实现插件化、模块化系统,或者处理频繁更新的组件非常有用。下面将详细讲解如何...

    restclient-ui-3.2.2-jar-with-dependencies

    "restclient-ui-3.2.2-jar-with-dependencies" 是这个工具的一个特定版本,该版本包含了所有必要的依赖项,使得用户可以直接运行而无需额外安装其他库。这个版本号表明它是RESTClient的3.2.2迭代,且“jar-with-...

    android动态加载jar

    在Android开发中,动态加载JAR(Java Archive)文件是一种常见的技术,它允许应用程序在运行时加载和执行不在原始APK文件中的代码。这种技术有多种应用场景,例如更新功能、热修复、插件化框架等。下面将详细介绍...

    ksoap2-android-assembly-2.6.5-jar-with-dependencies.jar

    ksoap2-android-assembly-2.6.5-jar-with-dependencies.jar 要是需要最新的,下载地址: http://code.google.com/p/ksoap2-android/

    springboot+java类热加载

    在热加载场景下,JarinJAR使得在运行时能够动态替换内部的JAR,达到更新代码的目的。然而,JarinJAR并不直接支持热加载,需要配合类加载器的定制工作。 **动态编译**:在热加载过程中,可能会涉及到对源代码的动态...

    在可执行jar中载入第三方jar的几个解决方法

    这个问题通常发生在使用`Class.forName()`或`ClassLoader.getSystemClassLoader().loadClass()`尝试动态加载第三方JAR中的类时。 Java虚拟机(JVM)的类加载机制是导致此问题的关键。自JDK 1.2以来,JVM采用委托...

    Spring bean 动态注册,jar包热替换

    Spring bean 一般通过配置文件和注解进行加载,如果要实现jar或class...测试示例中是spring boot 的部分代码,动态加载的内容为接口实现类,且初始化时加载本地的实现类,动态加载后改为非程序加载目录中的jar实现类。

    android动态加载jar文件

    在Android开发中,有时我们需要实现动态加载功能,例如在运行时添加或更新功能模块,而无需重新编译和发布整个应用程序。这就是动态加载jar文件的作用。动态加载不仅可以提高应用程序的灵活性,还可以降低更新成本,...

    agent-jar-2.2.1.jar.zip

    `agent-jar-2.2.1.jar`正是这样一个代理库,它可能是为了方便在运行时对Java应用进行监控、性能分析或者增强功能而设计的。 `agent-jar-2.2.1.jar`的版本号为2.2.1,这表明它是经过了多次迭代和改进的稳定版本。...

    coherence.jar-coherence-work.jar-tangosol.jar-

    标题中的"coherence.jar-coherence-work.jar-tangosol.jar-"揭示了这是一组与Oracle Coherence相关的Java库文件。Coherence是Oracle公司提供的一种分布式数据管理解决方案,它主要用于实现高性能的数据缓存、数据...

    安卓插件机制相关-android动态加载插件dex后的jar以方便功能扩展.rar

    在Android系统中,插件化开发是一种常见的技术,它允许应用程序在运行时动态加载和执行新的功能模块,而无需重新编译或安装整个应用。这种技术对于大型应用或需要频繁更新功能的应用尤其有价值,因为它降低了维护...

    javax.servlet jar包---解决找不到javax.servlet.*等问题

    当你遇到“找不到javax.servlet.*”这样的错误时,通常是因为你的项目缺少了这个库,所以需要引入`javax.servlet.jar`来解决问题。 1. **Java Servlet简介** Java Servlet是Java平台上的一个标准,用于扩展服务器...

    dex2jar-2.1最新版

    总的来说,dex2jar-2.1是Android逆向工程中的一个重要工具,它的出现解决了旧版本在处理特定Dex文件时的局限性,提高了开发者和安全研究人员的工作效率。了解并熟练掌握它的使用方法,能帮助我们更好地探索和理解...

    动态加载Apk、Jar

    动态加载Apk主要应用于插件化开发,允许程序在运行时添加或更新功能模块。以下是一些关键步骤: 1. **创建自定义ClassLoader**:你需要继承dalvik.system.DexClassLoader或者dalvik.system.PathClassLoader,重写其...

    Spring-Boot插件式开发框架,为动态扩展系统而生的插件开发框架

    SpringBoot插件式开发框架是基于SpringBoot框架构建的一种创新性开发模式,旨在解决系统动态扩展和模块化管理的问题。这种框架充分利用了SpringBoot的简洁、高效特性,为开发者提供了快速构建可插拔功能的能力。下面...

    android 动态加载jar代码

    在Android开发中,动态加载jar代码是一种常见的技术,它允许应用程序在运行时加载新的功能或者更新已有代码,而无需重新安装整个应用。这种方式可以提高应用的灵活性和可维护性,尤其是在处理大型应用或需要频繁更新...

Global site tag (gtag.js) - Google Analytics