В первых трех статьях подробно описаны основные функции, общая конфигурация и картограф Mybatis.По сравнению с Hibernate, конфигурация картографа относительно сложна, но обладает хорошей гибкостью и масштабируемостью и может работать с различными бизнес-сценариями. Если вы хорошо разбираетесь в этом содержании, вы можете использовать MyBatis для плавной разработки.
Позже я представлю анализ и принцип работы MyBatis и пользовательских плагинов.Сегодня я прочитал эту часть книги, и она будет включать в себя основы отражения и динамического прокси.Эта статья обобщает их для легкого понимания принципа.
Индекс статьи:
- Введение в JDBC и MyBatis
- Все конфигурации MyBatis
- "Маппер" все понимают
- Основы отражения и динамических прокси
Из этого введения вы узнаете:
- Какие проблемы решают отражение и динамические прокси
- Объект класса
- Что может сделать отражение
- Реализация динамического прокси: динамический прокси JDK, CGLIB
Понимание отражения и динамических прокси
отражение
Сначала взгляните на определение отражения на официальном сайте:
Вы можете получить такую информацию, как поля, методы и конструкторы загруженного в данный момент класса, с помощью кода Java и использовать поля, методы и конструкторы отражения для работы в рамках ограничений безопасности.
Проще говоря, информацию о членах каждого типа в программе можно получить во время выполнения. Типы объектов, определенных в программе, определяются во время компиляции, и отражение может динамически создавать объекты и получать доступ к их членам или вызывать их.
Динамический прокси
Так называемый агент — это лицо или организация, выполняющая действия от имени другого лица или организации. Существует три основных роли: посетитель, агент и принципал. Посетитель взаимодействует с принципалом через агента, а некоторые из их собственные добавляются в середине.
Так называемый динамический прокси-класс означает, что прокси-класс не нужно определять во время компиляции, а создается во время выполнения.Это ключевой момент: прокси-класс создается во время выполнения.
Объект класса
Класс Class — это реальный класс, который существует в пакете java.lang и используется для представления информации о типах во время выполнения. Объект класса представляет информацию о типе пользовательского класса. Например, когда создается класс пользователя, JVM создаст объект класса, соответствующий пользователю, и сохранит информацию о типе, связанную с классом пользователя. Объект хранится в jvm heap в качестве типа пользователя в информационном интерфейсе области метода доступа.
При использовании пользовательского класса он сначала проверит, был ли загружен объект класса этого класса.Если он не загружен, загрузчик класса по умолчанию сначала будет искать файл .class в соответствии с именем класса, а объект класса будет загружаться в память.
Объекты класса можно получить следующими тремя способами:
- Используйте статический метод forName класса Class;
- Получить класс объекта напрямую;
- Вызвать метод getClass() объекта;
Объект Class является основой отражения и предоставляет метод получения информации о классе, который будет представлен позже.
Особенности, обеспечиваемые отражением
Фреймворк отражения Java в основном обеспечивает следующее:
- Определить класс, к которому принадлежит объект во время выполнения;
- создавать объекты во время выполнения;
- Получить переменные-члены, методы, родительские классы, интерфейсы и другую информацию, содержащуюся в классе, во время выполнения;
- Вызов метода объекта во время выполнения;
Следующие примеры иллюстрируют связанные функции
Создайте экземпляр:
//获取String所对应的Class对象
Class<?> c = User.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
User user = (User)constructor.newInstance("calm");
Получить метод:
//返回类或接口声明的所有方法,包括私有的,但不包括继承的方法
public Method[] getDeclaredMethods() throws SecurityException
//所有public方法,包括继承的方法
public Method[] getMethods() throws SecurityException
//返回一个特定的方法,第一个参数为方法名称,后面的参数为方法参数对应Class的对象
public Method getMethod(String name, Class<?>... parameterTypes)
Метод вызова:
Class<?> userClass=User.class;
Object obj = userClass.newInstance();
Method method =klass.getMethod("addRole",String.class);
method.invoke(obj,"超级管理员");
Динамический прокси JDK
Сам JDK обеспечивает реализацию динамического прокси, который требует, чтобы прокси реализовывал интерфейс.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h)
Первый параметр — загрузчик классов, второй параметр — список интерфейсов, реализуемых агентом, а третий параметр — объект, реализующий интерфейс InvocationHandler.
InvocationHandler — это интерфейс, который используется для стандартизации метода выполнения делегата.Общий код обработки может быть добавлен до и после выполнения метода. Сгенерированный динамический прокси-класс содержит свойство InvocationHandler, и при вызове соответствующего метода будет инициирован вызов метода invoke.
public class JDKProxy implements InvocationHandler {
private Object targetObject;//被代理对象
public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)//invoke方法
throws Throwable {
Object ret = null;
ret = method.invoke(targetObject, args);
return ret;
}
}
Тестовый код:
JDKProxy jdkProxy=new JDKProxy();
UserService userService = (UserService)
jdkProxy.newProxy(new UserServiceImp());
userService.addRole("超级管理员");
Основной принцип динамического прокси JDK заключается в создании нового класса с входящим интерфейсом в соответствии с определенными правилами.
Динамический прокси CGLIB
Для динамического прокси-сервера JDK требуется интерфейс. Динамический прокси-сервер CGLIB (Code Generate Library) не имеет этого требования. Он реализуется путем создания подкласса класса прокси и последующего использования библиотеки байт-кода ASM для изменения кода.
public class CGLibProxy implements MethodInterceptor {
private Object targetObject; //被代理对象
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
obj = method.invoke(targetObject, args);
return obj;
}
}
Тестовый код:
CGLibProxy cgLibProxy=new CGLibProxy();
UserService userService = (UserService)
cgLibProxy.newProxy(new UserServiceImp());
userService.addRole("超级管理员");
ASM — это среда обработки байт-кода Java. Он может изменять существующие классы в двоичной форме или динамически генерировать классы. Однако в процессе создания байт-кода класса ASM работает на уровне инструкций по сборке базовой JVM, что требует от пользователей ASM определенного понимания структуры организации классов и инструкций по сборке JVM. Кроме того, вы можете использовать фреймворк javassist для управления байт-кодом, который более оптимизирован для интерфейса, предоставленного разработчиком.
Понимание отражения и динамического прокси очень полезно для анализа и принципа работы MyBatis, который будет представлен в следующей статье.
Добро пожаловать, чтобы отсканировать QR-код ниже и подписаться на мою личную общедоступную учетную запись WeChat~