Runtime code generation and compilation

2019-04-12 12:15发布

Say I have this code that uses some input (e.g. a URL path) to determine which method to run, via reflection:

// init
map.put("/users/*", "viewUser");
map.put("/users", "userIndex");

// later
String methodName = map.get(path);
Method m = Handler.class.getMethod(methodName, ...);
m.invoke(handler, ...);

This uses reflection so the performance can be improved. It could be done like this:

// init
map.put("/users/*", new Runnable() { public void run() { handler.viewUser(); } });
map.put("/users", new Runnable() { public void run() { handler.userIndex(); } });

// later
Runnable action = map.get(path);
action.run();

But manually creating all those Runnables like that has its own issues. I'm wondering, can I generate them at runtime? So I'd have an input map as in the first example, and would dynamically create the map of the second example. Sure, generating it is just a matter of building a string, but what about compiling and loading it?

Note: I know the performance increase is so little it's a perfect example of premature optimization. This is therefore an academic question, I'm interested in runtime generation and compilation of code.

4条回答
女痞
2楼-- · 2019-04-12 12:37

I think you can achieve this with the code found here. It is some time ago I tried this, and I'm not sure anymore where I found the code I was using, but it seems that this is the same.

Basically, you use the 1.6 Compiler API, but use an "untraditional" way to find source files and write class files: The Compiler takes an Iterable<JavaFileObject>, where you plug in your memory-backed implementation, and a JavaFileManager that handles writing class files, where you hold the binary compiler output in memory.

Now that your code was compiled, you only need a custom ClassLoader that can read from your in-memory byte code and load the class with the right FQCN etc.

And, luckily, all that seems to be ready ;)

查看更多
▲ chillily
3楼-- · 2019-04-12 12:40

The only ways to generate code dynamically are to either generate source code and compile it or to generate byte code and load it at runtime. There are templating solutiions out there for the former, and bytecode manipulation libraries for the latter. Without a real case and some profiling I don't think you can really say which will be better. From a maintenance point of view I think reflection is the best option when available.

查看更多
淡お忘
4楼-- · 2019-04-12 12:40

Well, you could write code to a .java file, compile it with javac (how to do that) and load it into Java using Reflection.

But maybe, as a trade-off, you could also fetch the Method objects during initialization - so you would just have to call the invoke() method for every request.

查看更多
霸刀☆藐视天下
5楼-- · 2019-04-12 12:46

Actually, the reflection engine will generate similar invocation stubs internally, if you invoke the same methods over and over again. (Just use the same Method objects instead of recreating them again and again.)

查看更多
登录 后发表回答