Commit 78f7fb17 authored by 雍欢's avatar 雍欢

生成QueryRequest的方法抽象成接口,并提供cglib和javassist两种实现方式

parent 452da19b
......@@ -46,6 +46,12 @@
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.24.0-GA</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
......
package com.topsunit.query.binding;
import com.huigou.data.domain.query.QueryAbstractRequest;
import com.topsunit.query.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author yonghuan
*/
public abstract class AbstractQueryRequestFactory implements QueryRequestFactory {
private final static Logger LOG = LoggerFactory.getLogger(AbstractQueryRequestFactory.class);
@Override
public QueryAbstractRequest getQueryRequest(Method method, Object[] args) {
long startTime = System.currentTimeMillis();
QueryAbstractRequest queryRequest = newInstance(method, args);
LOG.info("为查询方法 {}.{} 生成QueryRequest,共花费{}毫秒", method.getClass().getName(), method.getName(), System.currentTimeMillis() - startTime);
PropertyDescriptor[] propertyDescriptors;
try {
propertyDescriptors = Introspector.getBeanInfo(queryRequest.getClass()).getPropertyDescriptors();
} catch (IntrospectionException ie) {
throw new IllegalArgumentException(ie);
}
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
String paramName = paramAnnotation.value();
PropertyDescriptor propertyDescriptor = Stream.of(propertyDescriptors)
.filter(pd -> pd.getName().equals(paramName))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(String.format("无法匹配查询参数 %s", paramName)));
Object paramVal = args[i];
if (paramVal instanceof Collection) {
Collection<?> items = (Collection<?>) paramVal;
paramVal = items.stream().map(String::valueOf).collect(Collectors.joining(","));
}
try {
propertyDescriptor.getWriteMethod().invoke(queryRequest, paramVal);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException(String.format("绑定参数 paramName=%s,paramValue=%s 时候出错", paramName, paramVal), e);
}
}
}
return queryRequest;
}
protected abstract QueryAbstractRequest newInstance(Method method, Object[] args);
}
package com.topsunit.query.binding;
import com.huigou.data.domain.query.QueryAbstractRequest;
import com.topsunit.query.annotations.Param;
import net.sf.cglib.beans.BeanGenerator;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
/**
* 利用cblib生成QueryRequest对象。
*
* @author yonghuan
*/
public class CglibQueryRequestFactory extends AbstractQueryRequestFactory implements QueryRequestFactory {
@Override
protected QueryAbstractRequest newInstance(Method method, Object[] args) {
BeanGenerator queryGenerator = new BeanGenerator();
queryGenerator.setSuperclass(QueryAbstractRequest.class);
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
Class parameterType = parameter.getType();
if (Collection.class.isAssignableFrom(parameterType)) {
parameterType = String.class;
}
queryGenerator.addProperty(paramAnnotation.value(), parameterType);
}
}
QueryAbstractRequest queryRequest = (QueryAbstractRequest) queryGenerator.create();
return queryRequest;
}
}
package com.topsunit.query.binding;
import com.huigou.data.domain.query.QueryAbstractRequest;
import com.topsunit.query.annotations.Param;
import javassist.*;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
/**
* 利用Javassist生成QueryRequest对象。
*
* @author yonghuan
*/
public class JavassistQueryRequestFactory extends AbstractQueryRequestFactory implements QueryRequestFactory {
@Override
protected QueryAbstractRequest newInstance(Method method, Object[] args) {
try {
Class<?> clazz = getClass(method);
return (QueryAbstractRequest) clazz.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
private Class<?> getClass(Method method) throws NotFoundException, CannotCompileException {
ClassPool classPool = new ClassPool(true);
classPool.insertClassPath(new LoaderClassPath(JavassistQueryRequestFactory.class.getClassLoader()));
String className = method.getDeclaringClass().getPackage().getName() + "." + method.getName() + "QueryRequest";
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
}
CtClass cc = classPool.makeClass(className);
cc.setSuperclass(classPool.get("com.huigou.data.domain.query.QueryAbstractRequest"));
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
Class parameterType = parameter.getType();
if (Collection.class.isAssignableFrom(parameterType)) {
parameterType = String.class;
}
String propertyName = paramAnnotation.value();
CtField cf = CtField.make(String.format("private %s %s;", parameterType.getName(), propertyName), cc);
cc.addField(cf);
String upperCamelCaseName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
CtMethod setter = CtMethod.make(String.format("public void set%s(%s %s){ this.%s = %s; }", upperCamelCaseName, parameterType.getName(), propertyName, propertyName, propertyName), cc);
cc.addMethod(setter);
CtMethod getter = CtMethod.make(String.format("public %s get%s(){ return this.%s; }", parameterType.getName(), upperCamelCaseName, propertyName), cc);
cc.addMethod(getter);
}
}
return cc.toClass();
}
}
......@@ -23,7 +23,7 @@ public class MapperProxy<T> implements InvocationHandler {
invokeStrategies.add(new SelectSqlInvokeStrategy(new DefaultSqlTranslator(), new DefaultParameterParser()));
invokeStrategies.add(new ObtainSqlInvokeStrategy());
invokeStrategies.add(new ObtainQueryDescriptorInvokeStrategy());
invokeStrategies.add(new SqlQueryInvokeStrategy());
invokeStrategies.add(new SqlQueryInvokeStrategy(new CglibQueryRequestFactory()));
}
......
......@@ -4,7 +4,6 @@ import com.huigou.data.query.model.QueryDescriptor;
import com.topsunit.query.annotations.Select;
import com.topsunit.query.annotations.Sql;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
......
package com.topsunit.query.binding;
import com.huigou.data.domain.query.QueryAbstractRequest;
import java.lang.reflect.Method;
/**
* @author yonghuan
*/
public interface QueryRequestFactory {
QueryAbstractRequest getQueryRequest(Method method, Object[] args);
}
......@@ -35,6 +35,12 @@ import java.util.stream.Stream;
*/
final class SqlQueryInvokeStrategy implements InvokeStrategy {
private final QueryRequestFactory queryRequestFactory;
public SqlQueryInvokeStrategy(QueryRequestFactory queryRequestFactory) {
this.queryRequestFactory = queryRequestFactory;
}
@Override
public boolean supports(InvokeContext invokeContext, Method method, Object[] args) {
return true;
......@@ -51,7 +57,7 @@ final class SqlQueryInvokeStrategy implements InvokeStrategy {
throw new IllegalArgumentException("只能设置一个自定QueryRequest");
}
if (requests.isEmpty()) {
requests.add(generateQueryProxy(method, args));
requests.add(queryRequestFactory.getQueryRequest(method, args));
}
QueryAbstractRequest query = requests.get(0);
......@@ -91,48 +97,4 @@ final class SqlQueryInvokeStrategy implements InvokeStrategy {
throw new IllegalArgumentException(String.format("无法转换查询结果集为:%s", retType.getName()));
}
private QueryAbstractRequest generateQueryProxy(Method method, Object[] args) {
BeanGenerator queryGenerator = new BeanGenerator();
queryGenerator.setSuperclass(QueryAbstractRequest.class);
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
Class parameterType = parameter.getType();
if (Collection.class.isAssignableFrom(parameterType)) {
parameterType = String.class;
}
queryGenerator.addProperty(paramAnnotation.value(), parameterType);
}
}
QueryAbstractRequest queryProxy = (QueryAbstractRequest) queryGenerator.create();
PropertyDescriptor[] propertyDescriptors;
try {
propertyDescriptors = Introspector.getBeanInfo(queryProxy.getClass()).getPropertyDescriptors();
} catch (IntrospectionException ie) {
throw new IllegalArgumentException(ie);
}
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
String paramName = paramAnnotation.value();
PropertyDescriptor propertyDescriptor = Stream.of(propertyDescriptors)
.filter(pd -> pd.getName().equals(paramName))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(String.format("无法匹配查询参数 %s", paramName)));
Object paramVal = args[i];
if (paramVal instanceof Collection) {
Collection<?> items = (Collection<?>) paramVal;
paramVal = items.stream().map(String::valueOf).collect(Collectors.joining(","));
}
try {
propertyDescriptor.getWriteMethod().invoke(queryProxy, paramVal);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException(String.format("绑定参数 paramName=%s,paramValue=%s 时候出错", paramName, paramVal), e);
}
}
}
return queryProxy;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment