com.github.mybatis.spring.MapperFactoryBean Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mybatis-spring-support Show documentation
Show all versions of mybatis-spring-support Show documentation
using mybatis lib, add spring support
The newest version!
package com.github.mybatis.spring;
/*
* Copyright 2010-2012 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.
*/
import com.github.mybatis.entity.IdEntity;
import com.github.trace.TraceContext;
import com.github.trace.TraceRecorder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.Reflection;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.*;
import static org.springframework.util.Assert.notNull;
/**
* BeanFactory that enables injection of MyBatis mapper interfaces. It can be set up with a
* SqlSessionFactory or a pre-configured SqlSessionTemplate.
*
* Sample configuration:
*
*
* {@code
*
*
*
*
*
*
*
*
*
*
*
* }
*
*
* Note that this factory can only inject interfaces, not concrete classes.
*
* @author Eduardo Macarron
* @version $Id$
* @see org.mybatis.spring.SqlSessionTemplate
*/
public class MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {
private static final Logger LOG = LoggerFactory.getLogger(MapperFactoryBean.class);
private static final TimeZone CHINA_ZONE = TimeZone.getTimeZone("GMT+08:00");
private static final Locale CHINA_LOCALE = Locale.CHINA;
private static final Set NAMES = ImmutableSet.of("Boolean", "Character", "Byte", "Short", "Long", "Integer", "Byte", "Float", "Double", "Void", "String");
private Class mapperInterface;
private String iface;
private boolean addToConfig = true;
/**
* Sets the mapper interface of the MyBatis mapper
*
* @param mapperInterface class of the interface
*/
public void setMapperInterface(Class mapperInterface) {
this.mapperInterface = mapperInterface;
this.iface = mapperInterface.getSimpleName();
}
/**
* If addToConfig is false the mapper will not be added to MyBatis. This means
* it must have been included in mybatis-config.xml.
*
* If it is true, the mapper will be added to MyBatis in the case it is not already
* registered.
*
* By default addToCofig is true.
*
* @param addToConfig
*/
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
/**
* {@inheritDoc}
*/
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Throwable t) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);
throw new IllegalArgumentException(t);
} finally {
ErrorContext.instance().reset();
}
}
}
/**
* {@inheritDoc}
*/
public T getObject() throws Exception {
final T mapper = getSqlSession().getMapper(this.mapperInterface);
return Reflection.newProxy(this.mapperInterface, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
TraceContext rpc = TraceContext.get();
String parameters = getParameters(args);
String iface = MapperFactoryBean.this.iface;
rpc.reset().inc().setStamp(start).setIface(iface).setMethod(method.getName()).setParameter(parameters);
try {
return method.invoke(mapper, args);
} catch (Exception e) {
rpc.setFail(true).setReason(e.getMessage());
LOG.error("{}.{}({})", iface, method.getName(), parameters, e);
throw e;
} finally {
rpc.setCost(System.currentTimeMillis() - start);
TraceRecorder.getInstance().post(rpc.copy());
}
}
});
}
/**
* {@inheritDoc}
*/
public Class getObjectType() {
return this.mapperInterface;
}
/**
* {@inheritDoc}
*/
public boolean isSingleton() {
return false;
}
/**
* 函数参数信息
*
* @param args 参数列表
* @return 格式化输出
*/
protected String getParameters(Object[] args) {
if (args == null)
return "";
StringBuilder sbd = new StringBuilder();
if (args.length > 0) {
for (Object i : args) {
if (i == null) {
sbd.append("null");
} else {
Class clz = i.getClass();
if (isPrimitive(clz)) {
sbd.append(evalPrimitive(i));
} else if (clz.isArray()) {
evalArray(i, sbd);
} else if (Collection.class.isAssignableFrom(clz)) {
Object[] arr = ((Collection>) i).toArray();
evalArray(arr, sbd);
} else if (i instanceof Date) {
sbd.append('"').append(formatYmdHis(((Date) i))).append('"');
} else if (i instanceof IdEntity) {
sbd.append(i.getClass().getSimpleName()).append("[id=").append(((IdEntity) i).getId()).append(']');
}else {
sbd.append(clz.getSimpleName()).append(":OBJ");
}
}
sbd.append(',');
}
sbd.setLength(sbd.length() - 1);
}
return sbd.toString();
}
private static boolean isPrimitive(Class clz) {
return clz.isPrimitive() || NAMES.contains(clz.getSimpleName());
}
private String evalPrimitive(Object obj) {
String s = String.valueOf(obj);
if (s.length() > 32) {
return s.substring(0, 32) + "...";
}
return s;
}
private void evalArray(Object arr, StringBuilder sbd) {
int sz = Array.getLength(arr);
if (sz == 0) {
sbd.append("[]");
return;
}
Class> clz = Array.get(arr, 0).getClass();
if (clz == Byte.class) {
sbd.append("Byte[").append(sz).append(']');
return;
}
if (isPrimitive(clz)) {
sbd.append('[');
int len = Math.min(sz, 10);
for (int i = 0; i < len; i++) {
Object obj = Array.get(arr, i);
if (isPrimitive(obj.getClass())) {
sbd.append(evalPrimitive(obj));
} else {
sbd.append(obj.getClass().getSimpleName()).append(":OBJ");
}
sbd.append(',');
}
if (sz > 10) {
sbd.append(",...,len=").append(sz);
}
if (sbd.charAt(sbd.length() - 1) == ',') {
sbd.setCharAt(sbd.length() - 1, ']');
} else {
sbd.append(']');
}
} else {
sbd.append("[len=").append(sz).append(']');
}
}
/**
* 构造时间的显示,带上时分秒的信息,如 2013-06-11 03:14:25
*
* @param date 时间
* @return 字符串表示
*/
private String formatYmdHis(Date date) {
Calendar ca = Calendar.getInstance(CHINA_ZONE, CHINA_LOCALE);
ca.setTimeInMillis(date.getTime());
StringBuilder sbd = new StringBuilder();
sbd.append(ca.get(Calendar.YEAR)).append('-');
int month = 1 + ca.get(Calendar.MONTH);
if (month < 10) {
sbd.append('0');
}
sbd.append(month).append('-');
int day = ca.get(Calendar.DAY_OF_MONTH);
if (day < 10) {
sbd.append('0');
}
sbd.append(day).append(' ');
int hour = ca.get(Calendar.HOUR_OF_DAY);
if (hour < 10) {
sbd.append('0');
}
sbd.append(hour).append(':');
int minute = ca.get(Calendar.MINUTE);
if (minute < 10) {
sbd.append('0');
}
sbd.append(minute).append(':');
int second = ca.get(Calendar.SECOND);
if (second < 10) {
sbd.append('0');
}
sbd.append(second);
return sbd.toString();
}
protected Object findDefault(Method method) {
Class> clz = method.getReturnType();
if (clz == String.class) {
return "";
} else if (clz == Long.class || clz == Double.class) {
return 0L;
} else if (clz == Boolean.class) {
return Boolean.FALSE;
} else if (clz.isArray()) {
return new byte[0];
} else if (clz.isAssignableFrom(Set.class)) {
return ImmutableSet.of();
} else if (clz.isAssignableFrom(List.class)) {
return ImmutableList.of();
} else if (clz.isAssignableFrom(Map.class)) {
return ImmutableMap.of();
} else {
return null;
}
}
}