简体   繁体   English

从外部库动态加载Java函数

[英]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. 我正在做一个工程设计不太好的大型Java项目,实际上我们有两个主要的开发分支。 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). 一个分支A是第二个分支B的子集,具有第二个分支B的所有功能,但没有在用户操作上集成安全检查(它们只是标记在文件上的哈希,用于标记哪个用户执行了什么操作)。

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. 由于开发是在A分支上完成的,因此,只要完成了一个错误修复,我就必须手动合并B分支上的所有工作。

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? 现在,作为Java初学者,我的问题是以下问题:是否可以在外部库中“外部化”某些类的某些功能(即实现安全性检查的所有功能),以便代码执行每当jar文件中存在该库时,这些函数就会执行这些函数,否则会执行普通的“无安全性”函数?

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. 只要不存在该库,该代码就必须执行f1()和g1(),但是如果存在该库,则执行它们的加星标版本。

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. 理想情况下,鉴于上述问题,我只想在一组Java文件中剪切并粘贴“与安全相关的”函数,并将其编译为库,然后在需要时手动对这些函数进行更改-不经常修改。

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. @ RH6,您的要求当然可以,但在上述情况下可能并不容易。 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). 您可以探索的一种途径是使用AspectJ并编织建议(围绕建议)。 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. 在此建议书中,您可以检查是否存在所需的JAR,如果存在,则可以使用自定义类加载器(尽管如果JAR位于类路径中,则没有必要)可以加载/创建所需类的对象,并且执行f1 *()/ g1 *()方法。 If the JAR is not present, proceed to execute the f1()/g1() method. 如果不存在JAR,则继续执行f1()/ g1()方法。

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. 使B扩展A(并将其命名为SecuredA),并覆盖f1()和g1()以添加所需的安全检查。

  • Create a SecurityManager interface that is called inside of f1() and g1(). 创建一个在f1()和g1()内部调用的SecurityManager接口。 You then have to create 2 implementations: one that does nothing (= A) and one that does security related functions (= B). 然后,您必须创建2个实现:一个不执行任何操作(= A),另一个不执行与安全相关的功能(= B)。 Then you will just have to inject/use the correct SecurityManager depending of the current case. 然后,您仅需要根据当前情况注入/使用正确的SecurityManager。

There are various design principles to solve this. 有多种设计原则可以解决此问题。

For example: IoC (inversion of control). 例如:IoC(控制反转)。

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 . 在软件工程中,控制反转(IoC)描述了一种设计,其中计算机程序的自定义编写部分从通用的可重用库接收控制流 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 . 据我所知,最受欢迎的框架是Spring During the instantiation of your objects you start using a factory method. 在实例化对象期间,您开始使用工厂方法。 This factory method will check an XML file for possible overruling. 此工厂方法将检查XML文件中是否存在否决。 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. 或者,如果您不喜欢Spring依赖项。 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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