English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Глубокое понимание механизма динамического代理 java

Retrofit - это框架 для сетевых запросов с очень высокой степенью декомпозиции, в последнее время, изучая его, я обнаружил очень мощную и практичную технологию динамического агента. Эта статья будет служить прелюдией к retrofit, чтобы让大家 узнать: какие есть применения динамического агента, что такое динамический агент, как его использовать, где находятся его ограничения?

Применение динамического агента

1. AOP - программирование на основе аспектов, декомпозиция программы

Короче говоря, когда вы хотите выполнить некоторые общие операции перед и после методов некоторых классов, а также выполнять индивидуальные операции в методах - используйте динамический агент. В условиях большого объема бизнеса это может уменьшить количество кода и улучшить поддерживаемость.

2. Хотите настроить некоторые методы библиотеки третьей стороны

Я использую библиотеку третьей стороны, но некоторые из его методов не соответствуют моим потребностям, я хочу переписать эти методы сам или добавить некоторые специальные операции перед и после методов - с помощью динамического агента. Но необходимо учитывать, что у этих методов есть ограничения, и я объясню их позже.

Что такое динамический агент

Давайте начнем с конкретных примеров из жизни.

Предположим, что вы большой владелец недвижимости (агентируемый), у вас много домов, которые вы хотите сдавать в аренду, и вы считаете, что искать承租щиков слишком сложно, и вы не хотите это делать сами, поэтому вы нанимаете человека, который будет代理ировать вас (агент), чтобы помочь вам управлять этими вещами, и этот человек (агент, то есть агент) будет взимать с вас некоторые соответствующие агентские сборы (дополнительные операции по сдаче в аренду дома). Для承租щика агент является владельцем дома и помогает вам выполнять некоторые задачи.

Таким образом, это пример代理, почему он называется "динамическим агентом", где проявляется这个词 "динамический"?

Мы можем так думать, что если у вас jedes ваше жилье имеет агента, который помогает вам управлять, и каждый раз, когда вы хотите сдавать в аренду новое жилье, вам нужно нанять нового агента, вы получите много агентов, что приведет к высоким затратам на агентов, что можно рассматривать как "статический агент".

Но предположим, что мы передаем все наши дома одному агенту для代理, чтобы он мог динамически переключаться между несколькими домами и помогать вам справляться с каждым承租щиком. Это процесс "динамического代理". Одна из основных особенностей динамического代理 в том, что代理ный класс создается только в runtime, а не на этапе компиляции.

Давайте рассмотрим это на примере кода

операции по аренде дома

/**
*Определение интерфейса
**/
public interface RentHouse {
void rent();//房屋出租
void charge(String str);//出租费用收取

владелец дома

public class HouseOwner implements RentHouse {
public void rent() {
  System.out.println("I want to rent my house");

public void charge(String str) {
  System.out.println("You get : " + str + " RMB HouseCharge.");


агент

public class DynamicProxy implements InvocationHandler {
// 这个就是我们要代理的真实对象,即房东
private Object subject;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object subject) {
  this.subject = subject;

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //  Мы можем добавить свои действия до того, как мы будем代理 настоящий объект, агент взимает агентский сбор
  System.out.println("до "+method.getName()+" house");
  System.out.println("Метод:" + method.getName());
  //    Если метод - charge, агент взимает 100 юаней агентского сбора
  if (method.getName().equals("charge")) {
    method.invoke(subject, args);
    System.out.println("Я получу 100 RMB ProxyCharge.");
  } else {
    //  Когда代理-объект вызывает методы настоящего объекта, он автоматически переходит к методу invoke объекта handler, связанного с агентом, для вызова
    method.invoke(subject, args);
  
  //  Мы можем добавить свои действия после代理 настоящего объекта
  System.out.println("после "+method.getName()+" house");
  возвращает null;


гость

public class Client {
public static void main(String[] args)
{
  //  Настоящий объект, который мы хотим代理 --房东
  HouseOwner houseOwner = new HouseOwner();
  //  Мы хотим代理哪个 настоящий объект, передаем этот объект внутрь, и в конце мы вызываем его методы через этот настоящий объект
  InvocationHandler handler = new DynamicProxy(houseOwner);
  /*
   * Создание нашего代理-объекта через метод newProxyInstance класса Proxy, посмотрим на его три параметра
   * Первый параметр handler.getClass().getClassLoader() ,мы здесь используем объект ClassLoader класса handler для загрузки нашего代理-объекта
   * Второй параметр realSubject.getClass().getInterfaces(), мы предоставляем интерфейсы объекта代理, которые реализует реальный объект, что означает, что я хочу代理 этот реальный объект, и таким образом я могу вызывать методы этой группы интерфейсов
   * Третий параметр handler, мы связываем этот объект代理 с объектом InvocationHandler, указанным выше
   */
  RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
      .getClass().getInterfaces(), handler); // это динамический класс代理, посредник
  System.out.println(rentHouse.getClass().getName());
  rentHouse.rent();
  rentHouse.charge("10000");


Давайте посмотрим на вывод

com.sun.proxy.$Proxy0
before rent house
Метод: rent
Я хочу сдавать свою квартиру
after rent house
before charge house
Метод: charge
Вы получите: 10000 RMB HouseCharge.
I will get 100 RMB ProxyCharge.
after charge house
Процесс завершен с кодом выхода 0

В выводе есть before rent house и after rent house, что означает, что мы можем добавить операции перед и после метода. Еще один вывод I will get 100 RMB ProxyCharge. показывает, что мы можем не только добавить операции, но и заменить метод или даже не выполнять его.

В начале просмотра кода у вас могут возникнуть множество вопросов, давайте посмотрим, как использовать динамическую代理 с помощью следующего контента.

Как использовать динамическую代理?

В динамической代理-механизме Java есть два важных класса и интерфейса: InvocationHandler (Interface) и Proxy (Class), которые необходимы для реализации динамической代理.

Каждый динамический класс прокси должен реализовывать интерфейс InvocationHandler (код-посредник), и каждый экземпляр класса прокси связан с handler. Когда мы вызываем метод через объект прокси, вызов метода перенаправляется на метод invoke интерфейса InvocationHandler (увеличение функциональности метода пишется здесь), который является частью интерфейса.

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

Мы видим, что этот метод принимает три параметра, так что что означают эти параметры?

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//proxy: указывает на реальный объект, который мы проксируем
//method: указывает на объект Method, который представляет собой метод, который мы собираемся вызвать у реального объекта
//args: указывает на параметры, принятые при вызове метода реального объекта

Давайте теперь рассмотрим класс Proxy

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

Класс Proxy предназначен для динамического создания объектов прокси, он предоставляет множество методов, но мы используем в основном метод newProxyInstance:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

Эта функция служит для получения динамического объекта прокси, который принимает три параметра, давайте посмотрим, что означают эти параметры

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
//loader: объект ClassLoader, который определяет,哪个 объект ClassLoader будет загружать созданные объекты прокси
//interfaces: массив объектов Interface, который указывает на то, какие интерфейсы я планирую предоставить объектам, для которых я буду создавать прокси, если я предоставлю им набор интерфейсов, то объект прокси宣称实现了 этот интерфейс (полиморфизм), и таким образом я могу вызывать методы этого набора интерфейсов
//h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

//h: объект InvocationHandler, который указывает на то, к которому объект InvocationHandler будет привязан, когда этот объект динамического агента будет вызывать методы

Таким образом,结合起来上面给出的 код, мы можем понять способ использования динамического агента

Ограничения динамического агента
Как мы видим из использования динамического агента, все методы, которые могут быть 增强, являются интерфейсами (public методы, не реализующие интерфейсы, также могут использоваться через наследование класса агента), класс HouseOwner наследует RentHouse в коде. Но для частных методов динамический агент JDK не может помочь!

Заключение

Сценарии использования динамического агента намного больше, чем это, его внутренний принцип будет представлен в будущих статьях, но механизм временного генерирования代理 класса Reflection в классе приложения определяет, что это будет有一定的影响 на производительность. Эта статья не слишком详尽地作为retrofit принципов предварительной статьи, если есть ошибки и пропуски, пожалуйста, исправляйте!

Вот и все, что есть в этой статье, мы надеемся, что это поможет вам в изучении, и мы просим вас активно поддерживать учебник呐喊.

Заявление: содержимое статьи предоставлено из Интернета, авторское право принадлежит правообладателям, материалы предоставлены пользователями Интернета по их собственной инициативе, сайт не обладает правами собственности, материалы не были отредактированы вручную, и сайт не несет ответственности за соответствующие юридические вопросы. Если вы обнаружите спорное содержимое о нарушении авторских прав, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @) для сообщения о нарушении,并提供 соответствующие доказательства. Если после проверки обнаружится, что содержимое является нарушением авторских прав, сайт незамедлительно удалит спорное содержимое.

Вам может понравиться