java 模块化

java9出了模块,作为一名主要用java的程序员,所以要提前学习,保持一颗好学的心.

1.创建模块

 

 

 新建java project com.horstmann.greet,eclipse新版会提示是否要创建模块,

 

 

 

,如果在此输入模块名字的话就会生成一个module-info.java类,是模块的描述信息类,主要包含以下内容

 

 

 

 到此一个模块就创建好了,如果没有在创建的时候输入模块,也可以自己新建module-info.java类来创建模块.

2. 暴露模块

我们创建一个接口

package com.horstmann.greet;

public interface Greeter {
    static Greeter newInstance() {
        return new com.horstmann.greet.internal.GreeterImpl();
    }
    String greet(String subject);
    
}

和它的实现类

package com.horstmann.greet.internal;

import com.horstmann.greet.Greeter;

public class GreeterImpl implements Greeter {

    @Override
    public String greet(String subject) {
        // TODO Auto-generated method stub
        return "Hello, " + subject + "!";
    }

}

目录结构如下

 

 

 一般来说都会暴露模块的接口,而不是实现类,类似于es6中的模块,我们直接exports包即可

module com.horstmann.greet {
    exports com.horstmann.greet;
}

这样其他模块就可以引用即可

3.引用暴露的模块

新建模块 v2ch09.exportedpkg

 

 

 创建类HelloWorld

在eclipse中右键属性引入刚刚的模块

 

 

 编辑module-info.java即可引入导出的类

module v2ch09.exportedpkg {
    requires com.horstmann.greet;
    requires hellomod.test;
}
public class HelloWorld {
    public static void main(String[] args) {
        Greeter greeter = Greeter.newInstance();
        System.out.println(greeter.greet("Modular World"));
    }
}

 

直接运行helloworld类,即可看到结果

 

 

通过exports和requires,我们可以在module-info中对模块的权限进行控制,需要哪些模块,不需要哪些模块,非常方便. 

 

4.模块和反射

模块不能通过反射访问私有属性比如:

package hellomod.test;

public class ReflectTest {
    private Integer name;

    public ReflectTest(Integer name) {
        super();
        this.name = name;
    }
}

我在另一个模块通过反射访问name,会报错

ReflectTest reflectTest = new ReflectTest(123);
        Field field = reflectTest.getClass().getDeclaredField("name");
        System.out.println(field.getInt(reflectTest));

 

 

 解决: 在要访问的模块中添加open关键词即可

open module hellomod.test{
    exports hellomod.test;
}

如图 我们在module 前面添加 open即可

或者添加exports和opens关键词

module hellomod.test{
     exports hellomod.test;
     opens hellomod.test;
}

即可开放反射访问权限

 

 

 5.自动模块和不具名模块

自动模块: 就是把jar文件放到模块路径上的模块. 为了改造以前的方式成模块,jar文件直接可以放到模块路径上成为一个新的模块

所有包都导出,包含其他所有模块

不具名模块: 不在模块路径中的类组成的模块.

可以访问其他模块,但是不能被其他模块访问

 

6.依赖的传递和静态模块

如果想要传递依赖,使用 transitive关键字即可

module v2ch09.exportedpkg {
    requires transitive com.horstmann.greet;
    requires hellomod.test;
}

这样,别的模块引入v2ch09.exportedpkg这个模块以后,也会自动引入com.horstmann.greet这个模块

静态模块是 requires static,声明一个模块必须在编译时出现,运行时可选,也就是写代码的时候可以存在,但是运行以后能不能用就另外当回事了.

7.限定导出和开放

to关键词可以做到让模块给指定的模块开放,比如:

module hellomod.test{
     exports hellomod.test;
     opens hellomod.test to com.horstmann.greet;
}

hellomod.test,只有com.horstmann.greet模块才可以使用反射,或者在exports后面加入也可以.

8.服务加载 ServiceLoader

ServiceLoader提供了一个机制,用于将服务和实现匹配,在模块中,可以用 provices和uses实现.

比如:

一个接口

public interface GreeterService {
    void hello();
}

有两个实现类

public class FrenchGreeter implements GreeterService{

    @Override
    public void hello() {
        System.out.println("FrenchGreeter Hello");
    }

}
public class GermanGreeterFactory implements GreeterService {

    @Override
    public void hello() {
        System.out.println("GermanGreeter Hello");
    }

}

 

module com.horstmann.greetsvc {
    exports com.horstmann.greetsvc;
    provides com.horstmann.greetsvc.GreeterService with 
        com.horstmann.greetsvc.internal.FrenchGreeter,
        com.horstmann.greetsvc.internal.GermanGreeterFactory;
}

在module中我们可以这样声明, provides 提供接口,with后面跟着实现类,

在另一个模块中我们可以这样使用

    requires com.horstmann.greetsvc;
    uses com.horstmann.greetsvc.GreeterService;

代码中这样写

        ServiceLoader<GreeterService> greeterLoader = ServiceLoader.load(GreeterService.class);
        GreeterService user = null;
        for(GreeterService greetService : greeterLoader) {
            user = greetService;
            user.hello();
        }

我们就通过类似于 spring 方式一样,或者了GreeterService所有实现类,一个遍历直接获取了所有的实现类.

9. 模块化工具

jdeps jlink等,需要时在看吧.

 

posted @ 2021-11-23 21:58  随意的马蒂洛克  阅读(455)  评论(0编辑  收藏  举报