Чтобы проксировать класс с помощью динамического прокси jdk, проксируемый класс должен реализовать хотя бы один интерфейс, и проксироваться могут только методы в этом интерфейсе.
Реализация динамического прокси в jdk обычно делится на три этапа:
1. Напишите интерфейсы и классы реализации.
2. Напишите процессор, реализующий интерфейс InvokeHandler. Этот интерфейс имеет только один метод, и его сигнатура — общедоступный вызов объекта (прокси-сервер объекта, метод метода, аргументы Object[]).
throws Throwable Вы можете добавить свой собственный код в метод реализации процессора до и после вызова метода для выполнения динамического перехвата. Следует отметить, что динамический прокси-класс, сгенерированный прокси, не является реальным классом, который мы проксируем, поэтому мы можем добавить в процессор переменную-член типа Object, чтобы указать на класс, который мы действительно хотим проксировать (то есть класс в классе реализации шага 1).
3. Используйте метод newProxyInstance класса java.lang.reflect.Proxy для создания динамического прокси-класса. Для всех вызовов прокси-методов вы можете напрямую вызвать метод сгенерированного динамического прокси-класса, но сначала необходимо выполнить для него принудительное преобразование типов и преобразовать его в интерфейс метода, который мы хотим вызвать.
Анализ принципов JDK:
Анализируя исходный код Proxy, вы можете увидеть подробную генерацию динамических прокси-классов. Метод newProxyInstance сначала создает экземпляр класса динамического прокси-класса, а затем вызывает его конструктор, тип параметра которого — InvocationHandler, для создания динамического прокси-класса и возврата.
Как создать экземпляр класса динамического прокси-класса. Класс ProxyGenerator используется для создания потока байтов класса динамического прокси-класса и загрузки его в область метода.
Анализируя процесс генерации байтового потока класса, мы видим, что он использует Proxy в качестве родительского класса для реализации всех методов проксируемого интерфейса. Тело реализации каждого метода в основном вызывает метод вызова процессора.
Основной код процесса генерации потока байтов класса выглядит следующим образом:
Скопируйте код кода следующим образом:
частный байт[]generateClassFile()
{
addProxyMethod(hashCodeMethod, java/lang/Object);
addProxyMethod(equalsMethod, java/lang/Object);
addProxyMethod(toStringMethod, java/lang/Object);
for(int i = 0; i <interfaces.length; i++)
{
Метод amethod[] = интерфейсы[i].getMethods();
for(int k = 0; k < amethod.length; k++)
addProxyMethod(amethod[k], интерфейсы[i]);
}
Список списка;
for(Итератор итератор = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(список))
список = (Список)итератор.следующий();
пытаться
{
методы.add(generateConstructor());
for(Итератор iterator1 = proxyMethods.values().iterator(); iterator1.hasNext();)
{
Список list1 = (Список)итератор1.следующий();
Итератор iterator2 = list1.iterator();
в то время как (итератор2.hasNext())
{
ProxyMethod proxymethod = (ProxyMethod)iterator2.next();
field.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
методы.add(<SPAN style="COLOR: red">proxymethod.generateMethod()</SPAN><SPAN style="COLOR: #000000">);</SPAN>
Скопируйте код кода следующим образом:
}
}
методы.add(generateStaticInitializer());
}
catch (IOException ioException)
{
throw new InternalError("неожиданное исключение ввода-вывода");
}
если(methods.size() > 65535)
throw new IllegalArgumentException("Превышен лимит метода");
если (fields.size() > 65535)
throw new IllegalArgumentException("Превышен предел поля");
cp.getClass(dotToSlash(имякласса));
cp.getClass("java/lang/reflect/Proxy");
for(int j = 0; j <interfaces.length; j++)
cp.getClass(dotToSlash(interfaces[j].getName()));
cp.setReadOnly();
ByteArrayOutputStream bytearrayoutputstream = новый ByteArrayOutputStream ();
DataOutputStream dataoutputstream = новый DataOutputStream (bytearrayoutputstream);
пытаться
{
dataoutputstream.writeInt(-889275714);
dataoutputstream.writeShort(0);
dataoutputstream.writeShort(49);
cp.write(поток вывода данных);
dataoutputstream.writeShort(49);
dataoutputstream.writeShort(cp.getClass(dotToSlash(className)));
dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
dataoutputstream.writeShort(interfaces.length);
for(int l = 0; l <interfaces.length; l++)
dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName())));
dataoutputstream.writeShort(fields.size());
FieldInfo полеИнформация;
Скопируйте код кода следующим образом:
//Добавляем атрибуты
for(Итератор iterator3 = field.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream))
fieldinfo = (FieldInfo)iterator3.next();
//Добавляем метод
dataoutputstream.writeShort(methods.size());
Информация о методе
for(Итератор iterator4 = методы.iterator(); iterator4.hasNext(); методinfo.write(dataoutputstream))
Methodinfo = (MethodInfo)iterator4.next();
dataoutputstream.writeShort(0);
}
поймать (IOException ioException1)
{
throw new InternalError("неожиданное исключение ввода-вывода");
}
вернуть bytearrayoutputstream.toByteArray();
}
Примечание. Красная часть кода, proxymethod.generateMethod(), генерирует тело метода для каждого метода. Просматривая исходный код, мы видим, что все они вызывают метод вызова процессора реализации интерфейса InvoctionHandler.