предисловие
Если кто-то задаст вам эти вопросы, посмотрите, сможете ли вы на них ответить.
- Интерфейс Mybatis Mapper не имеет класса реализации, как реализовать SQL-запрос
- Почему динамический прокси JDK не может проксировать класс (проблема взимания платы за вызов)
- Это могут быть динамические прокси абстрактного класса JDK (дополнительная проблема)
На железный сок ответить не могу, докажи прокси, исходники mybatis еще не видел. Но отношения нет, по ходу разберусь.
Динамический прокси-бой
Как мы все знаем, динамический прокси JDK, используемый базовым пакетом Mybatis. Прежде чем говорить о динамическом прокси-сервере Mybatis, давайте взглянем на демо-версию динамического прокси, которую мы обычно пишем, и поговорим о ней.
Вообще говоря, определение динамического прокси-сервера JDK делится на три шага, как показано ниже.
- Определить интерфейс прокси
- Определить класс реализации прокси-интерфейса
- Определить обработчик вызовов динамического агента
Трехэтапный код выглядит следующим образом, и друзья, которые играли в динамические прокси, могут понять его после прочтения.
public interface Subject { // 定义代理接口
String sayHello();
}
public class SubjectImpl implements Subject { // 定义代理接口实现类
@Override
public String sayHello() {
System.out.println(" Hello World");
return "success";
}
}
public class ProxyInvocationHandler implements InvocationHandler { // 定义动态代理调用处理器
private Object target;
public ProxyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 🧱 🧱 🧱 进入代理调用处理器 ");
return method.invoke(target, args);
}
}
Напишите тестовую программу, запустите, посмотрите, она же разбита на три шага.
- Создайте класс реализации прокси-интерфейса
- Создайте динамический прокси-класс и произнесите три параметра
- загрузчик классов
- Массив интерфейсов, реализованных проксируемым классом
- Вызвать обработчик (вызвать метод проксируемого класса, проходить его каждый раз)
- Метод вызывается классом реализации прокси
public class ProxyTest {
public static void main(String[] args) {
Subject subject = new SubjectImpl();
Subject proxy = (Subject) Proxy
.newProxyInstance(
subject.getClass().getClassLoader(),
subject.getClass().getInterfaces(),
new ProxyInvocationHandler(subject));
proxy.sayHello();
/**
* 打印输出如下
* 调用处理器:🧱 🧱 🧱 进入代理调用处理器
* 被代理实现类:Hello World
*/
}
}
Реализована демо-функция, общий процесс работы тоже понятен, далее будет разобран принцип реализации.
Анализ принципа динамического агента
С точки зрения принципа, как выполняется описанная выше динамическая тестовая программа прокси?
Первый шаг прост,Создан класс реализации интерфейса Subject, что также является нашей обычной реализацией
Второй шаг — создать динамический прокси-объект для проксируемого объекта. Друг тут спрашивал, как доказать, что это динамический прокси-объект? как показано на рисунке
Имя объекта динамического агента JDK — правило. Любой динамический прокси-объект, созданный классом Proxy, префикс должен$Proxy, число после него также является частью имени
Если вы хотите найти мелких партнеров,Обратите внимание на внутренний класс Proxy ProxyClassFactory., Там будет ответ, который вы хотите
Вернемся к теме, продолжаем смотреть на ProxyInvocationHandler,Внутренне поддерживает ссылку на класс, который реализует прокси-интерфейс, метод вызова внутренне использует отражение для вызова метода класса реализации прокси-интерфейса.
Видно, что сгенерированный динамический прокси-класс наследует класс Proxy, а затем реализует интерфейс Subject, а метод реализации sayHello фактически вызывает метод вызова ProxyInvocationHandler.
Я случайно обнаружил причину, по которой динамический прокси JDK не может проксировать класс ^^
То есть, когда мы вызываемSubject#sayHelloКогда цепочка вызовов методов выглядит так
Однако в Демо есть класс реализации прокси-интерфейса, а в Mybatis Mapper нет, как в это играть?
Неважно, если вы не знаете, вы, вероятно, не сможете увидеть это, если знаете.Давайте посмотрим, как работает исходный код mybatis.
версия mybatis: 3.4.x
Реализация исходного кода Mybatis
Я не знаю, что такой тест не считается проблемой,Mapper Почему Mapper не нужен класс реализации?
Предположим, в нашем проекте используется трехуровневый дизайн, Контроллер управляет приемом запросов, Сервис отвечает за бизнес-обработку, а Маппер отвечает за взаимодействие с базой данных.
Уровень Mapper, также известный как уровень отображения базы данных, отвечает за операции с базой данных, такие как запрос данных или добавление, удаление и т. д.
Согласно смелому предположению, проект не использует Mybatis и должен написать взаимодействие с базой данных на уровне реализации Mapper.Что будет написано?
Напишет некоторые обычные операции JDBC, такие как:
// 装载Mysql驱动
Class.forName(driveName);
// 获取连接
con = DriverManager.getConnection(url, user, pass);
// 创建Statement
Statement state = con.createStatement();
// 构建SQL语句
String stuQuerySqlStr = "SELECT * FROM student";
// 执行SQL返回结果
ResultSet result = state.executeQuery(stuQuerySqlStr);
...
Если все слои реализации Mapper в проекте должны играть так, разве вы не хотите побеждать людей...
Так что MyBatis интегрированные очки боли проекта, вошли, как это сделать
- Все операции, которые взаимодействуют с JDBC, инкапсулируются динамическим прокси-сервером JDK внизу, и пользователям нужно только настроить файлы Mapper и .xml.
- Операторы SQL определяются в файлах .xml или Mapper.При запуске проекта операторы SQL анализируются синтаксическим анализатором и собираются в объекты на Java.
Есть много видов парсеров, потому что в Mybatis есть не только статические операторы, но и динамические SQL-операторы.
Вот почему интерфейс Mapper не требует класса реализации,Поскольку он был инкапсулирован Mybatis через динамический прокси, если каждый Mapper имеет класс реализации, он раздут и бесполезен.. После этой операции нам показывают фреймворк Mybatis, используемый в проекте.
Верхнее постельное белье так долго, и, наконец, к главному герою,Почему интерфейс Mybatis Mapper может реализовать динамический прокси без реализации классов?
Практически невозможно представить процесс динамического прокси Mybatis в строгом порядке, не процитировав заранее не введенные термины, автор старается сделать его максимально простым для понимания.
Никакой класс реализации не завершает динамический прокси
Основная мысль здесь, возьмите маленькую книгу и сядьте на доску.
Давайте сначала посмотрим, могут ли обычные динамические агенты полагаться на интерфейсы без реализации классов.
public interface Subject {
String sayHello();
}
public class ProxyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 🧱 🧱 🧱 进入代理调用处理器 ");
return "success";
}
}
Как видно из кода, мы не реализовали интерфейс Subject, продолжаем смотреть как реализовать динамический прокси
public class ProxyTest {
public static void main(String[] args) {
Subject proxy = (Subject) Proxy
.newProxyInstance(
subject.getClass().getClassLoader(),
new Class[]{Subject.class},
new ProxyInvocationHandler());
proxy.sayHello();
/**
* 打印输出如下
* 调用处理器:🧱 🧱 🧱 进入代理调用处理器
*/
}
}
Видно, что по сравнению с Демо в начале текста здесь правильныйProxy.newProxyInstanceПараметры метода изменены
Раньше массив Class реализуемого интерфейса получался путем реализации класса, а здесь сам интерфейс помещается в массив Class таким же образом.
В чем разница между динамическим прокси-классом, сгенерированным с реализованным интерфейсом, и нереализованным интерфейсом
- Иметь интерфейс реализации правильно
InvocationHandler#invokeВызов метода, метод вызова вызывает метод прокси-объекта (SubjectImpl) (sayHello) посредством отражения. - Нет реализации интерфейс является единственным
InvocationHandler#invokeпозвонить.Таким образом, реализация интерфейса возвращает возвращаемое значение интерфейса прокси-объекта, в то время как интерфейс без реализации возвращает только возвращаемое значение метода вызова.
InvocationHandler#invokeВозвращаемым значением метода является строка успеха, определите строковую переменную, может ли она успешно вернуться
Теперь появился ответ на первый вопрос,Mapper не имеет класса реализации, и все операции, такие как вызов JDBC, реализованы в Mybatis InvocationHandler.
Поскольку проблема решена, это дает людям ощущение, что это не так сложно, но вам не интересно, как поживает нижний слой Mybatis?
Сначала киньте вопрос, а потом посмотрите исходник с вопросом, что может заставит вас глубоко вспомнить Дабл
Интерфейс в нашей Демо исправлен, но Mybatis Mapper не исправлен, что мне делать?
Мибатис так говорит
Посмотрите на прокси динамического интерфейса, который он реализует внизу Mybatis, вам нужно только обратить внимание на код на отметке
Как и в нашем демонстрационном коде, суть в том, чтоmapperInterfaceкак это назначено
Поговорим о конкретной логике генерации динамических классов прокси в фабрике прокси Mybatis.
- Согласно связанному пространству имен на .xml, через
Class#forNameВозвращает объект класса путем отражения (а не только пространство имен .xml) - Передайте полученный объект класса (на самом деле объект интерфейса) в прокси-фабрику Mybatis, чтобы сгенерировать прокси-объект, который сейчас является свойством mapperInterface.
Тайна раскрыта, Mybatis использует полное имя интерфейса для передачиClass#forNameСоздайте объект класса, тип объекта класса - это интерфейс
Для удобства всеобщего понимания тестовый класс, предоставляемый исходным кодом Mybatis, является примером. Предположим, что существующий интерфейс AutoConstructorMapper и соответствующий XML-файл выглядят следующим образом.
Выполните первый шаг и получите объект класса в соответствии с пространством имен .xml.
- Первый шаг — получить атрибут пространства имен тега сопоставления в XML-файле, чтобы получить полную информацию об интерфейсе сопоставления.
- Получить объект класса на основе полной информации картографа
- Добавьте в соответствующий контейнер картографа и дождитесь создания динамического прокси-объекта.
Если вы вызываете для создания динамического прокси-объекта в это время, метод newInstance фабрики прокси выглядит следующим образом:
Пока что на все вопросы о прокси и динамических прокси Mybatis, упомянутые в начале статьи, даны ответы.
Могут ли JDK динамически проксировать абстрактные классы?
Произнеся сначала код перед заключением,не может!
public abstract class AbstractProxy {
abstract void sayHello();
}
AbstractProxy proxyInterface = (AbstractProxy) Proxy
.newProxyInstance(
ProxyTest.class.getClassLoader(),
new Class[]{AbstractProxy.class},
new ProxyInvocationHandler());
proxyInterface.sayHello();
Нет сомнений в том, что ошибка неизбежна, и JDK не может быть прокси для классов.
С небольшим сомнением давайте взглянем на расположение отчета об ошибках исходного кода прокси.Динамический прокси JDK будет иметь проверку интерфейса в коде процесса генерации классов прокси.
Абстрактный класс — это все-таки класс, а абстрактный не может быть интерфейсом (так же, как и я, хоть и набрал 60 фунтов, но все равно красавчик)
Если интервьюер задаст этот вопрос в следующий раз,будь тверд, просто не могу
Вывод
В сочетании с проблемами, связанными с использованием динамического прокси-сервера JDK Mybatis, статья описана, которая резюмируется здесь.
Q: Могут ли JDK классы динамических прокси-прокси?
Поскольку прокси-класс, сгенерированный динамическим прокси-сервером JDK, наследует класс прокси, а поскольку Java не поддерживает множественное наследование, он не может проксировать класс.
Вопрос. Могут ли JDK динамически проксировать абстрактные классы?
Нет, абстрактные классы по сути тоже классы.В процессе генерации прокси-классов прокси проверяет, является ли входящий класс интерфейсом.
Q: Интерфейс Mybatis Mapper не имеет класса реализации, как реализовать динамический прокси?
Мибатис пройдетClass#fornameПолучите объект класса интерфейса mappper, сгенерируйте соответствующий объект динамического агента, основной бизнес-процесс будетInvocationHandler#invokeобрабатывать
Надеюсь, что читатели, прочитавшие ее, смогут что-то почерпнуть.Если у вас есть сомнения по поводу содержания статьи, вы можете пообщаться, оставив сообщение или добавив автора в друзья.Удачи!
Поиск в Wechat [круг интереса к исходному коду], подпишитесь на официальный аккаунт и ответьте 123, чтобы получить учебные материалы, такие как GO, Netty, Seata, SpringCloud Alibaba, спецификации разработки, сборник интервью, структуру данных и так далее!