cc.concurrent.mango.Mango Maven / Gradle / Ivy
/*
* Copyright 2014 mango.concurrent.cc
*
* The Mango Project licenses this file to you 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 cc.concurrent.mango;
import cc.concurrent.mango.exception.IncorrectAnnotationException;
import cc.concurrent.mango.runtime.DataSourceFactoryHolder;
import cc.concurrent.mango.runtime.operator.*;
import cc.concurrent.mango.util.ToStringHelper;
import cc.concurrent.mango.util.concurrent.CacheLoader;
import cc.concurrent.mango.util.concurrent.DoubleCheckCache;
import cc.concurrent.mango.util.concurrent.LoadingCache;
import cc.concurrent.mango.util.logging.InternalLogger;
import cc.concurrent.mango.util.logging.InternalLoggerFactory;
import cc.concurrent.mango.util.reflect.AbstractInvocationHandler;
import cc.concurrent.mango.util.reflect.Reflection;
import javax.annotation.Nullable;
import javax.sql.DataSource;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* mango框架DAO工厂
*
* @author ash
*/
public class Mango {
private final static InternalLogger logger = InternalLoggerFactory.getInstance(Mango.class);
private final DataSourceFactoryHolder dataSourceFactoryHolder;
private final CacheHandler defaultCacheHandler;
private final ConcurrentHashMap statsCounterMap;
public Mango(DataSource dataSource) {
this(new SimpleDataSourceFactory(dataSource));
}
public Mango(DataSourceFactory dataSourceFactory) {
this(dataSourceFactory, null);
}
public Mango(DataSource dataSource, CacheHandler defaultCacheHandler) {
this(new SimpleDataSourceFactory(dataSource), defaultCacheHandler);
}
public Mango(DataSourceFactory dataSourceFactory, CacheHandler defaultCacheHandler) {
this.dataSourceFactoryHolder = new DataSourceFactoryHolder(dataSourceFactory);
this.defaultCacheHandler = defaultCacheHandler;
this.statsCounterMap = new ConcurrentHashMap();
}
/**
* 创建代理DAO类
*/
public T create(Class daoClass) {
return create(daoClass, null);
}
/**
* 创建代理DAO类,并对该类使用特定的{@link CacheHandler}
*/
public T create(Class daoClass, @Nullable CacheHandler cacheHandler) {
if (daoClass == null) {
throw new NullPointerException("dao interface can't be null");
}
DB dbAnno = daoClass.getAnnotation(DB.class);
if (dbAnno == null) {
throw new IncorrectAnnotationException("dao interface expected one cc.concurrent.mango.DB " +
"annotation but not found");
}
if (cacheHandler == null) {
cacheHandler = defaultCacheHandler;
}
return Reflection.newProxy(daoClass,
new MangoInvocationHandler(dataSourceFactoryHolder, cacheHandler, statsCounterMap));
}
/**
* 返回各个方法对应的状态
*/
public Map getStatsMap() {
Set> entrySet = statsCounterMap.entrySet();
Map map = new HashMap();
for (Map.Entry entry : entrySet) {
map.put(entry.getKey(), entry.getValue().snapshot());
}
return map;
}
/**
* 设置新的{@link DataSourceFactory},实时生效
*/
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
dataSourceFactoryHolder.set(dataSourceFactory);
}
/**
* 获得正在使用的{@link DataSourceFactory}
*/
public DataSourceFactory getDataSourceFactory() {
return dataSourceFactoryHolder.get();
}
private static class MangoInvocationHandler extends AbstractInvocationHandler implements InvocationHandler {
private final DataSourceFactoryHolder dataSourceFactoryHolder;
private final CacheHandler cacheHandler;
private final ConcurrentHashMap statsCounterMap;
private MangoInvocationHandler(DataSourceFactoryHolder dataSourceFactoryHolder,
@Nullable CacheHandler cacheHandler,
ConcurrentHashMap statsCounterMap) {
this.dataSourceFactoryHolder = dataSourceFactoryHolder;
this.cacheHandler = cacheHandler;
this.statsCounterMap = statsCounterMap;
}
private final LoadingCache cache = new DoubleCheckCache(
new CacheLoader() {
public CacheableOperator load(Method method) throws Exception {
StatsCounter statsCounter = getStatusCounter(method);
long now = System.nanoTime();
CacheableOperator operator = OperatorFactory.getOperator(method);
statsCounter.recordInit(System.nanoTime() - now);
operator.setDataSourceFactoryHolder(dataSourceFactoryHolder);
operator.setCacheHandler(cacheHandler);
operator.setStatsCounter(statsCounter);
return operator;
}
});
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
if (logger.isDebugEnabled()) {
logger.debug("{} #args={}", ToStringHelper.toString(method), args);
}
Operator operator = cache.get(method);
Object r = operator.execute(args);
if (logger.isDebugEnabled()) {
logger.debug("{} #result={}", ToStringHelper.toString(method), r);
}
return r;
}
private StatsCounter getStatusCounter(Method method) {
StatsCounter statsCounter = statsCounterMap.get(method);
if (statsCounter == null) {
statsCounter = new SimpleStatsCounter();
StatsCounter old = statsCounterMap.putIfAbsent(method, statsCounter);
if (old != null) { // 已经存在,就用老的,这样能保证单例
statsCounter = old;
}
}
return statsCounter;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy