许多同学日常开发时,都不太注意到,原来自己维护这么久的 web 工程中,居然还有 package-info.java 这么一个类。
但只要我们在 idea 中搜索一下,就能够发现很多依赖包,都用到了这个类的实现。
那么,下面我们一起研究下,到底什么是 package-info.java 类文件~~
【目录】
1)注解技术
2)package-info类拆解
3)动态ClassLoader原理 与 双亲委派机制
4)自定义ClassLoader
一、注解技术
注解(annotation)是 Java 5 引入的,用来为类、方法、字段、参数等 Java 结构提供额外信息的机制。我先举个例子,比如,Java 核心类库中的@Override注解是被用来声明某个实例方法重写了父类的同名同参数类型的方法。
package java.lang;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
二、package-info类拆解
下面我们用一个简单的例子(分包逻辑开发),演示 package-info.java 的用法:
1)创建一个package:packageinfo
2)创建一个注解:PackageAnotation
/**
* PackageAnotation.java 定义修饰包的注解
* package-info不是平常类,其作用有三个:
* 1、为标注在包上Annotation提供便利;
* 2、声明包的私有类和常量;
* 3、提供包的整体注释说明。
*/
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
@interface PackageAnotation {
public String version() default "";
}
3)创建一个类,类名 = package-info.java
/**
* package-info不是平常类,其作用有三个:
* 1、为标注在包上Annotation提供便利;
* 2、声明包的私有类和常量;
* 3、提供包的整体注释说明。
*/
@PackageAnotation(version="1.0")
package packageinfo;
4)创建测试用例,类名 = TestPackageInfo.java
package packageinfo;
/**
* 测试package-info.java文件的作用
* 1、为标注在包上Annotation提供便利;
* 2、声明包的私有类和常量;
* @author [email protected]
*/
public class TestPackageInfo {
public static void main(String[] args) {
//1 获取 Package 类
Package p = Package.getPackage("packageinfo");
//2 判断这个包对象,(是否在 package-info.java 中声明)且被某个注解(PackageAnotation)修饰
if(p != null && p.isAnnotationPresent(PackageAnotation.class)) {
//3 如果找到了注解,获取注解信息,实现业务逻辑(Servlet过滤、鉴权、分发请求等)
PackageAnotation nav = p.getAnnotation(PackageAnotation.class);
if (nav != null) {
System.out.println("package version:" + nav.version());
}
}
}
}
三、动态ClassLoader原理 与 双亲委派机制
3.1、动态ClassLoader原理
上面的测试用例,Package.getPackage("packageinfo"); 背后隐藏了一个原理 -- 类的动态加载。
写好一个Java程序,都是由若干个.class文件组织而成的一个完整的Java应用程序。当程序在运行时,即会调用该程序的一个入口函数,通过它来调用系统的相关功能;而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法。因此,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是按需通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。
所以ClassLoader就是用来动态加载class文件到内存当中用的。
我们写好的应用类(业务代码),大部分都是通过这个类加载器 AppClassLoader 来加载到JVM里面。
3.2 JVM默认有3个默认类加载器
ExtClassLoader 称为扩展类加载器,主要负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有jar包或者由java.ext.dirs系统属性指定的jar包.放入这个目录下的jar包对AppClassLoader加载器都是可见的(因为ExtClassLoader是AppClassLoader的父加载器,并且Java类加载器采用了委托机制)。
BootstrapClassLoader 称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等,可通过如下程序获得该类加载器从哪些地方加载了相关的jar或class文件。
3.3 双亲委派机制
如果说,我们想引用一些外部依赖,那么就需要更高层的类加载器,让它们帮我们完成这个类装载的过程了,而这个过程也有个专有名词:双亲委派机制。
类加载分级:
-> 自定义ClassLoader
-> AppClassLoader
-> ExtClassLoader
-> BootstrapClassLoader
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器,父类加载器又将加载任务向上委托,直到最父类加载器,如果最父类加载器可以完成类加载任务,就成功返回,如果不行就向下传递委托任务,由其子类加载器进行加载。
总结
以上是关于package-info.java的相关知识介绍,还牵扯到了类加载器的回顾,希望对大家工作有所帮助。
后端技术&架构精华
《源码系列》
《JDK之Object 类》
《JDK之BigDecimal 类》
《JDK之String 类》
《JDK之Lambda表达式》
《Spring源码:Event事件发布与监听》
《经典书籍》
《Java并发编程实战:第1章 多线程安全性与风险》
《Java并发编程实战:第2章 影响线程安全性的原子性和加锁机制》
《Java并发编程实战:第3章 助于线程安全的三剑客:final & volatile & 线程封闭》
《服务端技术栈》
《Docker 核心设计理念》
《Kafka史上最强原理总结》
《HTTP的前世今生》
《算法系列》
《读懂排序算法(一):冒泡&直接插入&选择比较》
《读懂排序算法(二):希尔排序算法》
《读懂排序算法(三):堆排序算法》
《读懂排序算法(四):归并算法》
《读懂排序算法(五):快速排序算法》
《读懂排序算法(六):二分查找算法》
《项目管理》
《学点项目管理,对咱程序员很重要》
《项目管理实践篇(一):技术人如何做好风险把控》
《项目管理实践篇(二):总结项目经历》
《如何写好一篇汇报材料》