问题
I want to have hot code swapping between project updates, but I haven't found any information about how to load .class files dynamically. More specifically, I want something like that:
- Make
lein uberjar, obtainsome-client-0.0.0-standalone.jar. - Run it with
java -jar some-client-0.0.0-standalone.jar. - Make changes to project. Obtain new program version,
some-client-0.0.1-standalone.jar, copy it tosome-client-0.0.0-standalone.jardirectory. - Client receive sequence of commands needed to update to new version.
- (optional) Updates resources. Resources from old jar are no longer used.
- (optional)
some-client-0.0.0-standalone.jarcan be deleted now.
回答1:
Plug-in framework approach
You've stated you want to have hot code swapping, but what you actually need is loosely coupled modules and ability to do resolve in run-time. Frankly speaking any plug-in framework may help, including mature OSGi (will be covered below).
Since you are doing some kind of PoC I suggest to review the following example:
- you have a meta application with some extension points (metaphor explanation) defined
- functionality to be upgraded or replaced will be implemented as a loosely coupled modules (plug-ins)
- meta application performs resolve by request or automatically in order to find updated "functionality" (according to defined extension points)
Having that define simlle upgrade scenario can be proposed:
- user uses an application
- user installs (copies) a JAR (other type of bundle) with new implementation of one or several extension points
- user triggers global system resolve or system scans for new updates or system performs resolve every tine user tries to access some piece of functionality
In such a way meta application will be able to provide a new or updated functionality without restart. So you can:
- try use some simple java plug-in framework (like, for example, Java Simple Plugin Framework. 5 minutes and it works. No XML. This approach seems to be a little bit ugly
- use dynamic nature of clojure, as was suggested here
You can also review and adopt Waterfront (Clojure based editor for Clojure) findings (it might be needed to enhance lifecycle management, etc)
- check the Modular composition/plugin architecture thread
- look through the code waterfront on SourceForge
In terms of implementation, Waterfront is based on the context pattern. It allows event handlers to communicate in a functional (side-effect free) manner. On top of this there is a plugin-loader mechanism which loads the plugins that are specified in Waterfront's configuration file. This means that functionality can be easily added or removed (extremely useful when debugging!).
OSGI approach
As was suggested OSGi seems to be a good way to solve your problem. Please also note OSGi is good, mature and provides a lot stuff out of the box, but it is also somewhat complex:
BTW, OSGi is a long-term goal for the clojure community. You can check Clojure Todo:
> better modularization for OSGi etc
> * names
> * no single namespace pool
> * namespaces found via classes, thus tracks classloader and modules
> * deal with import proxying a la Class.forName stack walk?
There are some solutions already available:
- clojure-osgi-utils
- clojure.osgi
Second project provides Producer-Consumer example using clojure and OSGi:
- producer service
- consumer service
Happy coding.
回答2:
For reloading at runtime strictly from jar files you may need to look into OSGi class loaders.
For Clojure code you could start nrepl in your client that listens on a local port and then when you want to reload the code you connect to that port and make a call to load-file
来源:https://stackoverflow.com/questions/15145721/clojure-hot-code-swapping-for-uberjars-classes