Each module is responsible for its resources, like media or configuration files.
每个模块负责各自的资源,比如媒体和配置文件。
Previously we'd put all resources into the root level of our project and manually manage which resources belonged to different parts of the application.
模块化出现之前的代码,所有的资源基本都在 根目录管理,需要手动管理划分资源的归属。
With modules, we can ship required images and XML files with the module that needs it, making our projects much easier to manage.
When we create a module, we include a descriptor file that defines several aspects of our new module:
当构建一个模块的时候,我们创建描述符文件,并且定义模块的相关内容。
Name – the name of our module 模块名称
Dependencies – a list of other modules that this module depends on 模块的描述信息
Public Packages – a list of all packages we want accessible from outside the module 允许对外访问的模块
Services Offered – we can provide service implementations that can be consumed by other modules 可以被其他模块使用的服务实现
Services Consumed – allows the current module to be a consumer of a service 允许当前模块成为一个服务的使用者
Reflection Permissions – explicitly allows other classes to use reflection to access the private members of a package 明确地允许其他类使用反射来访问包的私有成员。
The module naming rules are similar to how we name packages (dots are allowed, dashes are not). It's very common to do either project-style (my.module) or Reverse-DNS (_com.baeldung.mymodule_) style names.
模块的命名规则类似于我们命名包的方式(允许使用点,不允许使用破折号)。 比如:
项目风格(my.module)
反向DNS(_com.baeldung.ymodule_)
下文的案例将会一直使用项目风格介绍。
We need to list all packages we want to be public because by default all packages are module private.
我们需要列出所有我们想要公开的软件包,因为在默认情况下,所有软件包都是模块私有的。
The same is true for reflection. By default, we cannot use reflection on classes we import from another module.
Application Modules – These modules are what we usually want to build when we decide to use Modules. They are named and defined in the compiled _module-info.class_ file included in the assembled JAR.
Automatic Modules – We can include unofficial modules by adding existing JAR files to the module path. The name of the module will be derived from the name of the JAR. Automatic modules will have full read access to every other module loaded by the path.
Unnamed Module – When a class or JAR is loaded onto the classpath, but not the module path, it's automatically added to the unnamed module. It's a catch-all module to maintain backward compatibility with previously-written Java code.
Modules can be distributed one of two ways: as a JAR file or as an “exploded” compiled project. This, of course, is the same as any other Java project so it should come as no surprise.
模块同可以通过jar形式发布,或者作为编译项目发布,发布方式和其他Java项目一样。
We can create multi-module projects comprised of a “main application” and several library modules.
我们可以创建”一个主程序应用“和多个库模块形成的多模块项目。
和Maven的多Moudule概念类似,只不过是语言本身开始支持这种封包方式。
We have to be careful though because we can only have one module per JAR file.
但我们必须小心,因为每个JAR文件只能有一个模块。
When we set up our build file, we need to make sure to bundle each module in our project as a separate jar.
Sometimes we write code that references another module, but that users of our library will never want to use.
有的时候会出现代码引用了另一个模块但是永远没有使用。
For instance, we might write a utility function that pretty-prints our internal state when another logging module is present. But, not every consumer of our library will want this functionality, and they don't want to include an extra logging library.
By default, a module doesn't expose any of its API to other modules. This _strong encapsulation_ was one of the key motivators for creating the module system in the first place.
Our code is significantly more secure, but now we need to explicitly open our API up to the world if we want it to be usable.
We use the _exports_ directive to expose all public members of the named package:
module my.module {
exports com.my.package.name;
}
Now, when someone does _requires my.module_, they will have access to the public types in our _com.my.package.name_ package, but not any other package.
We can use _exports…to_ to open up our public classes to the world.
我们可以使用 exports...to 将我们的公共类向世界开放。
But, what if we don't want the entire world to access our API?
但是如果不想公开API应该怎么办?
We can restrict which modules have access to our APIs using the _exports…to_ directive.
我们可以使用exports...tod的指令限制模块访问API。
Similar to the _exports_ directive, we declare a package as exported. But, we also list which modules we are allowing to import this package as a _requires_. Let's see what this looks like:
A _service_ is an implementation of a specific interface or abstract class that can be _consumed_ by other classes.
服务是一个特定接口或抽象类的实现,可以被其他类所使用。
We designate the services our module consumes with the _uses_ directive.
我们使用 uses 指令指定模块使用的服务。
Note that the class name we _use_ is either the interface or abstract class of the service, not the implementation class:
注意,指定的类名称应该是 接口 而不是具体的实现类。
module my.module {
uses class.name;
}
We should note here that there's a difference between a _requires_ directive and the _uses_ directive.
在这里我们应该注意到,_requires_ 指令和 uses 指令之间是有区别的。
We might _require_ a module that provides a service we want to consume, but that service implements an interface from one of its transitive dependencies.
比如我们可能使用requires指令引入了提供服务的模块,但服务实现的接口来自某个传递依赖。
Instead of forcing our module to require _all_ transitive dependencies just in case, we use the _uses_ directive to add the required interface to the module path.
A module can also be a _service provider_ that other modules can consume.
一个模块可以是服务的提供者给其他模块进行使用。
The first part of the directive is the _provides_ keyword. Here is where we put the interface or abstract class name.
指令的第一部分是 provides 关键字。这部分要把接口和抽象类的名字放这里。
Next, we have the _with_ directive where we provide the implementation class name that either _implements_ the interface or _extends_ the abstract class.
接下来,我们有 with 指令,在这里我们提供实现类的名称,该类要么是 implements_ 接口,要么是 _extends 抽象类。
Here's what it looks like put together:
上面两个关键字放在一起的结果如下:
module my.module {
provides MyInterface with MyInterfaceImpl;
}
We mentioned earlier that encapsulation was a driving motivator for the design of this module system.
前面的模块化概念实际上就是进一步提高Java语言的封装性。
Before Java 9, it was possible to use reflection to examine every type and member in a package, even the _private_ ones. Nothing was truly encapsulated, which can open up all kinds of problems for developers of the libraries.
If we need to allow reflection of private types, but we don't want all of our code exposed, we can use the _opens_ directive to expose specific packages.
Okay, so reflection is great sometimes, but we still want as much security as we can get from _encapsulation_. We can selectively open our packages to a pre-approved list of modules, in this case, using the _opens…to_ directive:
我们可以有选择地将我们的包开放给预先批准的模块列表,在这种情况下,使用opens...to指令
module my.module {
opens com.my.package to moduleOne, moduleTwo, etc.;
}
By now, support for Java 9 modules has been added to Maven and Gradle, so you won't need to do a lot of manual building of your projects. However, it's still valuable to know _how_ to use the module system from the command line.
We'll be using the command line for our full example down below to help solidify how the entire system works in our minds.
下面会介绍完整例子中如何使用命令行,帮助理解整个公共系统的运作方式。这里只需要理解工作机制即可。
_module-path_ – We use the _–module-path_ option to specify the module path. This is a list of one or more directories that contain your modules.
_add-reads_ – Instead of relying on the module declaration file, we can use the command line equivalent of the _requires_ directive; _–add-reads_.
_add-exports_ – Command line replacement for the _exports_ directive.
_add-opens_ _–_ Replace the _open_ clause in the module declaration file.
_add-modules_ _–_ Adds the list of modules into the default set of modules
_list-modules_ _–_ Prints a list of all modules and their version strings
_patch-module_ – Add or override classes in a modules
_illegal-access=permit|warn|deny_ – Either relax strong encapsulation by showing a single global warning, shows every warning, or fails with errors. The default is _permit_.
A lot of libraries depend on reflection to work their magic (JUnit and Spring come to mind).
很多库都依赖反射来发挥它们的魔力(比如 JUnit 和 Spring )。
By default in Java 9, we will _only_ have access to public classes, methods, and fields in our exported packages. Even if we use reflection to get access to non-public members and call _setAccessible(true),_ we won't be able to access these members.
We can use the _open_, _opens_, and _opens…to_ options to grant runtime-only access for reflection. Note, this is runtime-only!
虽然我们可以使用 open 、_opens_ 和 opens...to 选项来处理反射只在运行时授权访问。但是需要注意这些指令都是 只在运行时间内生效!
We won't be able to compile against private types, and we should never need to anyway.
我们将无法针对私有类型进行编译,而且无论如何我们都不需要这样做。
If we must have access to a module for reflection, and we're not the owner of that module (i.e., we can't use the _opens…to_ directive), then it's possible to use the command line _–add-opens_ option to allow own modules reflection access to the locked down module at runtime.
First, we need to set up our project structure. We'll create several directories to organize our files.
首先,我们需要设置我们的项目结构。我们将创建几个目录来组织我们的文件。
Start by creating the project folder:
通过下面的命令进行构建。
mkdir module-project
cd module-project
This is the base of our whole project, so add files in here such as Maven or Gradle build files, other source directories, and resources.
只需要一串命令构建项目,没有Maven和Gradle那样的额外依赖。
We also put a directory to hold all our project specific modules.
我们还放了一个目录来存放我们所有的项目特定模块。
Next, we create a module directory:
下面创建模块目录。
mkdir simple-modules
Here's what our project structure will look like:
最后整个项目结构如下:
module-project
|- // src if we use the default package
|- // build files also go at this level
|- simple-modules
|- hello.modules
|- com
|- baeldung
|- modules
|- hello
|- main.app
|- com
|- baeldung
|- modules
|- main
Now that we have the basic structure in place, let's add our first module.
现在我们有了基本的结构,让我们来添加我们的第一个模块。
Under the _simple-modules_ directory, create a new directory called _hello.modules_.
在simple-modules这个目录下面构建一个新的名为hello.modules的模块。
We can name this anything we want but follow package naming rules (i.e., periods to separate words, etc.). We can even use the name of our main package as the module name if we want, but usually, we want to stick to the same name we would use to create a JAR of this module.
We don't need to expose anything to the outside world. Instead, all we need to do is depend on our first module, so we have access to the public classes it exports.
There are two parts to this command, the _javac_ and _find_ commands.
这个命令有两个部分,_javac_ 和 find 命令。
The _find_ command is simply outputting a list of all ._java_ files under our simple-modules directory. We can then feed that list directly into the Java compiler.
The only thing we have to do differently than the older versions of Java is to provide a _module-source-path_ parameter to inform the compiler that it's building modules.
The unnamed module concept is similar to the default package. Therefore, it's not considered a real module, but can be viewed as the default module.
未命名模块的概念类似于默认包。 这个模块被叫做默认模块。
If a class is not a member of a named module, then it will be automatically considered as part of this unnamed module.
如果一个类不是一个命名的模块的成员,那么它将被自动认为是这个未命名的模块的一部分。
Sometimes, to ensure specific platform, library, or service-provider modules in the module graph, we need to add modules to the default root set. For example, when we try to run Java 8 programs as-is with Java 9 compiler we may need to add modules.
In general, the option to add the named modules to the default set of root modules is –add-modules < module >(,< module >)* where < module > is a module name.
// 多态, 在JAVA中是这样用的, 其实在PHP当中可以自然消除, 因为参数是动态的, 你传什么过来都可以, 不限制类型, 直接调用类的方法
abstract class Tiger {
public abstract function climb();
}
class XTiger extends Tiger {
public function climb()
jQuery.extend({
handleError: function( s, xhr, status, e ) {
// If a local callback was specified, fire it
if ( s.error ) {
s.error.call( s.context || s, xhr, status, e );
}
always 总是
rice 水稻,米饭
before 在...之前
live 生活,居住
usual 通常的
early 早的
begin 开始
month 月份
year 年
last 最后的
east 东方的
high 高的
far 远的
window 窗户
world 世界
than 比...更
最近使用mybatis.3.1.0时无意中碰到一个问题:
The errors below were detected when validating the file "mybatis-3-mapper.dtd" via the file "account-mapper.xml". In most cases these errors can be d