Java 反编译工具:DJ Java Decompiler / JD-GUI

Java 反编译 Java Decompiler “Java Decompiler”, 由 Pavel Kouznetsov开发,目前最新版本为0.2.5. 它由 C++开发,并且官方可以下载windows、linux和苹果Mac Os三个平台的可执行程序。 http://jd.benow.ca/ http://www.oschina.net/p/java+decompiler DJ Java Decompiler(不免费) DJ Java Decompiler 是个反编译的工具,可以将编译过的 CLASS 文件编译还原成为 Java 原始文件,并且不需要额外安装 JVM (Java Virtual Machine) 或是JDK 的工具模组即可使用。不单如此,它也兼具有 Java 程序编辑工具的角色,提供一些辅助功能便于程序撰写与修改。 DJ Java Decompiler 在 Windows 95、Windows 98、Windows 2000、Windows XP、Windows 2003、Windows Vista、 Windows 7等多种平台上均可以运行的 Java 反编译器和汇编器。DJ Java Decompiler 能够反复编译复杂的 Java 小程序和二进制文件,生产出准确的源代码。它不仅是 Java 反编译器和汇编器,也是一个功能齐全的使用有着着色语法的图形用户界面的 Java 编辑器。 这款软件十分适合用来学习编程,而且它能够让用户保存、打印、编辑和编译生成的 Java 代码。 另外,DJ Java Decompiler 是一个独立的 windows 应用程序,它不要求安装Java,所以运行使用相当方便,大家不妨试一下。 个人觉得比较好的功能有: 可以直接打开jar 档, 查看jar 包里原文件 ...

Created 24246-08-24 · Updated 5056-06-05 · 1 min · 75 words · -

dex2jar

dex2jar https://code.google.com/p/dex2jar/ http://blog.csdn.net/kesenhoo/article/details/6544094 dex2jar contains following compment dex-reader is designed to read the Dalvik Executable (.dex/.odex) format. It has a light weight API similar with ASM. An example here dex-translator is designed to do the convert job. It reads the dex instruction to dex-ir format, after some optimize, convert to ASM format. dex-ir used by dex-translator, is designed to represent the dex instruction dex-tools tools to work with .class files. here are examples: Modify a apk DeObfuscate a jar d2j-smali [To be published] disassemble dex to smali files and assemble dex from smali files. different implementation to smali/baksmali, same syntax, but we support escape in type desc “Lcom/dex2jar\t\u1234;” dex-writer [To be published] write dex same way as dex-reader.

Created 10106-04-10 · Updated 5056-06-05 · 1 min · 118 words · -

Jetty

Jetty Jetty 是一个开源的 servlet 容器,它为基于 Java 的 web 内容(例如 JSP 和 servlet)提供运行环境。Jetty 使用 Java 编写,API 以一组 JAR 包的形式发布。开发人员可以将 Jetty 容器实例化成一个对象,为一些独立运行(stand-alone)的 Java 应用提供网络和 web 连接。 易用性 易用性是 Jetty 设计的基本原则,主要体现在: 通过 XML 或 API 配置 Jetty 默认配置可满足大部分需求 将 Jetty 嵌入应用程序只需很少的代码 可扩展性 在使用了 Ajax 的 Web 2.0 应用中,每个连接需要保持更长时间,线程和内存消耗会明显增加。Jetty 在这方面有优势: 即使在大量服务请求下,系统性能仍可保持可接受水平 利用 Continuation 机制处理大量用户请求及长连接 接口设计良好,当某种实现无法满足需求时,可方便地修改 Jetty 的特定实现 易嵌入性 Jetty 设计之初就是作为优秀组件来设计的,可非常容易地嵌入应用程序,无需为使用 Jetty 而大幅修改程序。某种程度上,也可以把 Jetty 理解为一个嵌入式 Web 服务器。 Jetty 可作为嵌入式服务器使用,运行速度较快且轻量,可在 Java 测试用例中控制其运行,使自动化测试不再依赖外部环境。 Jetty vs Tomcat 参考:Jetty 与 Tomcat 的比较(IBM developerWorks) ...

Created 16166-12-16 · Updated 20206-05-20 · 1 min · 173 words · -

Java 引用类型与基本类型

在 Java 性能优化中,内存管理是一个要优先考虑的关键因素。而说到内存分配,就必然会涉及到基本类型和引用类型。 名词定义 所谓基本类型,就是 Java 语言中如下 8 种内置类型:boolean、char、byte、short、int、long、float、double。而引用类型就是那些可以通过 new 来创建对象的类型(基本上都派生自 Object)。 两种类型的存储方式 这两种类型的差异,首先体现在存储方式上。在 Java 中,引用类型的对象存储在堆(Heap)上;而基本类型的值存储在栈(Stack)上。 堆和栈的性能差异 堆和栈在性能方面差别很大。堆相对进程来说是全局的,能够被所有线程访问;而栈是线程局部的,只能本线程访问。 由于堆是所有线程共有的,从堆里申请内存要进行相关的加锁操作,因此申请堆内存的复杂度和时间开销比栈要大很多;从栈里申请内存,虽然又简单又快,但是栈的大小有限,分配不了太多内存。 为什么这样设计 James Gosling 设计 Java 时,把各种东西都放置到栈中显然不现实:一来栈是线程私有的(不便于共享),二来栈的大小是有限的,三来栈的结构也间接限制了它的用途。而都放堆里面,申请堆内存需要加锁,开销太大。如果仅仅在函数中写一个简单的 int n = 0,也要到堆里面去分配内存,性能就会很差。 最终的折中方案:把类型分为基本类型和引用类型;引用类型(Object 派生)的对象存放到堆里面;把基本类型(非 Object 派生)的值存放到栈里面。从 Java 语法上也可以看出两者的差别:引用类型可以用 new 创建对象;而基本类型则不需要用 new 来创建。 这样设计的弊端 这个折中决策带来了一些深远影响: 由于基本类型不是派生自 Object,因此不能算是纯粹的对象,使 Java 的"纯面向对象"招牌打了折扣。 出于某些场合(比如容器类)的考虑,不得不为每个基本类型加上对应的包装类(比如 Integer、Byte 等),使语言变得有点冗余。 结论 使用 new 创建对象的开销不小,在程序中能避免就应该尽量避免。另外,使用 new 创建对象,不光创建时开销大,将来垃圾回收时销毁对象也是有开销的。 参考: http://program-think.blogspot.com/2009/03/java-performance-tuning-1-two-types.html http://www.ibm.com/developerworks/cn/java/praxis/pr8.html 原始类型和封装类 原始类型 封装类 boolean Boolean char Character byte Byte short Short int Integer long Long float Float double Double 引用类型与基本类型的行为差异 引用类型和原始类型的行为完全不同。例如,假定一个方法中有两个局部变量,一个变量为 int 原始类型,另一个变量是对一个 Integer 对象的对象引用: ...

Created 20206-09-20 · Updated 13136-05-13 · 2 min · 260 words · -

Lombok

Lombok 是一个 Java 编译器插件,通过注解在编译期自动生成 getter/setter、构造器、equals/hashCode、toString、Builder 等样板代码,让源文件保持简洁。 发音:来自印度尼西亚龙目岛(Lombok Island),读作 LOM-bok,重音在第一个音节。 出现时间:2009 年首次发布,比 Spring Boot(2014 年)早了五年,与 Spring 没有直接关系,是独立的 Java 工具。 原理:利用 Java 编译器的注解处理器(Annotation Processing)在 javac 编译时修改语法树,将生成的方法直接写入 .class 字节码,源文件里没有这些方法但编译产物里有。IDE 需要安装 Lombok 插件才能识别生成的方法。 解决了什么问题 Java 要求显式写大量与业务无关的样板代码,一个普通的 JavaBean 需要: // 不用 Lombok:一个 User 类要写几十行 public class User { private Long id; private String name; private String email; public User() {} public User(Long id, String name, String email) { ... } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } // ... 还有 equals / hashCode / toString ... } 用 Lombok: ...

Created 12126-05-12 · Updated 12126-05-12 · 2 min · 392 words · -

AOP

AOP(Aspect-Oriented Programming,面向切面编程)是对 OOP 的补充,用于将横切关注点(cross-cutting concerns)从业务逻辑中分离出来,集中管理。典型横切关注点包括:日志记录、事务管理、权限校验、性能监控、缓存、同步等——这些逻辑如果分散在每个方法里,既冗余又难以维护。 AOP 实际是 GoF 设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP 可以说也是这种目标的一种实现。 AOP 解决了什么问题 在没有 AOP 的情况下,每个业务方法都要亲自处理横切逻辑: // 没有 AOP:每个方法都要重复写日志、事务、权限检查 public User findById(Long id) { log.info("开始查询 user={}", id); // 日志 checkPermission("user:read"); // 权限 Transaction tx = db.beginTransaction(); // 事务 try { User user = db.query(id); // 真正的业务逻辑 tx.commit(); return user; } catch (Exception e) { tx.rollback(); throw e; } finally { log.info("查询结束"); // 日志 } } 这带来三个问题: ...

Created 7076-01-07 · Updated 12126-05-12 · 4 min · 775 words · -

SOLID 面向对象设计原则

SOLID 是面向对象设计的五大基本原则的首字母缩写,由 Robert C. Martin(Uncle Bob)整理归纳。这五个原则是编写可维护、可扩展代码的基础。 S — 单一职责原则 (Single Responsibility Principle, SRP) 一个类应该只有一个引起它变化的原因。 一个类只做一件事。如果一个类承担了多个职责,那么每个职责的变化都可能影响这个类,导致它越来越难以维护。 反例: 简单工厂模式中的工厂类 Driver 同时负责判断车型和创建所有车对象,违反了单一职责。 O — 开闭原则 (Open-Closed Principle, OCP) 软件实体应该对扩展开放,对修改封闭。 添加新功能时,应该通过新增代码实现,而不是修改已有代码。详见开闭原则。 反例: 简单工厂的 if/else 判断链,每新增一种产品都要修改工厂方法。 L — 里氏替换原则 (Liskov Substitution Principle, LSP) 子类必须能够替换其父类,且程序行为不变。 任何使用父类的地方,换成子类后程序应该仍然正确运行。子类不应该破坏父类的契约。 示例: Benze 和 Bmw 都实现了 Car 接口,客户端代码使用 Car 类型,无论实际是哪种车,drive() 都能正确调用。 I — 接口隔离原则 (Interface Segregation Principle, ISP) 客户端不应该被迫依赖它不使用的方法。 接口应该尽量细化,不要把不相关的方法放在同一个接口里。大接口应该拆分成多个小接口,让实现类只需要关心自己用到的方法。 反例: 一个包含 fly()、swim()、run() 的 Animal 接口,鱼类被迫实现 fly() 和 run()。 ...

Created 16166-04-16 · Updated 16166-04-16 · 1 min · 87 words · -

设计模式 — 工厂模式, Factory

设计模式 — 工厂模式, Factory 一、引子 话说十年前,有一个老板,他家有三辆汽车 —— Benz奔驰、Bmw宝马、Audi奥迪,还雇了司机为他开车。不过,老板坐车时总是怪怪的: 上Benz车后跟司机说"开奔驰车!",坐上Bmw后他说"开宝马车!",坐上Audi说"开奥迪车!"。你一定说: 这人有病!直接说开车不就行了?! 而当把这个老板的行为放到我们程序设计中来时,会发现这是一个普遍存在的现象。幸运的是,这种有病的现象在 OO (面向对象) 语言中可以避免了。下面就以 Java 语言为基础来引入我们本文的主题: 工厂模式。 二、分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。 工厂模式在《Java与模式》中分为三类: 简单工厂模式 (Simple Factory) 工厂方法模式 (Factory Method) 抽象工厂模式 (Abstract Factory) 这三种模式从上到下逐步抽象,并且更具一般性。 GOF在《设计模式》一书中将工厂模式分为两类: 工厂方法模式 (Factory Method) 与抽象工厂模式 (Abstract Factory) 。将简单工厂模式 (Simple Factory) 看为工厂方法模式的一种特例,两者归为一类。 两者皆可,在本文使用《Java与模式》的分类方法。下面来看看这些工厂模式是怎么来"治病"的。 简单工厂模式, 简单工厂 (Simple Factory) 简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单: 定义一个用于创建对象的接口。 先来看看它的组成: 工厂类角色: 这是本模式的核心,含有一定的业务逻辑和判断逻辑。在 java 中它往往由一个具体类实现。 抽象产品角色: 它一般是具体产品继承的父类或者实现的接口。在 java 中由接口或者抽象类来实现。 具体产品角色: 工厂类所创建的对象就是此角色的实例。在 java 中由一个具体类实现。 来用类图来清晰的表示下的它们之间的关系 (如果对类图不太了解,请参考我关于类图的文章) : 那么简单工厂模式怎么来使用呢?我们就以简单工厂模式来改造老板坐车的方式——现在老板只需要坐在车里对司机说句: “开车"就可以了。 // 抽象产品 interface Car { void drive(); } // 具体产品 class Benze implements Car { public void drive() { System.out.println("Driving Benz"); } } // 具体产品 class Bmw implements Car { public void drive() { System.out.println("Driving Bmw"); } } // 工厂类 class Driver { // 工厂方法,注意返回类型为抽象产品 public static Car createCar(String s) throws Exception { // 判断逻辑,返回具体的产品角色给 Client if (s.equalsIgnoreCase("Benz")) { return new Benze(); } else if (s.equalsIgnoreCase("Bmw")) { return new Bmw(); } else { throw new Exception(); } } } // 客户端 public class Magnate { public static void main(String[] args) throws Exception { // 告诉司机我今天坐奔驰 Car car = Driver.createCar("benz"); // 下命令: 开车 car.drive(); car = Driver.createCar("bmw"); car.drive(); } } 将本程序空缺的其他信息填充完整后即可运行。如果你将所有的类放在一个文件中,请不要忘记只能有一个类被声明为public。本程序在jdk1.4 下运行通过。 ...

Created 16166-04-16 · Updated 16166-04-16 · 3 min · 440 words · -

开闭原则

开闭原则 开闭原则(Open-Close Principle/OCP)是面向对象设计中"可复用设计"的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。 1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了开闭原则,它的原文是这样: “Software entities should be open for extension,but closed for modification”。翻译过来就是: “软件实体应当对扩展开放,对修改关闭”。这句话说得略微有点专业,我们把它讲得更通俗一点,也就是: 软件系统中包含的各种组件,例如模块 (Modules) 、类 (Classes) 以及功能 (Functions) 等等,应该在不修改现有代码的基础上,引入新功能。开闭原则中"开",是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中"闭",是指对于原有代码的修改是封闭的,即不应该修改原有的代码。实现开闭原则的关键就在于"抽象"。把系统的所有可能的行为抽象成一个抽象底层,这个抽象底层规定出所有的具体实现必须提供的方法的特征。作为系统设计的抽象层,要预见所有可能的扩展,从而使得在任何扩展情况下,系统的抽象底层不需修改;同时,由于可以从抽象底层导出一个或多个新的具体实现,可以改变系统的行为,因此系统设计对扩展是开放的。 我们在软件开发的过程中,一直都是提倡需求导向的。这就要求我们在设计的时候,要非常清楚地了解用户需求,判断需求中包含的可能的变化,从而明确在什么情况下使用开闭原则。 关于系统可变的部分,还有一个更具体的对可变性封装原则 (Principle of Encapsulation of Variation, EVP) ,它从软件工程实现的角度对开闭原则进行了进一步的解释。EVP要求在做系统设计的时候,对系统所有可能发生变化的部分进行评估和分类,每一个可变的因素都单独进行封装。 我们在实际开发过程的设计开始阶段,就要罗列出来系统所有可能的行为,并把这些行为加入到抽象底层,根本就是不可能的,这么去做也是不经济的,费时费力。另外,在设计开始阶段,对所有的可变因素进行预计和封装也不太现实,也是很难做得到。所以,开闭原则描绘的愿景只是一种理想情况或是极端状态,现实世界中是很难被完全实现的。我们只能在某些组件,在某种程度上符合开闭原则的要求。 通过以上的分析,对于开闭原则,我们可以得出这样的结论: 虽然我们不可能做到百分之百的封闭,但是在系统设计的时候,我们还是要尽量做到这一点。 对于软件系统的功能扩展,我们可以通过继承、重载或者委托等手段实现。以接口为例,它对修改就是是封闭的,而对具体的实现是开放的,我们可以根据实际的需要提供不同的实现,所以接口是符合开闭原则的。如果一个软件系统符合开闭原则的,那么从软件工程的角度来看,它至少具有这样的好处: 可复用性好。 我们可以在软件完成以后,仍然可以对软件进行扩展,加入新的功能,非常灵活。因此,这个软件系统就可以通过不断地增加新的组件,来满足不断变化的需求。 可维护性好。 由于对于已有的软件系统的组件,特别是它的抽象底层不去修改,因此,我们不用担心软件系统中原有组件的稳定性,这就使变化中的软件系统有一定的稳定性和延续性。开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。因此,针对开闭原则的实现方法,一直都有面向对象设计的大师费尽心机,研究开闭原则的实现方式。后面要提到的里氏代换原则 (LSP) 、依赖倒转原则 (DIP) 、接口隔离原则 (ISP) 以及抽象类 (Abstract Class) 、接口(Interface)等等,都可以看作是开闭原则的实现方法。 http://baike.baidu.com/view/866233.htm

Created 16166-04-16 · Updated 16166-04-16 · 1 min · 53 words · -

JMM, Java Memory Model, java 内存模型

JMM, Java Memory Model, java 内存模型 Java内存模型,是指Java程序在运行时内存的模型,而Java代码是运行在Java虚拟机之上的,由Java虚拟机通过解释执行(解释器)或编译执行(即时编译器)来完成, 所以Java内存模型,也就是指Java虚拟机的运行时内存模型。 Java内存比较流行的说法便是堆和栈,这其实是非常粗略的一种划分,这种划分的"堆"对应内存模型的Java堆,“栈"是指虚拟机栈,然而Java内存模型远比这更复杂 @startuml skinparam componentStyle rectangle skinparam nodesep 10 skinparam ranksep 10 component "Java Run-time Data Areas" { [heap] component thread0 { [PC Register] as pc0 [thread stack] as ts0 [Native Method Stack] as nms0 pc0 -[hidden]-> ts0 ts0 -[hidden]-> nms0 } component thread1 { [PC Register] as pc1 [thread stack] as ts1 [Native Method Stack] as nms1 pc1 -[hidden]-> ts1 ts1 -[hidden]-> nms1 } thread0 --[hidden]--> heap thread1 --[hidden]--> heap component "method area" as ma { [constant pool] as cp } heap -[hidden]-> ma } @enduml Java 虚拟机的内存空间 (运行时数据区)分为 5 个部分: 程序计数器, PC register Java 虚拟机栈, JVM stack, 线程栈, thread stack 本地方法栈, native method stack 堆, heap 方法区, method area,方法区里面还有一个常量池 线程私有的数据区: 程序计数器,虚拟机栈,本地方法栈 所有线程共有的数据区: Java堆,方法区 ...

Created 21216-09-21 · Updated 21216-09-21 · 3 min · 596 words · -

自动装箱 拆箱

自动装箱 拆箱 Java作为面向对象语言,有人认为所看到的都是对象,事实上,在Java SE 5之前,基本类型默认并不是采用对象存在的如果您想要把基本类型作为对象来处理,就必须自行转换,不过,在Java SE 5之后,为基本数据类型提供了自动装箱和拆箱功能,使得将基本类型转换为对象变得极其便捷。 在这里来捋一捋java的基本数据类型,不理不要紧,一理才发现俺也掌握的不是那么明确,在这里俺也再次学习下 总计有八个,分别是 byte字节型 (一个字节) ,char字符型 (两个字节) ,short短整型 (两个字节) ,int整型 (四个字节) , long长整型 (八个字节) ,float浮点型 (四个字节) ,double 双精度浮点型 (八个字节) ,boolean型 (一个字节) 在javase5之前,如果想要把基本数据类型作为对象来操作,就需要采用对应的对象,来把它们打包才行 现在虽然不用这样了,但其中也有一些要注意的地方,俺揪出来晒晒。 先说说类和对象,建立个概念吧先 类-可以认为是对象的设计图 对象-是按照设计图实现了的具体工具 先这么简单理解吧,如果真要扯开了说,那可是软件工程里面的一门专业课,我们有个概念就好 之所以要将基本类型数据打包成为对象,原因很简单,是因为对象可以携带更多的数据。 手动、自动装箱拆箱示例 Long,Integer,Double,Float,Boolean等等的类就是所谓的wrapper类,就跟wrapper这个单词所代表的意思一样,就是提供一个"包装,加壳",把基本数据类型放在里面,来看代码,体会下先 public class WrapperDemo{ public staticvoid main(String[] args){ int data1=21; int data2=24; //打包成为对象 Integer data1Wrapper = new Integer(data1); Integer data2Wrapper = new Integer(data2); //原始数据直接除以3 System.out.println(data1/3); //将数据打包,转换为double型,除以3 System.out.println(data1Wrapper.doubleValue()/3); //比较 System.out.println(data1Wrapper.compareTo(data2Wrapper)); } } 图1-1 WrapperDemo的运行结果 通过上面的代码和运行结果,看到了将基本数据类型打包成为对象带来的好处了吧,别着急,这还只是javase5之前的做法,在javase5之后就已经支持自动装箱和拆箱了,在这,就不再单独写代码出来了,只写几个能说明问题的语句就可以了,相信很容易理解的。 javase5之前,手动打包 Integer data1 = new Integer(10); ...

Created 30306-06-30 · Updated 30306-06-30 · 1 min · 201 words · -

idea plugin

idea plugin java 编码规范检查 Alibaba Java Coding Guidelines idea 中统计代码行数 plugin: Statistic https://blog.csdn.net/liuchaoxuan/article/details/81270341

Created 7076-04-07 · Updated 7076-04-07 · 1 min · 13 words · -

java 开发环境

java 开发环境 jdk wiloon.com/jdk 安装 maven https://maven.apache.org/download.cgi apache-maven-3.6.3-bin.zip 安装 idea https://www.jetbrains.com/idea/download/#section=windows https://download.jetbrains.8686c.com/idea/ideaIC-2019.3.3.exe 安装 eclipse https://www.eclipse.org/downloads/packages/ Eclipse IDE for Java Developers, Windows 64-bit subclipse https://github.com/subclipse/subclipse/wiki Help>Install New Software>Add latest: https://dl.bintray.com/subclipse/releases/subclipse/latest/

Created 28286-02-28 · Updated 28286-02-28 · 1 min · 29 words · -

multi-release JAR (MR JAR)

multi-release JAR (MR JAR) https://openjdk.java.net/jeps/238 https://in.relation.to/2017/02/13/building-multi-release-jars-with-maven/

Created 1016-01-01 · Updated 1016-01-01 · 1 min · 6 words · -

netty Reactor 模式

netty Reactor模式 Reactor模式的角色构成(Reactor模式一共有5中角色构成): Handle (句柄或描述符,在Windows下称为句柄,在Linux下称为描述符):本质上表示一种资源(比如说文件描述符,或是针对网络编程中的socket描述符),是由操作系统提供的;该资源用于表示一个个的事件,事件既可以来自于外部,也可以来自于内部;外部事件比如说客户端的连接请求,客户端发送过来的数据等;内部事件比如说操作系统产生的定时事件等。它本质上就是一个文件描述符,Handle是事件产生的发源地。 Synchronous Event Demultiplexer (同步事件分离器):它本身是一个系统调用,用于等待事件的发生(事件可能是一个,也可能是多个)。调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件产生为止。对于Linux来说,同步事件分离器指的就是常用的I/O多路复用机制,比如说select、poll、epoll等。在Java NIO领域中,同步事件分离器对应的组件就是Selector;对应的阻塞方法就是select方法。 Event Handler (事件处理器):本身由多个回调方法构成,这些回调方法构成了与应用相关的对于某个事件的反馈机制。在Java NIO领域中并没有提供事件处理器机制让我们调用或去进行回调,是由我们自己编写代码完成的。Netty相比于Java NIO来说,在事件处理器这个角色上进行了一个升级,它为我们开发者提供了大量的回调方法,供我们在特定事件产生时实现相应的回调方法进行业务逻辑的处理,即,ChannelHandler。ChannelHandler中的方法对应的都是一个个事件的回调。 Concrete Event Handler (具体事件处理器):是事件处理器的实现。它本身实现了事件处理器所提供的各种回调方法,从而实现了特定于业务的逻辑。它本质上就是我们所编写的一个个的处理器实现。 Initiation Dispatcher (初始分发器):实际上就是Reactor角色。它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了应用进行事件处理器的注册、删除等设施。它本身是整个事件处理器的核心所在,Initiation Dispatcher会通过 Synchronous Event Demultiplexer 来等待事件的发生。一旦事件发生,Initiation Dispatcher 首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理这些事件。Netty中ChannelHandler 里的一个个回调方法都是由 bossGroup 或 workGroup 中的某个EventLoop来调用的。 Reactor模式流程 ① 初始化Initiation Dispatcher,然后将若干个Concrete Event Handler注册到Initiation Dispatcher中。当应用向Initiation Dispatcher注册Concrete Event Handler时,会在注册的同时指定感兴趣的事件,即,应用会标识出该事件处理器希望Initiation Dispatcher在某些事件发生时向其发出通知,事件通过Handle来标识,而Concrete Event Handler又持有该Handle。这样,事件 ————> Handle ————> Concrete Event Handler 就关联起来了。 ② Initiation Dispatcher 会要求每个事件处理器向其传递内部的Handle。该Handle向操作系统标识了事件处理器。 ③ 当所有的Concrete Event Handler都注册完毕后,应用会调用handle_events方法来启动Initiation Dispatcher的事件循环。这是,Initiation Dispatcher会将每个注册的Concrete Event Handler的Handle合并起来,并使用Synchronous Event Demultiplexer(同步事件分离器)同步阻塞的等待事件的发生。比如说,TCP协议层会使用select同步事件分离器操作来等待客户端发送的数据到达连接的socket handler上。 比如,在Java中通过Selector的select()方法来实现这个同步阻塞等待事件发生的操作。在Linux操作系统下,select()的实现中 a)会将已经注册到Initiation Dispatcher的事件调用epollCtl(epfd, opcode, fd, events)注册到linux系统中,这里fd表示Handle,events表示我们所感兴趣的Handle的事件;b)通过调用epollWait方法同步阻塞的等待已经注册的事件的发生。不同事件源上的事件可能同时发生,一旦有事件被触发了,epollWait方法就会返回;c)最后通过发生的事件找到相关联的SelectorKeyImpl对象,并设置其发生的事件为就绪状态,然后将SelectorKeyImpl放入selectedSet中。这样一来我们就可以通过Selector.selectedKeys()方法得到事件就绪的SelectorKeyImpl集合了。 ④ 当与某个事件源对应的Handle变为ready状态时(比如说,TCP socket变为等待读状态时),Synchronous Event Demultiplexer就会通知Initiation Dispatcher。 ⑤ Initiation Dispatcher会触发事件处理器的回调方法,从而响应这个处于ready状态的Handle。当事件发生时,Initiation Dispatcher会将被事件源激活的Handle作为『key』来寻找并分发恰当的事件处理器回调方法。 ⑥ Initiation Dispatcher会回调事件处理器的handle_event(type)回调方法来执行特定于应用的功能(开发者自己所编写的功能),从而相应这个事件。所发生的事件类型可以作为该方法参数并被该方法内部使用来执行额外的特定于服务的分离与分发。 ...

Created 3036-10-03 · Updated 3036-10-03 · 1 min · 186 words · -

jetty-maven-plugin, jetty maven plugin

jetty-maven-plugin, jetty maven plugin maven plugin <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.33.v20201020</version> <configuration> <stopKey>stop</stopKey> <stopPort>5599</stopPort> <webApp> <!-- <contextPath>/app0</contextPath> --> <contextPath>/</contextPath> <defaultsDescriptor>src/main/resources/webdefault.xml</defaultsDescriptor> </webApp> <scanIntervalSeconds>2</scanIntervalSeconds> [httpConnector](httpConnector) <port>8080</port> </httpConnector> </configuration> </plugin> webdefault.xml 可以去maven的本地仓库找到 .m2\repository\org\eclipse\jetty\jetty-webapp\9.4.20.v20190813 解压后在这里可以找到webdefault.xml jetty-webapp-9.4.20.v20190813\org\eclipse\jetty\webapp run mvn jetty:run mvnDebug jetty:run # 默认调试端口8000 debug - mvnDebug https://blog.wiloon.com/?p=15212 mvnDebug -suspend默认为n, https://www.eclipse.org/jetty/documentation/jetty-11/programming-guide/index.html#jetty-maven-plugin http://www.blogjava.net/fancydeepin/archive/2015/06/23/maven-jetty-plugin.html https://my.oschina.net/jackieyeah/blog/524556 https://stackoverflow.com/questions/7875002/setting-debug-configuration-for-mavenjettyeclipse

Created 6066-03-06 · Updated 6066-03-06 · 1 min · 48 words · -

ConcurrentLinkedQueue

ConcurrentLinkedQueue http://www.infoq.com/cn/articles/ConcurrentLinkedQueue 一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。 新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。 https://www.cnblogs.com/yangzhenlong/p/8359875.html ConcurrentLinkedQueue是Queue的一个安全实现.Queue中元素按FIFO原则进行排序.采用CAS操作,来保证元素的一致性。 https://blog.51cto.com/u_15259710/3193985 https://juejin.cn/post/6844903602427805704

Created 3036-01-03 · Updated 3036-01-03 · 1 min · 16 words · -

java grpc

java grpc maven依赖 <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.31.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.31.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.31.0</version> </dependency> <dependency> <!-- necessary for Java 9+ --> <groupId>org.apache.tomcat</groupId> <artifactId>annotations-api</artifactId> <version>6.0.53</version> <scope>provided</scope> </dependency> create proto file in src/main/proto/foo.proto option java_package = “com.wiloon.foo”; maven 执行 mvn compile, 就可以在target/generated-sources 下看到生成的源码了 gradle build find generated source in build/generated/source/proto/main/grpc/com/wiloon/foo/foo.java https://grpc.io/docs/quickstart/java.html https://github.com/google/protobuf-gradle-plugin https://www.jianshu.com/p/59ac036b0d7b

Created 8086-09-08 · Updated 8086-09-08 · 1 min · 55 words · -

Parallel Scavenge

Parallel Scavenge Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量 (Throughput) 。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间) ,虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户的体验;而高吞吐量则可以最高效率地利用CPU时间,尽快地完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。 Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数及直接设置吞吐量大小的 -XX:GCTimeRatio参数。 MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的时间不超过设定值。不过大家不要异想天开地认为如果把这个参数的值设置得稍小一点就能使得系统的垃圾收集速度变得更快,GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的: 系统把新生代调小一些,收集300MB新生代肯定比收集500MB快吧,这也直接导致垃圾收集发生得更频繁一些,原来10秒收集一次、每次停顿100毫秒,现在变成5秒收集一次、每次停顿70毫秒。停顿时间的确在下降,但吞吐量也降下来了。 GCTimeRatio参数的值应当是一个大于0小于100的整数,也就是垃圾收集时间占总时间的比率,相当于是吞吐量的倒数。如果把此参数设置为19,那允许的最大GC时间就占总时间的5% (即1 / (1+19) ) ,默认值为99,就是允许最大1% (即1 / (1+99) ) 的垃圾收集时间。 由于与吞吐量关系密切,Parallel Scavenge收集器也经常被称为"吞吐量优先"收集器。除上述两个参数之外,Parallel Scavenge收集器还有一个参数-XX:+UseAdaptiveSizePolicy值得关注。这是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小 (-Xmn) 、Eden与Survivor区的比例 (-XX:SurvivorRatio) 、晋升老年代对象年龄 (-XX:PretenureSizeThreshold) 等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为GC自适应的调节策略 (GC Ergonomics) 。如果读者对于收集器运作原理不太了解,手工优化存在困难的时候,使用Parallel Scavenge收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个很不错的选择。只需要把基本的内存数据设置好 (如-Xmx设置最大堆) ,然后使用MaxGCPauseMillis参数 (更关注最大停顿时间) 或GCTimeRatio参数 (更关注吞吐量) 给虚拟机设立一个优化目标,那具体细节参数的调节工作就由虚拟机完成了。自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。 HotSpot VM里多个GC有部分共享的代码。有一个分代式GC框架,Serial/Serial Old/ParNew/CMS都在这个框架内;在该框架内的young collector和old collector可以任意搭配使用,所谓的"mix-and-match"。 而ParallelScavenge与G1则不在这个框架内,而是各自采用了自己特别的框架。这是因为新的GC实现时发现原本的分代式GC框架用起来不顺手。请参考官方文档的Collector Styles一段。 ParallelScavenge (PS) 的young collector就如其名字所示,是并行的拷贝式收集器。本来这个young collector就是"Parallel Scavenge"所指,但因为它不兼容原本的分代式GC框架,为了凸显出它是不同的,所以它的young collector带上了PS前缀,全名变成PS Scavenge。对应的,它的old collector的名字也带上了PS前缀,叫做PS MarkSweep。 这个PS MarkSweep默认的实现实际上是一层皮,它底下真正做mark-sweep-compact工作的代码是跟分代式GC框架里的serial old (这个collector名字叫做MarkSweepCompact) 是共用同一份代码的。也就是说实际上PS MarkSweep与MarkSweepCompact在HotSpot VM里是同一个collector实现,包了两张不同的皮;这个collector是串行的。 ...

Created 5056-06-05 · Updated 5056-06-05 · 1 min · 153 words · -

java maven 可执行 jar/ executable jar, maven-assembly-plugin

java maven 可执行 jar/ executable jar, maven-assembly-plugin 在pom中加入 maven-assembly-plugin <project> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.wiloon.java.lock.TestFutex</mainClass> </manifest> </archive> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> mvn clean package assembly:single # 如果没执行过 mvn package 会报错: Cannot include project artifact: com.wiloon.java:pingd-java:jar:1.0-SNAPSHOT; it doesn't have an associated file or directory. java -jar target/pingd-java-1.0-SNAPSHOT-jar-with-dependencies.jar

Created 16166-12-16 · Updated 16166-12-16 · 1 min · 63 words · -