Flink plugin机制,结合SPI和自定义ClassLoader实现,允许冲突jar包并存,不用再修改代码等方式来统一class版本。

    下面代码模拟plugin的实现流程

    1. public interface IShout {
    2. void shout();
    3. boolean valid(String config);
    4. }
    5. public class Cat implements IShout {
    6. @Override
    7. public void shout() {
    8. System.out.println(this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile());
    9. System.out.println("miao miao");
    10. }
    11. @Override
    12. public boolean valid(String config) {
    13. return config.equalsIgnoreCase("cat");
    14. }
    15. }
    16. public class Dog implements IShout {
    17. @Override
    18. public void shout() {
    19. System.out.println(this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile());
    20. System.out.println("wang wang");
    21. }
    22. @Override
    23. public boolean valid(String config) {
    24. return config.equalsIgnoreCase("dog");
    25. }
    26. }
    27. public class MyClassLoader extends URLClassLoader {
    28. public MyClassLoader(URL[] urls) {
    29. super(urls);
    30. }
    31. @Override
    32. protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
    33. synchronized (getClassLoadingLock(name)) {
    34. Class<?> c = findLoadedClass(name);
    35. if (c == null) {
    36. try {
    37. //优先从当前路径下加载class
    38. c = findClass(name);
    39. } catch (ClassNotFoundException e) {
    40. c=getParent().loadClass(name);
    41. }
    42. }
    43. if (resolve) {
    44. resolveClass(c);
    45. }
    46. return c;
    47. }
    48. }
    49. }
    50. public class SPIMain {
    51. public static void main(String[] args) throws IOException {
    52. Path path = Files.createTempDirectory(Paths.get("c:/workspace/tmp"),"spi");
    53. // path.toFile().deleteOnExit();
    54. String catPath = Cat.class.getCanonicalName().replace(".", "/") + ".class";
    55. File file = path.resolve(catPath).toFile();
    56. file.getParentFile().mkdirs();
    57. Files.copy(SPIMain.class.getClassLoader().getResourceAsStream(catPath), file.toPath());
    58. ClassLoader subModuleClassLoader = new MyClassLoader(new URL[]{path.toUri().toURL()});
    59. ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class,subModuleClassLoader);
    60. String config="cat";
    61. IShout shout = null;
    62. for (IShout s : shouts) {
    63. s.shout();
    64. if(s.valid(config)){
    65. shout = s;
    66. break;
    67. }
    68. }
    69. shout.shout();
    70. IShout cat = new Cat();
    71. cat.shout();
    72. }
    73. }

    程序输出:

    1. /C:/workspace/github/JavaTest/java-test/target/classes/
    2. wang wang
    3. /c:/workspace/tmp/spi4806402692415880585/
    4. miao miao
    5. /c:/workspace/tmp/spi4806402692415880585/
    6. miao miao
    7. /C:/workspace/github/JavaTest/java-test/target/classes/
    8. miao miao