-

   rss_rss_hh_new

 - e-mail

 

 -

 LiveInternet.ru:
: 17.03.2011
:
:
: 51

:


[ ] Java- 2017

, 30 2017 . 16:07 +
CyberSoft 16:07

Java- 2017

Java- 2017


,


, , Java 9.


( ), .
, :


  • Java 9
  • Elasticsearch
  • Maven

, , .


: Elasticsearch . , . Elasticsearch, rolling upgrade. - (, - ) reindex . : , . 2 .


Java API , , Elasticsearch. , 5- Rest Client, ( API Elasticsearch), 2- .


: 2- Elasticsearch 1.7 2.4. , ( OSGi).


. Maven- :


+---pom.xml
+---core/
|   +---pom.xml
|   +---src/
|       +---main/
|       |   +---java/
|       |   |   +---elasticsearch/
|       |   |       +---client/
|       |   |           +---SearchClient.java
|       |   |           +---Searcher.java
|       |   +---resources/
|       +---test/
|           +---java/
+---es-v1/
|   +---pom.xml
|   +---src/
|       +---main/
|       |   +---java/
|       |   |   +---elasticsearch/
|       |   |       +---client/
|       |   |           +---v1/
|       |   |               +---SearchClientImpl.java
|       |   +---resources/
|       +---test/
|           +---java/
+---es-v2/
    +---pom.xml
    +---src/
        +---main/
        |   +---java/
        |   |   +---elasticsearch/
        |   |       +---client/
        |   |           +---v2/
        |   |               +---SearchClientImpl.java
        |   +---resources/
        +---test/
            +---java/

, , :


  • core ;
  • ( ) Elasticsearch ;
  • es-v1 Elasticsearch 1.7.5;
  • es-v2 Elasticsearch 2.4.5.

core Searcher, "" es-v1 es-v2:


public class Searcher {
    public static void main(String[] args) throws Exception {
        List clients = Arrays.asList(
                getClient("1"),
                getClient("2")
        );
        for (SearchClient client : clients) {
            System.out.printf("Client for version: %s%n", client.getVersion());
            Map doc = client.search("test");
            System.out.println("Found doc:");
            System.out.println(doc);
            System.out.println();
        }
        clients.forEach(SearchClient::close);
    }

    private static SearchClient getClient(String desiredVersion) throws Exception {
        return null; // . 
    }
}

: Elasticsearch, , .


, :


public class SearchClientImpl implements SearchClient {
    private final Settings settings = ImmutableSettings.builder()
            .put("cluster.name", "es1")
            .put("node.name", "es1")
            .build();

    private final Client searchClient = new TransportClient(settings)
            .addTransportAddress(getAddress());

    private InetSocketTransportAddress getAddress() {
        return new InetSocketTransportAddress("127.0.0.1", 9301);
    }

    @Override
    public String getVersion() {
        return Version.CURRENT.number();
    }

    @Override
    public Map search(String term) {
        SearchResponse response = searchClient.prepareSearch("*")
                .setQuery(QueryBuilders.termQuery("field", term))
                .execute()
                .actionGet();
        if (response.getHits().getTotalHits() > 0) {
            return response.getHits().getAt(0).getSource();
        } else {
            return null;
        }
    }

    @Override
    public void close() {
        searchClient.close();
    }
}

: , Elasticsearch, field (*), , .


, SearchClient Searcher#getClient .


, Class.forName?


Java, , ClassLoader. , , :


private static SearchClient getClient(String desiredVersion) throws Exception {
    String className = String.format("elasticsearch.client.v%s.SearchClientImpl", desiredVersion);
    return (SearchClient) Class.forName(className).newInstance();
}

, , , :


Exception in thread "main" java.lang.IncompatibleClassChangeError: Implementing class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at elasticsearch.client.Searcher.getClient(Searcher.java:28)
    at elasticsearch.client.Searcher.main(Searcher.java:10)

ClassNotFoundException ...


URLClassLoader jar- , . - , class-path elasticsearch-2.4.5.jar elasticsearch-1.7.5.jar, ( ) 2.4.5. Searcher Elasticsearch 1.7.5 (getClient("1")), URLClassLoader ...


( ) , jar hell ( class-path hell).


ClassLoader


, . URLClassLoader es-v* jar-:


private static SearchClient getClient(String desiredVersion) throws Exception {
    String className = String.format("elasticsearch.client.v%s.SearchClientImpl", desiredVersion);
    Path moduleDependencies = Paths.get("modules", "es-v" + desiredVersion);
    URL[] jars = Files.list(moduleDependencies)
            .map(Path::toUri)
            .map(Searcher::toURL)
            .toArray(URL[]::new);
    ClassLoader classLoader = new URLClassLoader(jars); // parent = app's class loader
    return (SearchClient) classLoader.loadClass(className).newInstance();
}

modules/es-v*/, maven-dependency-plugin es-v1 es-v2.


:


mvn package

:


. 29, 2017 10:37:08  org.elasticsearch.plugins.PluginsService 
INFO: [es1] loaded [], sites []
. 29, 2017 10:37:12  org.elasticsearch.plugins.PluginsService 
INFO: [es2] modules [], plugins [], sites []
Client for version: 1.7.5
Found doc:
{field=test 1}

Client for version: 2.4.5
Found doc:
{field=test 2}

!


(1.7 JRE 9)

JvmInfo, Elasticsearch 1.7.


, core - Elasticsearch. - :


  1. Invoke findLoadedClass(String) to check if the class has already been loaded.
  2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
  3. Invoke the findClass(String) method to find the class.

Elasticsearch core, es-v*. , : , , 2 3. es-v*, core.


URLClassLoader, , , ParentLastURLClassLoader:


public class ParentLastURLClassLoader extends URLClassLoader {
    ...
}

loadClass(String,boolean), ClassLoader :


@Override
protected Class c = findLoadedClass(name);
        if (c == null) {
            try {
                if (getParent() != null) {
                    c = getParent().loadClass(name);
                }
            } catch (ClassNotFoundException e) {
            }

            if (c == null) {
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

getParent().loadClass(String) findClass(String) :


@Override
protected Class c = findLoadedClass(name);
        if (c == null) {
            try {
                c = findClass(name);
            } catch (ClassNotFoundException ignored) {
            }

            if (c == null) {
                c = getParent().loadClass(name);
                if(c == null) {
                    throw new ClassNotFoundException(name);
                }
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

, ClassNotFoundException, .


, , URLClassLoader getClient(String):


ClassLoader classLoader = new URLClassLoader(jars);

ParentLastURLClassLoader:


ClassLoader classLoader = new ParentLastClassLoader(jars);

, :


. 29, 2017 10:42:41  org.elasticsearch.plugins.PluginsService 
INFO: [es1] loaded [], sites []
. 29, 2017 10:42:44  org.elasticsearch.plugins.PluginsService 
INFO: [es2] modules [], plugins [], sites []
Client for version: 1.7.5
Found doc:
{field=test 1}

Client for version: 2.4.5
Found doc:
{field=test 2}

ServiceLoader API


Java 6 java.util.ServiceLoader, / . :


private static SearchClient getClient(String desiredVersion) throws Exception {
    Path moduleDependencies = Paths.get("modules", "es-v" + desiredVersion);
    URL[] jars = Files.list(moduleDependencies)
            .map(Path::toUri)
            .map(Searcher::toURL)
            .toArray(URL[]::new);
    ServiceLoader serviceLoader = ServiceLoader.load(SearchClient.class, new URLClassLoader(jars));
    return serviceLoader.iterator().next();
}

:


  • jar-,
  • ,
  • , .

ServiceLoader , META-INF/services:


+---es-v1/
|   +---src/
|       +---main/
|           +---resources/
|               +---META-INF/
|                   +---services/
|                       +---elasticsearch.client.spi.SearchClient
+---es-v2/
    +---src/
        +---main/
            +---resources/
                +---META-INF/
                    +---services/
                        +---elasticsearch.client.spi.SearchClient

, , : SearchClientImpl .
es-v1 :


elasticsearch.client.v1.SearchClientImpl

es-v2:


elasticsearch.client.v2.SearchClientImpl

maven-dependency-plugin es-v* modules/es-v*/. :


mvn clean package

:


. 29, 2017 10:50:17  org.elasticsearch.plugins.PluginsService 
INFO: [es1] loaded [], sites []
. 29, 2017 10:50:20  org.elasticsearch.plugins.PluginsService 
INFO: [es2] modules [], plugins [], sites []
Client for version: 1.7.5
Found doc:
{field=test 1}

Client for version: 2.4.5
Found doc:
{field=test 2}

, .


SearchClient spi :


core:  bootstrap -> system
spi:   bootstrap -> spi
es-v1: bootstrap -> spi -> es-v1
es-v2: bootstrap -> spi -> es-v2

..


  1. spi ( parent null bootstrap-),
  2. spi ( SearchClient),
  3. es-v*, spi,
  4. ...
  5. PROFIT!

OSGi


OSGi ( ?). Apache Felix Eclipse Equinox, , (?) . , . , ( , - ).


, .. Java 9 , .


Java?


9- , . , !


Hint: , , JDK 9, .


( , IntelliJ IDEA class-path module-path, module-path).



, , ( , ).


, , . boot, --module-path , , ( java.base ). .


( ). , . , .


. ( module-info.java) , . , , , . ServiceLoader API .


( , ):


  • - module-info.class jar- ( jar),
  • , module-path; , class-path.

, :


  1. boot- core. es-v*, - elasticsearch.shaded.
  2. Searcher es-v* , ServiceLoader API.

?...


Package Hell


( ).


, , - API Functions. Helpers . :


com.foo.bar
    public class Functions
    class Helpers

, :


com.foo.baz
    public class Additional

Helpers. , - :


com.foo.baz
    public class Additional
com.foo.bar
    public class AccessorToHelpers

(split package) . ? class-path , . , : jar- ( fat jar uber jar), - module-path , class-path. all-in-one jar.


Elasticsearch

Elasticsearch package-private / Lucene. , uber jar elasticsaerch-shaded .


Elasticsearch 1.7


Maven-, : pom.xml , 8-.


- , v1.7.5 :


  • maven-shade-plugin, uberjar , :


, :



  • Groovy ( - ), ( , JUL ), :


    org.codehaus.groovy:groovy-all
    org.slf4j:*
    log4j:*

  • ServiceLoader/Reflection API:


  • - ServiceLoader API :


    

  • pom.xml , UnsupportedOperationException, java.lang.management.RuntimeMXBean#getBootClassPath. JvmInfo:

info.bootClassPath = runtimeMXBean.getBootClassPath();

"":


if (runtimeMXBean.isBootClassPathSupported()) {
    info.bootClassPath = runtimeMXBean.getBootClassPath();
} else {
    info.bootClassPath = "";
}

.


, jar:


$ mvn package

elasticsearch-1.7.5.jar target. , , elasticsearch-shaded:


$ mvn install:install-file \
> -Dfile=elasticsearch-1.7.5.jar \
> -DgroupId=org.elasticsearch \
> -DartifactId=elasticsearch-shaded \
> -Dversion=1.7.5 \
> -Dpackaging=jar \
> -DgeneratePom=true

Maven- es-v1:



    
        org.elasticsearch
        elasticsearch-shaded
        1.7.5
    
    ...

Elasticsearch 2.4


v2.4.5. 2- . , elasticsearch-2.4.5.jar core.


  • , :

$ mvn versions:set -DnewVersion=2.4.5

  • , shade- :

Shading and package relocation removed



Elasticsearch used to shade its dependencies and to relocate packages. We no longer use shading or relocation.
You might need to change your imports to the original package names:
  • com.google.common was org.elasticsearch.common
  • com.carrotsearch.hppc was org.elasticsearch.common.hppc
  • jsr166e was org.elasticsearch.common.util.concurrent.jsr166e
    ...

shade- core, - :



    org.apache.maven.plugins
    maven-shade-plugin
    
        
            package
            
                shade
            
        
    
    
        
            
        
        
            
                org.slf4j:*
                log4j:*
            
        
    

  • com.twitter:jsr166e ( sun.misc.Unsafe, 9- "") core:


com.twitter.jsr166e java.util.concurrent.atomic.


  • animal-sniffer-maven-plugin ( 7- jsr166e), :


, , es-v1, :


  • 2.4.5,
  • core:

$ mvn clean package -pl org.elasticsearch:parent,org.elasticsearch:elasticsearch -DskipTests=true


, , Java, Maven- Java-. (src/main/java) module-info.java .


core , , , :


//   - elasticsearch.client.core
module elasticsearch.client.core {
    // ,     ,
    //      
    exports elasticsearch.client.spi; 
    //    ,     SearchClient
    //    ServiceLoader'
    uses elasticsearch.client.spi.SearchClient;
}

es-v1 es-v2 :


  • elasticsearch.client.core, .. ,
  • Elasticsearch ,
  • , SearchClient.

es-v1:


//   - elasticsearch.client.v1
module elasticsearch.client.v1 {
    //  core  SearchClient
    requires elasticsearch.client.core;
    //  
    requires elasticsearch.shaded;
    //   core,       
    provides elasticsearch.client.spi.SearchClient with elasticsearch.client.v1.SearchClientImpl;
}

es-v2 , v2.


? ModuleLayer, . , es-v* modules/es-v*/, :


private static SearchClient getClient(String desiredVersion) throws Exception {
    Path modPath = Paths.get("modules", "es-v" + desiredVersion);
    ModuleFinder moduleFinder = ModuleFinder.of(modPath);
    ModuleLayer parent = ModuleLayer.boot();
    Configuration config = parent.configuration().resolve(moduleFinder, ModuleFinder.of(), Set.of("elasticsearch.client.v" + desiredVersion));
    ModuleLayer moduleLayer = parent.defineModulesWithOneLoader(config, Thread.currentThread().getContextClassLoader());
    ServiceLoader serviceLoader = ServiceLoader.load(moduleLayer, SearchClient.class);
    Optional searchClient = serviceLoader.findFirst();
    if (searchClient.isPresent()) {
        return searchClient.get();
    }
    throw new Exception("Module 'elasticsearch.client.v" + desiredVersion + "' not found on " + modPath);
}

ModuleLayer#defineModulesWithManyLoaders , es-v* .


, . maven-compiler-plugin , 3.7.0:



    org.apache.maven.plugins
    maven-compiler-plugin
    3.7.0

Java 9 :



    1.9
    1.9

maven-dependency-plugin, :


$ mvn clean package

, :


. 29, 2017 10:59:01  org.elasticsearch.plugins.PluginsService 
INFO: [es1] loaded [], sites []
. 29, 2017 10:59:04  org.elasticsearch.plugins.PluginsService 
INFO: [es2] modules [], plugins [], sites []
Client for version: 1.7.5
Found doc:
{field=test 1}

Client for version: 2.4.5
Found doc:
{field=test 2}

, , , Java 8 .



, /. :


  • ClassLoader , ( ),
  • ServiceLoader API META-INF/services,
  • , ()
  • Java 9 .

P.S. Java 9!

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/339026/

:  

: [1] []
 

:
: 

: ( )

:

  URL