Je ne pouvais pas le trouver au moment de publier l'article, alors je l'ai recherché.
Exemple peut être trouvé ici. Je veux réécrire la méthode addParameter à la ligne 66 de ce code source et le transmettre. Si vous spécifiez un objet, vous pouvez y accéder de la même manière que vous l'avez passé en argument.
Tout d'abord, le code source correspondant est indiqué ci-dessous.
<détails> MyBatis a une chaîne dans le premier argument nommé insert / select / update / delete de la classe SqlSession. Analysez le contenu de Mapper et émettez SQL via une méthode qui a Object comme deuxième argument.
Dans CustomSqlSessionConfig, étendez `` SQLSessionTemplate '' et ajoutez un objet qui semble inapproprié pour remplacer chaque méthode et passez-le via un argument au paramètre du deuxième argument (en fait Map) et exécutez-le. J'essaye de le faire. Ce code est auto-satisfaisant et peut vraiment être simplifié.
Si vous essayez d'implémenter ce qui précède de manière simple, même si ce n'est pas un tel code, vous pouvez le réaliser en remplaçant la méthode cible comme indiqué dans ↓. <détails> Mais je n'aimais pas écrire la même chose encore et encore, alors j'ai essayé de m'y tenir. Le proxy dynamique est une fonction implémentée à partir d'anciennes versions de Java qui crée dynamiquement un objet avec la méthode d'interface (groupe) spécifiée par l'argument et agrège le traitement dans le D'autre part, @Delegate de lombok est une annotation qui étend toutes les méthodes publiques des champs annotés en tant que méthodes de la classe qui contient le champ (vous pouvez l'ajuster). Il peut être difficile d'obtenir une image à première vue, mais si vous regardez ce site, il sera plus facile d'obtenir une image. En combinant ces deux, vous pouvez traiter les méthodes arbitraires de votre propre classe (cette fois, il s'agit d'insérer ou de sélectionner) en une seule fois.
Cela a tendance à être un petit code magique noir, mais si vous l'aimez, vous devriez l'aimer! Je ne sais pas L'inconvénient de cette méthode est qu'il est difficile d'appeler la même méthode de la classe parent (appel de type super.xxx) depuis InvocationHandler. Puisque InvocationHandler prend un objet Method comme argument, ce serait bien de pouvoir faire If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The Java Language Specification, section 15.12.4.4; in particular, overriding based on the runtime type of the target object may occur.
(Si la méthode sous-jacente est une méthode d'instance, elle sera appelée à l'aide de la référence de méthode dynamique décrite dans la section Spécification du langage Java et sera remplacée, en particulier, en fonction du type d'exécution de l'objet cible. ) Réaliser super.xxx par réflexion Dans la classe enfant, vous devez obtenir la méthode de la classe parent Vous pouvez utiliser l'exemple de code comme vous le souhaitez, mais nous déclinons toute responsabilité quant au résultat.
Recommended Posts
CustomSqlSessionConfig.java
package mybatis_implicit_parameter.config;
import lombok.experimental.Delegate;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.Map;
@Configuration
public class CustomSqlSessionConfig {
@Bean
public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplateExt(sqlSessionFactory);
}
static class SqlSessionTemplateExt extends SqlSessionTemplate {
public SqlSessionTemplateExt(SqlSessionFactory sqlSessionFactory) {
super(sqlSessionFactory);
}
Object invokeParentMethod(Method method, Object[] args) throws Throwable {
return makeParentMethodHandle(method).bindTo(this).invokeWithArguments(args);
}
MethodHandle makeParentMethodHandle(Method method) throws Exception {
return MethodHandles.lookup().findSpecial(SqlSessionTemplate.class, method.getName(),
MethodType.methodType(method.getReturnType(), method.getParameterTypes()), SqlSessionTemplateExt.class);
}
@Delegate
final SqlSession proxy = (SqlSession)Proxy.newProxyInstance(SqlSessionTemplateExt.class.getClassLoader(),
new Class[]{SqlSession.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(hasParameter(method)) {
args[1] = addParameter(args[1]);
}
return SqlSessionTemplateExt.this.invokeParentMethod(method, args);
}
boolean hasParameter(Method method) {
Parameter[] params = method.getParameters();
return (params.length >= 2 && params[1].getType().equals(Object.class));
}
Object addParameter(Object parameter) {
parameter = (parameter == null) ? new MapperMethod.ParamMap() : parameter;
if (parameter instanceof Map) {
return addParameter((Map) parameter);
} else {
throw new RuntimeException("Motif inattendu Dites-moi si vous venez ici ~:" + parameter.getClass().getName());
}
}
Object addParameter(Map map) {
//Paramètres implicites définis ici
map.put("insertValue", "foo");
map.put("updateValue", "bar");
return map;
}
});
}
}
Pour expliquer brièvement ce que vous faites ...
Point de blocage: combiner le @Delegate de Lombok et le proxy dynamique
CustomSqlSessionConfig.java
(réduction)
@Override
public int insert(String statement,Object parameter) {
return super.insert(statement, addParameter(parameter));
}
(réduction)
InvocationHandler
spécifié. C'est une fonction qui peut être effectuée.method.invoke (...)
, mais lorsqu'il est combiné avec @Delegate, cela provoquera StackOverflow. C'est le même résultat si vous spécifiez la classe parente et obtenez l'objet Method avec la même signature de méthode. Il s'agit de la référence de l'API Method # invoke (https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/reflect/Method.html#invoke (https://docs.oracle.com/en/java/javase/13/docs/api/java/javase/13/docs/api/java/javase/13/docs/api/java.htmlre/flava.html) En effet, l'appel de méthode est réalisé par invokeVirtual comme décrit dans java.lang.Object, java.lang.Object ...)).
MethodHandles.lookup().findSpecial(SqlSessionTemplate.class, method.getName(),
MethodType.methodType(method.getReturnType(),
method.getParameterTypes()), SqlSessionTemplateExt.class);
`MethodHandle``` avec`
`findSpecial. MethodHandle est différent de la réflexion Java conventionnelle, et le résultat dépend de la classe dans laquelle il est efficace. Si vous faites cela dans la classe d'implémentation
InvocationHandler```, vous obtiendrez toujours une erreur.Point suspect
Version de bibliothèque confirmée
Nom de la bibliothèque
version
Spring-Boot
2.3.4.RELEASE
mybatis-spring-boot-starter
2.1.3
lombok
5.1.0
À propos de l'exemple de code