[Cao Gong's essay] talk about the contract between Maven framework and plug-ins

Cao Gong code shift 2021-09-15 10:02:24

say something Maven Contract between framework and plug-in


Maven The framework is like various platforms in the company now , Stipulate some contracts , Then try to pull the business side , Let's do ecological Co Construction on this platform .Maven In the same way , In fact, it is a framework for plug-in execution ,Maven At first, I didn't know who would contribute the plug-in , If you write all kinds of plug-ins , For the platform side , It could be a disaster , therefore , The platform side is responsible for setting standards , To write plug-ins on my platform , What must be done .

Maven A contract is made for the plug-in , This contract , It's through api jar Package mode . Every time I release Maven The new version , Accompanied by , There will be one api jar package .

If someone wants to be based on this version api jar Package to develop plug-ins , You need to introduce this plug-in into your plug-in project . And then according to api jar Contract interface in package , To implement their own plug-in logic .

such as ,maven clean In the engineering code of the plug-in , It depends on api jar package . as follows :

api jar What does the contract interface look like in the package ?

public interface Mojo {
void execute() throws MojoExecutionException, MojoFailureException;

The core method is this , As long as you implement this interface, you're done .

As a framework , How to call this plug-in ? In short , Namely :

1、 Find the implementation class of the plug-in jar package , Then construct a class loader for the plug-in , To load this jar package , Then find the corresponding class that implements the contract interface , Like here CleanMojo

2、 Loaded this CleanMojo Of class after , Of course, reflection generates objects , Then cast to the contract interface , Then the contract interface is called . such as :

Class cleanMojoClass = The class loader of the plug-in loads the class of the plug-in jar package ;
Mojo cleanMojo = (Mojo)cleanMojoClass.newInstance();

Only this and nothing more , Our theoretical knowledge is enough , Can we show the code 了 ?

The engineering practice

We will simulate the above process ,

  1. To build a Maven module, Used to store plug-ins api Contract interface ;
  2. To build a Maven module, introduce api, Implement plug-ins api, such , Even if our plug-in is implemented ;
  3. Next , Compile these two projects , hold jar Package installation to local warehouse ;
  4. Another new project , simulation Maven Framework to load plug-ins , And execute the plug-in .

plug-in unit api engineering

Direct use maven Of archetype Medium quickstart, Create a new one module, It's very simple , Just an interface :

And then execute mvn install, Install to local warehouse .

Plug in implementation project

stay pom in , We will introduce api.


The code is also simple , Just an implementation class .

And then execute mvn install, Install to local warehouse .

Main works , Simulate the framework to call the plug-in

The main project is to simulate our Maven frame , Because we call the plug-in , It must have been through api The way , therefore ,pom It must introduce api Of .


Next , We wrote a test class :

public static void main( String[] args ) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
// 1.1 It's about 
URL urlForPluginApi = new URL("file:/C:\\Users\\Administrator\\.m2\\repository\\org\\example\\my-plugin-api\\1.0-SNAPSHOT\\my-plugin-api-1.0-SNAPSHOT.jar");
URL urlForPluginImpl = new URL("file:/C:\\Users\\Administrator\\.m2\\repository\\org\\example\\my-plugin-implementation\\1.0-SNAPSHOT\\my-plugin-implementation-1.0-SNAPSHOT.jar");
URL[] urls = {urlForPluginApi, urlForPluginImpl};
// 1.2
URLClassLoader urlClassLoader = new URLClassLoader(urls,ClassLoader.getSystemClassLoader()){
public Class<?> loadClass(String name) throws ClassNotFoundException {
// Guarantee : When looking for class , Give priority to finding your own classpath, Can't find , And give it to parent classloader
Class<?> clazz = findClass(name);
return clazz;
}catch (ClassNotFoundException exception ){
return super.loadClass(name);
// 1.3
Class<?> implClazzByPluginClassloader = urlClassLoader.loadClass("org.example.MyMojoImplementation");
// 1.4 
MojoInterface mojoInterface = (MojoInterface) implClazzByPluginClassloader.newInstance();
// 1.5 
System.out.println( "Hello World!" );

Let me briefly explain the above code first :

  • 1.1 It's about , Constructed two url, Point to two files in my local warehouse , That is to say api.jar The implementation corresponding to the plug-in jar

  • 1.2 It's about , Use 1.1 Medium url, Constructed a classloader, This classloader Of parent classloader, What we pass is , Systematic AppClassloader.

    meanwhile , We rewritten this classloader act , The rewritten behavior is as follows : When you encounter a class to load , Give priority to loading , That is, I will go to my two url Inside looking for , See if you can find , If you can't find it , Will enter the exception , After the exception is caught by us , hand parent classloader To load the ;

  • 1.3 It's about , We use the new classloader, To load the implementation class of the plug-in

  • 1.4 It's about , utilize 1.3 Of the implementation class loaded at class, Reflection generates objects , Forced to MojoInterface Interface object

  • 1.5 It's about , Execute plug-in logic in a polymorphic manner

You might as well think about , Everyone feels , What is the final implementation result ? our “hello world” Can you print it out ?

This code , We uploaded gitee, You can pull it down and see .


Let me show you , Execution results :

Let's see. , Is this like a word , In my plug-in code , It implements the interface , Why can't we transform upward ?:

public class MyMojoImplementation implements MojoInterface{
public void execute() {
System.out.println("implementation execute business logic");

This ... How to put it? ... Let me explain to you , We load MyMojoImplementation when , Find this class , It also implements the interface MojoInterface, that , This interface class needs to be loaded , Because we classloader Has been rewritten ( Priority is given to loading by yourself ), therefore , In the end ,MojoInterface It's just like MyMojoImplementation equally , Are loaded by the plug-in class loader .

In the end , In the upward transformation , There will be the following situation , The two sides don't match , It's a mistake .

 MojoInterface( This class in the framework , It is loaded by the class loader of the framework ) mojoInterface = (MojoInterface) implClazzByPluginClassloader.newInstance();( The interface implemented by this implementation class , Is loaded by the plug-in class loader )

After class questions

We changed the code , Changed to the following , result , You can run through our hello world 了 . Why is this ?

I'm daily , Shenzhen Tencent employee , The back end of repeated horizontal jumps between Chengdu and Shenzhen java A program ape . Previously in Shenzhen 3 year , Later I went to Chengdu 4 year , Now I come to Shenzhen , Also started writing the front end , If you need to push inside, you can come to me . For front-line coding practice 、 The Internet 、 database 、 High concurrency, etc .

Also welcome to add me , Pull into the technology group to communicate ; Tencent can also find me .

This article by the blog one article many sends the platform OpenWrite Release !

Please bring the original link to reprint ,thank
Similar articles