序文は重要です
動的エージェントの機能:インターセプターメソッドのコールバックを通じて、ターゲットメソッドが拡張されます。
その意味するところは、ターゲットメソッドを強化することです。上記の文章は正しいですが、真実だとは思いません。誰もが知っているように、ダイナミックエージェントは流れを切るために鞭を投げるというヘゲモニーも持っており、ターゲットターゲットでさえサイエンスフィクションモードを必要としません。
注:この記事は、読者が動的プロキシの原理を理解していることを前提としています。ターゲットの意味を理解していないと、この記事を理解するのが困難です。最初に動的プロキシを理解することをお勧めします。
最新の2020年に収集されたインタビューの質問(すべてドキュメントにまとめられています)、mysql、netty、spring、thread、spring cloudなどの詳細な説明を含む多くの乾物があり、詳細な調査計画、インタビューの質問などもあります。私はインタビューに参加していると感じていますこのセクションは非常に明確です。インタビュー情報を取得するには、 ここをクリックしてください。!パスワード:51CTO
1. JDK動的プロキシをカスタマイズして、自動マッパーマッパーを実現します
まず、pojoを定義します。
public class User {
private Integer id;
private String name;
private int age;
public User(Integer id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// getter setter
}
再定义一个接口UserMapper.java。
public interface UserMapper {
public User getUserById(Integer id);
}
次に、動的プロキシを使用してストリームをキャストおよびホイップオフし、インスタンス化インターフェイスを実現し、インターフェイスメソッドを呼び出してデータを返す方法を見てみましょう。
InvocationHandlerをカスタマイズします。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MapperProxy implements InvocationHandler {
@SuppressWarnings("unchecked")
public <T> T newInstance(Class<T> clz) {
return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz }, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
// 诸如hashCode()、toString()、equals()等方法,将target指向当前对象this
return method.invoke(this, args);
} catch (Throwable t) {
}
}
// 投鞭断流
return new User((Integer) args[0], "zhangsan", 18);
}
}
上記のコードのターゲットは、Object.javaのメソッドが実行されると、ターゲットがこれを指し、ターゲットが人形、シンボル、およびプレースホルダーになります。傍受にはもうターゲットはありません。
テストコードを書く:
public static void main(String[] args) {
MapperProxy proxy = new MapperProxy();
UserMapper mapper = proxy.newInstance(UserMapper.class);
User user = mapper.getUserById(1001);
System.out.println("ID:" + user.getId());
System.out.println("Name:" + user.getName());
System.out.println("Age:" + user.getAge());
System.out.println(mapper.toString());
}
出力:
ID:1001
Name:zhangsan
Age:18
x.y.MapperProxy@6bc7c054
これは、Mybatis自動マッパーマッパーの基本的な実装原則です。
一部の読者は尋ねるのを助けないかもしれません:初心者が書くようにどのようにコードを書くのですか?構造や美しさの欠如はありません。
初心者のようなプログラムを書くことができる経験豊富なマスターとして、彼はマスターでなければならないことを述べなければなりません。これにより、初心者は心のこもった、快適な、自分のスタイルに沿ったものになり、大きな牛が書いたコードはこれに過ぎないと感じさせ、大きな牛が書いたコードよりも上手に書くことができます。それ以来、彼らは自信に満ちています。ダニエルとのギャップはあと3分だと思って熱意が高い。
2.Mybatis自動マッパーマッパーのソースコード分析
最初にテストクラスを作成します。
public static void main(String[] args) {
SqlSession sqlSession = MybatisSqlSessionFactory.openSession();
try {
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = studentMapper.findAllStudents();
for (Student student : students) {
System.out.println(student);
}
} finally {
sqlSession.close();
}
}
マッパーは次のようになります。
public interface StudentMapper {
List<Student> findAllStudents();
Student findStudentById(Integer id);
void insertStudent(Student student);
}
org.apache.ibatis.binding.MapperProxy.java部分源码。
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
// 投鞭断流
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
// ...
ソースコードのorg.apache.ibatis.binding.MapperProxyFactory.java部分。
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
これは、Mybatisが動的エージェントを使用してフローをカットする方法です。
3.インターフェイスマッパーのメソッドをオーバーロードできますか?(重要)
次のようになります。
public User getUserById(Integer id);
public User getUserById(Integer id, String name);
回答:いいえ。
理由:Mybatisは、実行するxml内の唯一のsqlを見つけるためのキーとして、package + Mapper + methodのフルネームを使用します。同様に:key = xyUserMapper.getUserByIdの場合、メソッドをオーバーロードすると競合が発生します。Mapperインターフェイスの場合、Mybatisはメソッドのオーバーロード(overLoad)を禁止しています。
注:学習するときは、最初にソースコードを学習し、原理を理解します。ブログ投稿を書くときは、まず原理を説明してから、ソースコードを読んでください。順番は正反対です。私は強すぎて預言者になれないと思って、読者が混乱しないように願っています。
やっと:
最新の2020年に収集されたインタビューの質問(すべてドキュメントにまとめられています)、mysql、netty、spring、thread、spring cloudなどの詳細な説明を含む多くの乾物があり、詳細な調査計画、インタビューの質問などもあります。私はインタビューに参加していると感じていますこのセクションは非常に明確です。インタビュー情報を取得するには、ここをクリックしてください。!パスワード:51CTO