/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache;
import java.util.concurrent.locks.ReadWriteLock;
/**
* SPI for cache providers. 为缓存提供者的接口(SPI:串行外设接口。)
*
* One instance of cache will be created for each namespace. 每个命名空间都会创建一个缓存的实例对象
*
* The cache implementation must have a constructor that receives the cache id as an String parameter.
* 继承{@link Cache}的实现类必须有一个可接收一个缓存ID的String类型参数的构造函数
*
* MyBatis will pass the namespace as id to the constructor.
* Mybatis会将命名空间作为id传入构造方法
*
*
* public MyCache(final String id) {
* if (id == null) {
* throw new IllegalArgumentException("Cache instances require an ID");
* }
* this.id = id;
* initialize();
* }
*
* @author Clinton Begin
*/
public interface Cache {
/**
* 获取缓存对象的唯一标识,一般是Mapper.xml的命名空间
* @return The identifier of this cache
*/
String getId();
/**
* 保存key/value到缓存对象中
* @param key Can be any object but usually it is a {@link CacheKey} 可以是任何对象,但一般是CacheKey对象
* @param value The result of a select. 查询结果
*/
void putObject(Object key, Object value);
/**
* 从缓存对象中获取key对应的value
* @param key The key
* @return The object stored in the cache.
*/
Object getObject(Object key);
/**
*
* 移除key对应的value
*
* As of 3.3.0 this method is only called during a rollback
* for any previous value that was missing in the cache.
* This lets any blocking cache to release the lock that
* may have previously put on the key.
* A blocking cache puts a lock when a value is null
* and releases it when the value is back again.
* This way other threads will wait for the value to be
* available instead of hitting the database.
* 在3.3.0后,这个方法只是在回滚在缓存中丢失了的任何之前的值。
* 这使得任何一个阻塞缓存释放可能之前写入键的锁。
* 一个阻塞缓存当值为null时加一个锁,在值再次后台时释放这个所。
* 这样其他线程会等待可用的价值,而不是数据库。
* @param key The key
* @return Not used
*/
Object removeObject(Object key);
/**
* Clears this cache instance.
* 清空缓存
*/
void clear();
/**
* Optional. This method is not called by the core.
* 获取缓存对象中存储的键/值对的数量
* @return The number of elements stored in the cache (not its capacity).
*/
int getSize();
/**
* 获取读写锁,这个方法mybatis的所有Cache实现类都没有重写过,都是直接返回null
*
* 从3.2.6起这个方法不再被框架核心调用,任何需要的锁,都必须由缓存供应商提供
*
* Optional. As of 3.2.6 this method is no longer called by the core.
*
* Any locking needed by the cache must be provided internally by the cache provider.
*
* @return A ReadWriteLock
*/
ReadWriteLock getReadWriteLock();
}
PerpetualCache
/**
* Copyright 2009-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
/**
* 永久缓存 Cache接口实现类,里面就是维护着一个HashMap
*
* Cache接口只有这唯一一个基础实现,其他实现类全都是装饰模式持有另一个缓存对象
*
* @author Clinton Begin
*/
public class PerpetualCache implements Cache {
/**
* 缓存对象的唯一标识
*/
private final String id;
/**
* 对象内部维护的HashMap,缓存Map
*/
private Map
FifoCache
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
/**
* FIFO (first in, first out) cache decorator.
* 使用先进先出缓存策略的缓存装饰类
* @author Clinton Begin
*/
public class FifoCache implements Cache {
/**
* 委托Cache对象
*/
private final Cache delegate;
/**
* 键列表
*
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
/**
* Lru (least recently used) cache decorator.
* 使用最近最少使用的缓存策略的缓存装饰类
* @author Clinton Begin
*/
public class LruCache implements Cache {
/**
* 真正存放缓存数据的Cache对象,委托类
*/
private final Cache delegate;
/**
* 记录着每个key的访问次数
*/
private Map
SoftCache
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
/**
* Soft Reference cache decorator
* Thanks to Dr. Heinz Kabutz for his guidance here.
* 软引用回收策略 缓存装饰类
*
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
/**
* Weak Reference cache decorator.
* Thanks to Dr. Heinz Kabutz for his guidance here.
*
* @author Clinton Begin
*/
public class WeakCache implements Cache {
/**
*
*/
private final Deque hardLinksToAvoidGarbageCollection;
private final ReferenceQueue queueOfGarbageCollectedEntries;
private final Cache delegate;
private int numberOfHardLinks;
public WeakCache(Cache delegate) {
this.delegate = delegate;
this.numberOfHardLinks = 256;
this.hardLinksToAvoidGarbageCollection = new LinkedList<>();
this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
removeGarbageCollectedItems();
return delegate.getSize();
}
public void setSize(int size) {
this.numberOfHardLinks = size;
}
@Override
public void putObject(Object key, Object value) {
removeGarbageCollectedItems();
delegate.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries));
}
@Override
public Object getObject(Object key) {
Object result = null;
@SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
WeakReference weakReference = (WeakReference) delegate.getObject(key);
if (weakReference != null) {
result = weakReference.get();
if (result == null) {
delegate.removeObject(key);
} else {
hardLinksToAvoidGarbageCollection.addFirst(result);
if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
hardLinksToAvoidGarbageCollection.removeLast();
}
}
}
return result;
}
@Override
public Object removeObject(Object key) {
removeGarbageCollectedItems();
return delegate.removeObject(key);
}
@Override
public void clear() {
hardLinksToAvoidGarbageCollection.clear();
removeGarbageCollectedItems();
delegate.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
private void removeGarbageCollectedItems() {
WeakEntry sv;
while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null) {
delegate.removeObject(sv.key);
}
}
private static class WeakEntry extends WeakReference {
private final Object key;
private WeakEntry(Object key, Object value, ReferenceQueue garbageCollectionQueue) {
super(value, garbageCollectionQueue);
this.key = key;
}
}
}
LoggingCache
/**
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
/**
* 日志功能,装饰类,用于记录缓存的命中率,如果开启了DEBUG模式,则会输出命中率日志。
*
/**
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
/**
* 定时清空Cache,但是并没有开始一个定时任务,而是在使用Cache的时候,才去检查时间是否到了。
*
* @author Clinton Begin
*/
public class ScheduledCache implements Cache {
private final Cache delegate;
/**
* 清除缓存数据的时间间隔,初始化为1小时
*/
protected long clearInterval;
/**
* 上一次清除的时间,初始化时赋值当前时间
*/
protected long lastClear;
public ScheduledCache(Cache delegate) {
this.delegate = delegate;
this.clearInterval = 60 * 60 * 1000; // 1 hour
this.lastClear = System.currentTimeMillis();
}
public void setClearInterval(long clearInterval) {
this.clearInterval = clearInterval;
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
clearWhenStale();
return delegate.getSize();
}
@Override
public void putObject(Object key, Object object) {
clearWhenStale();
delegate.putObject(key, object);
}
@Override
public Object getObject(Object key) {
return clearWhenStale() ? null : delegate.getObject(key);
}
@Override
public Object removeObject(Object key) {
clearWhenStale();
return delegate.removeObject(key);
}
/**
* 清空所有缓存数据
*/
@Override
public void clear() {
lastClear = System.currentTimeMillis();//记录当前时间
delegate.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
/**
* 判断是否到了清空数据的时间
*/
private boolean clearWhenStale() {
if (System.currentTimeMillis() - lastClear > clearInterval) {
clear();
return true;
}
return false;
}
}
SerializedCache
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
import org.apache.ibatis.io.Resources;
/**
* 序列化功能,将值序列化后存到缓存中。该功能用于缓存返回一份实例的Copy,用于保存线程安全。
*
* @author Clinton Begin
*/
public class SerializedCache implements Cache {
private final Cache delegate;
public SerializedCache(Cache delegate) {
this.delegate = delegate;
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
return delegate.getSize();
}
@Override
public void putObject(Object key, Object object) {
if (object == null || object instanceof Serializable) {
// 先序列化后再存放到缓存中
delegate.putObject(key, serialize((Serializable) object));
} else {
throw new CacheException("SharedCache failed to make a copy of a non-serializable object: " + object);
}
}
@Override
public Object getObject(Object key) {
Object object = delegate.getObject(key);
// 不为空,则反序列化,生成一份Copy
return object == null ? null : deserialize((byte[]) object);
}
@Override
public Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
/**
* 序列化
*/
private byte[] serialize(Serializable value) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(value);
oos.flush();
return bos.toByteArray();
} catch (Exception e) {
throw new CacheException("Error serializing object. Cause: " + e, e);
}
}
// 反序列化
private Serializable deserialize(byte[] value) {
Serializable result;
try (ByteArrayInputStream bis = new ByteArrayInputStream(value);
ObjectInputStream ois = new CustomObjectInputStream(bis)) {
result = (Serializable) ois.readObject();
} catch (Exception e) {
throw new CacheException("Error deserializing object. Cause: " + e, e);
}
return result;
}
public static class CustomObjectInputStream extends ObjectInputStream {
public CustomObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected Class> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
// 此方法只有在待序列化的类第一次序列化的时候才会被调用
// 遍历所支持的ClassLoader,加载对应的Class
return Resources.classForName(desc.getName());
}
}
}
SynchronizedCache
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
/**
* 同步Cache,实现比较简单,直接使用synchronized修饰方法。
* @author Clinton Begin
*/
public class SynchronizedCache implements Cache {
private final Cache delegate;
public SynchronizedCache(Cache delegate) {
this.delegate = delegate;
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public synchronized int getSize() {
return delegate.getSize();
}
@Override
public synchronized void putObject(Object key, Object object) {
delegate.putObject(key, object);
}
@Override
public synchronized Object getObject(Object key) {
return delegate.getObject(key);
}
@Override
public synchronized Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public synchronized void clear() {
delegate.clear();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}
TransactionalCache
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.cache.decorators;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
/**
* The 2nd level cache transactional buffer.2级缓存事务缓冲区
*
* This class holds all cache entries that are to be added to the 2nd level cache during a Session.
* Entries are sent to the cache when commit is called or discarded if the Session is rolled back.
* Blocking cache support has been added. Therefore any get() that returns a cache miss
* will be followed by a put() so any lock associated with the key can be released.
* 这个类保留着所有在对话期间被添加到二级缓存的缓存数据。缓存数据在事务提交后会被传入二级缓存中,或者在事务会话回退后被丢弃。
* 阻塞着已经添加缓存的缓存数据,因此任何get()方法返回出来的缓存丢失,会随后将由put(),所以任何的和对应的key关联的锁可以被释放掉。
*
原文地址:http://www.open-open.com/lib/view/open1346857871615.html
使用Java Mail API来发送邮件也很容易实现,但是最近公司一个同事封装的邮件API实在让我无法接受,于是便打算改用Spring Mail API来发送邮件,顺便记录下这篇文章。 【Spring Mail API】
Spring Mail API都在org.spri