Memcached 简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的 API 兼容大部分流行的开发语言。本质上,它是一个简洁的 key-value 存储系统。
Memcached 特性
memcached 作为高速运行的分布式缓存服务器,具有以下的特点。
协议简单
基于 libevent 的事件处理
内置内存存储方式
memcached 不互相通信的分布式
Memcached 命令
可以通过 telnet 命令并指定主机 ip 和端口来连接 Memcached 服务。
1 2 3 4 5 6 7 8 9 10 11 12 13
telnet 127.0.0.111211
Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. set foo 0 0 3 保存命令 bar 数据 STORED 结果 get foo 取得命令 VALUE foo 0 3 数据 bar 数据 END 结束行 quit 退出
Java 连接 Memcached
使用 Java 程序连接 Memcached,需要在你的 classpath 中添加 Memcached jar 包。
<!-- Add an EnvEntry only valid for this webapp --> <Newid="gargle"class="org.eclipse.jetty.plus.jndi.EnvEntry"> <Arg>gargle</Arg> <Argtype="java.lang.Double">100</Arg> <Argtype="boolean">true</Arg> </New>
<!-- Add an override for a global EnvEntry --> <Newid="wiggle"class="org.eclipse.jetty.plus.jndi.EnvEntry"> <Arg>wiggle</Arg> <Argtype="java.lang.Double">55.0</Arg> <Argtype="boolean">true</Arg> </New>
HandlerCollection 其实维护了一个 Handler 数组。这是为了同时支持多个 Web 应用,如果每个 Web 应用有一个 Handler 入口,那么多个 Web 应用的 Handler 就成了一个数组,比如 Server 中就有一个 HandlerCollection,Server 会根据用户请求的 URL 从数组中选取相应的 Handler 来处理,就是选择特定的 Web 应用来处理请求。
将 I/O 事件检测和业务处理这两种工作分开的思路也有缺点:当 Selector 检测读就绪事件时,数据已经被拷贝到内核中的缓存了,同时 CPU 的缓存中也有这些数据了,我们知道 CPU 本身的缓存比内存快多了,这时当应用程序去读取这些数据时,如果用另一个线程去读,很有可能这个读线程使用另一个 CPU 核,而不是之前那个检测数据就绪的 CPU 核,这样 CPU 缓存中的数据就用不上了,并且线程切换也需要开销。
因此 Jetty 的 Connector 做了一个大胆尝试,那就是把 I/O 事件的生产和消费放到同一个线程来处理,如果这两个任务由同一个线程来执行,如果执行过程中线程不阻塞,操作系统会用同一个 CPU 核来执行这两个任务,这样就能利用 CPU 缓存了。
ProduceExecuteConsume:任务生产者开启新线程来运行任务,这是典型的 I/O 事件侦测和处理用不同的线程来处理,缺点是不能利用 CPU 缓存,并且线程切换成本高。同样我们通过一张图来理解,图中的棕色表示线程切换。
ExecuteProduceConsume:任务生产者自己运行任务,但是该策略可能会新建一个新线程以继续生产和执行任务。这种策略也被称为“吃掉你杀的猎物”,它来自狩猎伦理,认为一个人不应该杀死他不吃掉的东西,对应线程来说,不应该生成自己不打算运行的任务。它的优点是能利用 CPU 缓存,但是潜在的问题是如果处理 I/O 事件的业务代码执行时间过长,会导致线程大量阻塞和线程饥饿。
// without annotation, we'd get "theName", but we want "name": @JsonProperty("name") public String getTheName() { return _name; }
// note: it is enough to add annotation on just getter OR setter; // so we can omit it here publicvoidsetTheName(String n) { _name = n; } }
@JsonIgnoreProperties 和 @JsonIgnore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// means that if we see "foo" or "bar" in JSON, they will be quietly skipped // regardless of whether POJO has such properties @JsonIgnoreProperties({ "foo", "bar" }) publicclassMyBean { // will not be written as JSON; nor assigned from JSON: @JsonIgnore public String internal;
// no annotation, public field is read/written normally public String external;
@JsonIgnore publicvoidsetCode(int c) { _code = c; }
// note: will also be ignored because setter has annotation! publicintgetCode() { return _code; } }
//不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册) kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
//Fix the NPE bug when deserializing Collections. ((DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()) .setFallbackInstantiatorStrategy(newStdInstantiatorStrategy());
@java.lang.Override publicbooleanequals(final java.lang.Object o) { if (o == this) returntrue; if (o == null) returnfalse; if (o.getClass() != this.getClass()) returnfalse; if (!super.equals(o)) returnfalse; finalPersonother= (Person)o; if (this.name == null ? other.name != null : !this.name.equals(other.name)) returnfalse; if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) returnfalse; if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) returnfalse; returntrue; }
@java.lang.Override publicinthashCode() { finalintPRIME=31; intresult=1; result = result * PRIME + super.hashCode(); result = result * PRIME + (this.name == null ? 0 : this.name.hashCode()); result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode()); result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode()); return result; } }
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `io.github.dunwu.javatech.bean.lombok.BuilderDemo01` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"name":"demo01"}"; line: 1, column: 2] at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1432) at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1062) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182) at io.github.dunwu.javatech.bean.lombok.BuilderDemo01.main(BuilderDemo01.java:22)
String to Complex Type if the Complex Type contains a String constructor
字符串和有字符串构造器的复杂类型(类)
String to Map
字符串和 Map
Collection to Collection
集合和集合
Collection to Array
集合和数组
Map to Complex Type
Map 和复杂类型
Map to Custom Map Type
Map 和定制 Map 类型
Enum to Enum
枚举和枚举
Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar
<!-- You are responsible for mapping everything between ClassA and ClassB --> <converter type="org.dozer.converters.TestCustomHashMapConverter" > <class-a>org.dozer.vo.TestCustomConverterHashMapObject</class-a> <class-b>org.dozer.vo.TestCustomConverterHashMapPrimeObject</class-b> </converter> </custom-converters> </configuration> </mappings>