简体   繁体   中英

Dynamically load Java functions from external library

I am working on a big Java project not so well engineered, and we actually have two main development branches. One branch, A, is a subset of the second, B, having all the functionalities of the latter but no security checks integrated on the user operations (they are just hashes on files that mark which user did what).

Since the development is done on the A branch, I have to manually merge all the work on branch B whenever a bugfix is done.

The codebase is huge and it has interdependencies all around, but rewriting it is out of discussion (founding problems, as usual). Moreover, the whole architecture is so complex that any structural changes can have strange side-effects. (I realize that this is a programmer's nightmare!).

Now, my question as a Java beginner is the following one: would it be possible to "externalize" some functions of some classes -- that is, all the functions that implement security checks -- in an external library, so that the code executes these functions whenever the library is present in the jar file, and executes the plain "no-security" functions otherwise?

Just to be clear, here's a small schematic of what I would like to do:

--- branch A ---
+ class ONE
  f1()
  f2()
+ class TWO
  g1()
  g2()

--- branch B ---
+ class ONE
  f1*()
  f2()
+ class TWO
  g1*()
  g2()

The code has to execute f1() and g1() whenever the library is not present, but executes their starred version if the library is there.

Ideally, given the problems above mentioned, I would like to just cut&paste the "security-related" functions in a set of java files, and compile them as a library, and I would perform the changes to these functions manually when needed -- they are not often modified.

Is there otherwise a way to deal with this situation that prevents these problems?

Thanks a lot in advance!

@RH6, what you are asking is certainly possible but may not be very easy in the situation you described above. However, as detailed above, the fundamental idea is to look for the presence/absence of the library in question and behave accordingly. This is more of a design matter and there are more than one approach, so right from the onset, you should be prepared to modify your design to incorporate this behaviour.

One avenue that you could explore is to use AspectJ and weave advices (around advice). In this advice body you could check if the required JAR is present or not, if it is present, you could use a custom class loader (though it is not necessary if the JAR is on classpath) load/create object of the required class and execute the f1*()/g1*() method. If the JAR is not present, proceed to execute the f1()/g1() method.

As you have observed, the above method is slightly less intrusive (requires build level intrusion into the existing code base) but it would require you to modify the build process as well as develop & maintain the advices.

I don't think you need to load functions dynamically. For example, you can either:

  • Make B extends A (and name it something like SecuredA) and overwrite f1() and g1() to add the required security checks.

  • Create a SecurityManager interface that is called inside of f1() and g1(). You then have to create 2 implementations: one that does nothing (= A) and one that does security related functions (= B). Then you will just have to inject/use the correct SecurityManager depending of the current case.

There are various design principles to solve this.

For example: IoC (inversion of control).

In software engineering, inversion of control (IoC) describes a design in which custom-written portions of a computer program receive the flow of control from a generic, reusable library . A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the reusable code that calls into the custom, or task-specific, code.

The most popular framework for this (as far as I know) is Spring . During the instantiation of your objects you start using a factory method. This factory method will check an XML file for possible overruling. Here is an example:

<?xml version="1.0" encoding="UTF-8"?>
 <beans ...>
   <bean id="myClass" class="package.my.MyClass" />
 </beans>

Alternatively if you don't like the Spring dependency. You can just create something yourself using some reflection:

Class defaultClass = package.my.MyClass.class;
String overruledClassName = System.getProperty(defaultClassName.getName + ".clazz");
Class clazz = (overruledClassName == null) ? defaultClass : Class.forName(overruledClassName);
Object createdObject = clazz.newInstance();

In combination with a property file that contains the following property:

package.my.MyClass.clazz = package.my.MyClassVersion2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM