- 浏览: 273163 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
muyufenghua:
public static <T super B> ...
浅谈Java泛型中的extends和super关键字 -
wantodare:
class Test1 {
{
a=1;
}
pr ...
Java对象初始化详解 -
wubo2qml:
问下如何进行列中数字大小的比较。我看了几个过滤器,最接近的是S ...
利用Filter进行HBase查询 -
blackproof:
rowkey是A_B我知道要的A集合,也知道要的B范围不用自定 ...
利用Filter进行HBase查询 -
bin_1715575332:
文章不错,尤其了后半部分讲解一些原理。
利用Filter进行HBase查询
最近看来一些有关Java Annotation的东西,主要是翻了一下Thinking in Java这本书。算是对Java的Annotation有了一个大致的了解。在看Thinking in Java的时候,书里面有一段代码,专门介绍如何利用Java 1.5之后自带的apt(Annotation Processing Tool)工具来处理Annotation的。代码如下:
这段代码做的事情是利用Java mirrors包提供的Visitor模式来处理Java源代码中的Annotation,然后生成一个创建数据库表的SQL语句。至于那些个Annotation怎么定义的大家参看Thinking in Java第四版的相关章节,这里不再累述了。
在这里我要将的主要有两个方面,一个是关于apt的,一个是关于上面代码中的Visitor模式的。
一,关于apt
apt是Sun从JDK 1.5(包括1.5)之后开始提供的处理源代码级别Annotation的工具,主要目标是根据源代码生成新的代码或者其他的一些文件,例如对象关系映射文件等。apt在处理源代码中的Annotation的时候,会调用特定的AnnotationProcessor,这些AnnotationProcessor是需要开发人员去实现的,一个Processor可以对应一个自定义的Annotation或者多个自定义的Annotation。
但是apt不是直接调用AnnotationProcessor的,而是要通过AnnotationProcessorFactory来获得处理具体Annotation的。而AnnotationProcessorFactory是一个接口,所以为了使用apt,我们除了要实现AnnotationProcessor之外,还要实现AnnotationProcessorFactory。具体的方法见Thinking in Java第四版。
apt的实现是在com.sun.tools.apt及其子包中,这个包实现了com.sun.mirror及其相关子包中的接口,用来处理源代码级别的Annotation。mirror包是Sun提供的专门用来获取源代码中的类型信息的工具包,而reflect包则是用来获取运行时类型信息的工具包。Sun建议在处理Java代码文件时,使用mirror包。
为了降低处理源码中Annotation的代码复杂度,mirror中的关于类型的所有接口(xxxDeclaration)实现了Visitor模式,每个Declaration接口的子类都有一个accept方法,用来接收一个DeclarationVisitor接口的实现类,并调用该接口中的相应方法。具体可以参看Sun的相关API文档。
我通过上面的代码看了一下mirror包里面相关类的源代码,从源代码以及上面代码的写法来看,apt是在扫描了全部的Java源文件之后,才去调用Processor的。也就是说AnnotationProcessorFactory接口的getProcessorFor方法是在apt分析了所有的源代码之后才被调用的,之后apt就会调用getProcessorFor方法返回的AnnotationProcessor接口实现类的process()方法,来处理Annotation。apt在扫描源代码的时候会将相关的Annotation信息保存在AnnotationProcessorEnvironment对象中,这样在AnnotationProcessor中就可以拿到所有Annotation信息了。至于那些Annotation的信息会被保存下来,这是在AnnotationProcessorFactory接口的supportedAnnotationTypes()方法中规定的。
关于apt大概就是这些了。
二,关于Visitor模式
在Sun的com.sun.mirror.declaration包里面定义了很多的Declaration接口,用来对应源代码中的不同层次的元素,包括类型,构造函数,成员变量,方法参数等等。但是在mirror包里面没有提供实现类。具体的实现类是在com.sun.tools.apt.mirror.declaration包里面定义的。因为apt工具需要使用这些信息。
在每个Declaration中都有个accept方法,该方法接收一个DeclarationVisitor接口的实现类,并调用DeclarationVisitor接口的实现类相应方法。在DeclarationVisitor定义了正对不同Declaration接口的方法,具体可以参看Sun的相关API文档。
在最开始的代码里面,TableCreationProcessor的process方法是这样写的:
其中的for循环遍历所有的TypeDeclaration,并调用每个TypeDeclaration的accept方法。在调用accept方法的时候并不是直接初始化一个DeclarationVisitor接口的实现类,而是调用的com.sun.mirror.util.DeclarationVisitors静态类的getDeclarationScanner静态方法。这个方法的作用看一下API的说明就知道了,是用来包装DeclarationVisitor的。官方的说明如下:
Return a DeclarationVisitor that will scan the declaration structure, visiting declarations contained in another declaration. For example, when visiting a class, the fields, methods, constructors, etc. of the class are also visited. The order in which the contained declarations are scanned is not specified.
The pre and post DeclarationVisitor parameters specify, respectively, the processing the scanner will do before or after visiting the contained declarations. If only one of pre and post processing is needed, use DeclarationVisitors.NO_OP for the other parameter.
大概意思就是这个方法包装出来的DeclarationScanner类实现了DeclarationVisitor接口,同时在Visit一个Declaration的时候,会同时Visit这个Declaration下的所有子Declaration,比如在Visit一个ClassDeclaration的时候,就会同时Visit这个Class中的TypeParameterDeclaration,FieldDeclaration,MethodDeclaration,TypeDeclaration(因为Type可能会有嵌套),ConstructorDeclaration等。
这样的话就节省了开发人员的代码量了,要不然我们自己还是要写同样的代码去处理这些个东西,而且还容易出错。
要写的主要问题大概就这么一些,其他的感觉都是比较好理解的,看下书应该就知道了。
//: annotations/database/TableCreationProcessorFactory.java // The database example using Visitor. // {Exec: apt -factory // annotations.database.TableCreationProcessorFactory // database/Member.java -s database} package annotations.database; import com.sun.mirror.apt.*; import com.sun.mirror.declaration.*; import com.sun.mirror.util.*; import java.util.*; import static com.sun.mirror.util.DeclarationVisitors.*; public class TableCreationProcessorFactory implements AnnotationProcessorFactory { public AnnotationProcessor getProcessorFor( Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) { return new TableCreationProcessor(env); } public Collection<String> supportedAnnotationTypes() { return Arrays.asList( "annotations.database.DBTable", "annotations.database.Constraints", "annotations.database.SQLString", "annotations.database.SQLInteger"); } public Collection<String> supportedOptions() { return Collections.emptySet(); } private static class TableCreationProcessor implements AnnotationProcessor { private final AnnotationProcessorEnvironment env; private String sql = ""; public TableCreationProcessor( AnnotationProcessorEnvironment env) { this.env = env; } public void process() { for(TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) { typeDecl.accept(getDeclarationScanner( new TableCreationVisitor(), NO_OP)); sql = sql.substring(0, sql.length() - 1) + ");"; System.out.println("creation SQL is :\n" + sql); sql = ""; } } private class TableCreationVisitor extends SimpleDeclarationVisitor { public void visitClassDeclaration( ClassDeclaration d) { DBTable dbTable = d.getAnnotation(DBTable.class); if(dbTable != null) { sql += "CREATE TABLE "; sql += (dbTable.name().length() < 1) ? d.getSimpleName().toUpperCase() : dbTable.name(); sql += " ("; } } public void visitFieldDeclaration( FieldDeclaration d) { String columnName = ""; if(d.getAnnotation(SQLInteger.class) != null) { SQLInteger sInt = d.getAnnotation( SQLInteger.class); // Use field name if name not specified if(sInt.name().length() < 1) columnName = d.getSimpleName().toUpperCase(); else columnName = sInt.name(); sql += "\n " + columnName + " INT" + getConstraints(sInt.constraints()) + ","; } if(d.getAnnotation(SQLString.class) != null) { SQLString sString = d.getAnnotation( SQLString.class); // Use field name if name not specified. if(sString.name().length() < 1) columnName = d.getSimpleName().toUpperCase(); else columnName = sString.name(); sql += "\n " + columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraints()) + ","; } } private String getConstraints(Constraints con) { String constraints = ""; if(!con.allowNull()) constraints += " NOT NULL"; if(con.primaryKey()) constraints += " PRIMARY KEY"; if(con.unique()) constraints += " UNIQUE"; return constraints; } } } } ///:~
这段代码做的事情是利用Java mirrors包提供的Visitor模式来处理Java源代码中的Annotation,然后生成一个创建数据库表的SQL语句。至于那些个Annotation怎么定义的大家参看Thinking in Java第四版的相关章节,这里不再累述了。
在这里我要将的主要有两个方面,一个是关于apt的,一个是关于上面代码中的Visitor模式的。
一,关于apt
apt是Sun从JDK 1.5(包括1.5)之后开始提供的处理源代码级别Annotation的工具,主要目标是根据源代码生成新的代码或者其他的一些文件,例如对象关系映射文件等。apt在处理源代码中的Annotation的时候,会调用特定的AnnotationProcessor,这些AnnotationProcessor是需要开发人员去实现的,一个Processor可以对应一个自定义的Annotation或者多个自定义的Annotation。
但是apt不是直接调用AnnotationProcessor的,而是要通过AnnotationProcessorFactory来获得处理具体Annotation的。而AnnotationProcessorFactory是一个接口,所以为了使用apt,我们除了要实现AnnotationProcessor之外,还要实现AnnotationProcessorFactory。具体的方法见Thinking in Java第四版。
apt的实现是在com.sun.tools.apt及其子包中,这个包实现了com.sun.mirror及其相关子包中的接口,用来处理源代码级别的Annotation。mirror包是Sun提供的专门用来获取源代码中的类型信息的工具包,而reflect包则是用来获取运行时类型信息的工具包。Sun建议在处理Java代码文件时,使用mirror包。
为了降低处理源码中Annotation的代码复杂度,mirror中的关于类型的所有接口(xxxDeclaration)实现了Visitor模式,每个Declaration接口的子类都有一个accept方法,用来接收一个DeclarationVisitor接口的实现类,并调用该接口中的相应方法。具体可以参看Sun的相关API文档。
我通过上面的代码看了一下mirror包里面相关类的源代码,从源代码以及上面代码的写法来看,apt是在扫描了全部的Java源文件之后,才去调用Processor的。也就是说AnnotationProcessorFactory接口的getProcessorFor方法是在apt分析了所有的源代码之后才被调用的,之后apt就会调用getProcessorFor方法返回的AnnotationProcessor接口实现类的process()方法,来处理Annotation。apt在扫描源代码的时候会将相关的Annotation信息保存在AnnotationProcessorEnvironment对象中,这样在AnnotationProcessor中就可以拿到所有Annotation信息了。至于那些Annotation的信息会被保存下来,这是在AnnotationProcessorFactory接口的supportedAnnotationTypes()方法中规定的。
关于apt大概就是这些了。
二,关于Visitor模式
在Sun的com.sun.mirror.declaration包里面定义了很多的Declaration接口,用来对应源代码中的不同层次的元素,包括类型,构造函数,成员变量,方法参数等等。但是在mirror包里面没有提供实现类。具体的实现类是在com.sun.tools.apt.mirror.declaration包里面定义的。因为apt工具需要使用这些信息。
在每个Declaration中都有个accept方法,该方法接收一个DeclarationVisitor接口的实现类,并调用DeclarationVisitor接口的实现类相应方法。在DeclarationVisitor定义了正对不同Declaration接口的方法,具体可以参看Sun的相关API文档。
在最开始的代码里面,TableCreationProcessor的process方法是这样写的:
public void process() { for(TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) { typeDecl.accept(getDeclarationScanner( new TableCreationVisitor(), NO_OP)); sql = sql.substring(0, sql.length() - 1) + ");"; System.out.println("creation SQL is :\n" + sql); sql = ""; } }
其中的for循环遍历所有的TypeDeclaration,并调用每个TypeDeclaration的accept方法。在调用accept方法的时候并不是直接初始化一个DeclarationVisitor接口的实现类,而是调用的com.sun.mirror.util.DeclarationVisitors静态类的getDeclarationScanner静态方法。这个方法的作用看一下API的说明就知道了,是用来包装DeclarationVisitor的。官方的说明如下:
引用
Return a DeclarationVisitor that will scan the declaration structure, visiting declarations contained in another declaration. For example, when visiting a class, the fields, methods, constructors, etc. of the class are also visited. The order in which the contained declarations are scanned is not specified.
The pre and post DeclarationVisitor parameters specify, respectively, the processing the scanner will do before or after visiting the contained declarations. If only one of pre and post processing is needed, use DeclarationVisitors.NO_OP for the other parameter.
大概意思就是这个方法包装出来的DeclarationScanner类实现了DeclarationVisitor接口,同时在Visit一个Declaration的时候,会同时Visit这个Declaration下的所有子Declaration,比如在Visit一个ClassDeclaration的时候,就会同时Visit这个Class中的TypeParameterDeclaration,FieldDeclaration,MethodDeclaration,TypeDeclaration(因为Type可能会有嵌套),ConstructorDeclaration等。
这样的话就节省了开发人员的代码量了,要不然我们自己还是要写同样的代码去处理这些个东西,而且还容易出错。
要写的主要问题大概就这么一些,其他的感觉都是比较好理解的,看下书应该就知道了。
发表评论
-
Java对象初始化详解
2012-07-18 00:43 27086在Java中,一个对象在可 ... -
利用Filter进行HBase查询
2012-07-11 00:14 19871在HBase中,我们可以利 ... -
Java中Enum类型的序列化
2012-07-07 21:53 30745在Java中,对Enum类型的序列化与其他对象类型的序列化有所 ... -
Java final关键字详解
2012-07-07 16:27 4054在java中,final关键字可以有如下的用处: final ... -
利用线程隔离简化并发控制
2012-06-28 01:18 2266在Java中,为了限制多个不同线程对共享变量或者状态的访问,利 ... -
Java内存模型能给我们什么
2012-06-24 15:07 1562首先,为什么需要有内 ... -
java方法调用过程解析和执行--编译器的处理
2012-06-02 15:24 2999本文尝试对java在编译器和运行期如何处理程序代码中的方法调用 ... -
maven杂记
2012-03-02 00:32 2059单独部署一个文件到repo 有时候我们会需要单独部署一个文件到 ... -
浅谈Java泛型中的extends和super关键字
2010-12-25 21:06 18981泛型是在Java 1.5中被加入了,这里不讨论泛型的细节 ... -
Java xml处理概述
2010-12-14 18:21 1599在Java中,对xml的处理模型主要有两种,一种DOM,一种是 ... -
Inversion of Control Containers and the Dependency Injection pattern
2009-12-02 23:02 1053One of the entertaining things ... -
Java中Soft,Weak,Phantom应用的区别和使用
2009-10-29 13:20 2427Java 1.2版本之后加入 ... -
java 反射实例化内部类
2009-08-25 13:51 5939内部类的初始化同一般类的初始化基本相同,只是内部类的类名全 ... -
java 泛型-erasure
2009-07-30 12:42 2643Java的泛型实现采用了擦除(erasure)机制,这给获 ... -
Java语言深入:深入研究Java equals方法
2009-07-28 11:43 1158equals方法的重要性毋 ... -
正则表达式计算单词出现次数
2009-06-23 16:06 5596给定一段文本,使用正则表达式计算该文本中不同单词的出现次数。 ... -
JDK 1.5 Proxy 动态代理机制分析
2009-06-16 11:34 2568Java的动态代理机制早在其1.3版本就已经引入了。在jdk1 ... -
使Maven 2在package、install等阶段跳过运行Test的配置
2009-06-07 11:52 10575Skipping Tests To skip running ...
相关推荐
### 搭建APT代理服务器知识点详解 #### 一、APT代理服务器概述 APT代理服务器是一种专门为局域网内多台Ubuntu Linux系统提供软件包安装与更新服务的解决方案。通过集中下载并缓存软件包,它能显著提高局域网内...
openstack工具,fuel一键安装镜像光盘MirantisOpenStack-9.0 上传本地源mirrors bootstraps 虚拟机VirtualBox等
Nacos 是一个由阿里巴巴开源的、轻量级的分布式服务治理和配置中心,它主要服务于微服务架构,提供服务发现、配置管理、健康检查等...通过学习和研究这些源码,你可以更好地理解和利用 Nacos,提升你的微服务治理能力。
Ubuntu18.04sudoaptupdate无法解析域名的解决方案.docx
Maven是Java开发中的一款项目管理和集成工具,它简化了构建、依赖管理以及项目的生命周期过程。在Maven中,`mirrors`配置是一个重要的部分,它关乎到Maven如何高效地下载依赖。`maven-阿里云-mirrors.txt.zip`这个...
在 Ubuntu 中,`dpkg` 工具用于处理这些包,包括安装、删除和验证等操作。 #### 依赖管理 当安装一个软件包时,可能需要其他软件包的支持,这些被称作依赖包。依赖关系确保了软件包能够正常运行。例如,一个应用...
`apt-get` 是 Advanced Package Tool(高级包工具)的一部分,用于管理和升级 Linux 系统中的软件包。它允许用户安装、升级、卸载和搜索软件包。然而,`apt-get` 默认依赖于配置文件中设定的软件源,这些源可能位于...
如果您想使用自己的 mirrors.list 文件,请通过将 /etc/apt/mirror.list 挂载为主机卷来覆盖默认值。 nginx 设置为在尽可能少的干扰下通过端口 80 炸掉整个 apt 镜像。 再一次,通过将 /etc/nginx/sites-enabled/...
对于基于Debian的发行版,如Ubuntu,通常会使用`apt`命令来进行软件包的安装、更新等操作。本文将详细介绍如何配置Ubuntu系统的软件和更新选项,以及如何正确地设置ROS源,以确保能够顺利地获取最新的ROS相关软件包...
APT是Debian及其衍生版(如Ubuntu)中的包管理工具。它提供了强大而灵活的功能,用于安装、更新和删除软件包。 - **安装包**:`apt-get install <pkg>` - **移除包**:`apt-get remove <pkg>` - **更新包列表**:`...
### 通过FPM工具将源码打包为RPM安装文件 #### 一、概述 在Linux环境下,将软件源码转换为易于安装的RPM格式是常见的做法之一。本篇文章将详细介绍如何使用FPM工具将Python源码打包为RPM安装文件的过程。此方法...
【Ethereal抓包工具简介】 Ethereal是一款强大的网络封包分析软件,广泛应用于网络故障排查、网络安全分析和性能优化。它能够捕获并显示网络上的数据包,帮助用户理解网络通信过程,深入分析网络流量。 **Ethereal...
在 Debian 和 Ubuntu 的包管理中,`apt` 和 `apt-get` 是两个紧密相关的命令行工具。`apt` 提供了一个更高级、用户友好的接口,而 `apt-get` 是其底层工作引擎,执行实际的包安装、升级和管理任务。因此,优化 `apt-...
sudo nano /etc/apt/sources.list deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi 2.更改系统更新源 sudo nano /etc/apt/sources.list.d/raspi.list deb ...
"mirrors-YApi-master.zip"这个压缩包文件,正是YApi的一个版本,虽然它提示仅供学习使用,但我们仍能从中获取丰富的知识。 YApi是由HappyDigger团队开发的,它的设计目标是提供一个高效率、易用的API管理平台,...
在Ubuntu 18.04操作系统中,"换源"是指更换系统软件包的下载源,目的是为了提高软件更新和安装的速度以及稳定性。通常,Ubuntu官方的软件源可能因为地理位置和网络条件的原因,在某些地区访问速度较慢。在这种情况下...
标题中的"mirrors-fzf-master_java_"表明这是一个与fzf工具相关的项目,可能是该工具的一个镜像或特定版本,特别是针对Java平台优化的。fzf是"Fast Filter"的缩写,是一个广受欢迎的开源命令行工具,由Junegunn Choi...
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,被广泛应用于图像处理、机器学习和深度学习领域。它提供了丰富的函数和模块,使得开发者能够轻松地进行图像分析和处理任务。在OpenCV的...
- 移除包:`apt-get remove` - 更新包列表:`apt-get update` - 更新系统:`apt-get upgrade` - 列出源:`cat /etc/apt/sources.list` - 添加源:编辑`/etc/apt/sources.list` - 移除源:编辑`/etc/apt/...