Динамический прокси JAVA
режим прокси
Шаблон агента — это широко используемый шаблон проектирования Java. Его особенностью является то, что класс агента и класс делегата имеют один и тот же интерфейс. Класс агента в основном отвечает за предварительную обработку сообщений для класса делегата, фильтрацию сообщений и пересылку сообщений в класс делегата. и последующая обработка сообщений. Обычно существует связь между прокси-классом и классом-делегатом. Объект прокси-класса связан с объектом класса-делегата. Объект прокси-класса сам по себе не реализует службу, а вызывает соответствующие методы. объекта класса делегата. Предоставлять определенные услуги.
По периоду создания агента класс агента можно разделить на два типа.
Статический прокси: создается программистами или автоматически генерируется определенным инструментом, а затем компилируется. Перед запуском программы файл .class прокси-класса уже существует.
Динамический прокси: динамически создается с использованием механизма отражения во время работы программы.
Сначала взгляните на статический прокси:
1.Count.java
Скопируйте код кода следующим образом:
пакет net.battier.dao;
/**
* Определить интерфейс учетной записи
*
* @author Администратор
*
*/
публичный интерфейс
// Метод просмотра аккаунта
общественный недействительный запросCount();
//Изменить метод аккаунта
общественный недействительный updateCount ();
}
2. ГрафИмпл.java
Скопируйте код кода следующим образом:
пакет net.battier.dao.impl;
импортировать net.battier.dao.Count;
/**
* Класс делегата (включая бизнес-логику)
*
* @author Администратор
*
*/
публичный класс CountImpl реализует Count {
@Override
общественный недействительный queryCount () {
System.out.println("Метод просмотра учетной записи...");
}
@Override
общественный недействительный updateCount () {
System.out.println("Изменить метод учетной записи...");
}
}
CountProxy.java
пакет net.battier.dao.impl;
импортировать net.battier.dao.Count;
/**
* Это прокси-класс (расширенный класс реализации CountImpl).
*
* @author Администратор
*
*/
публичный класс CountProxy реализует Count {
частный CountImpl countImpl;
/**
* Переопределить конструктор по умолчанию.
*
* @param countImpl
*/
общественный CountProxy (CountImpl countImpl) {
this.countImpl = countImpl;
}
@Override
общественный недействительный queryCount () {
System.out.println("Перед обработкой транзакции");
// Вызов метода класса делегата;
countImpl.queryCount();
System.out.println("После обработки транзакции");
}
@Override
общественный недействительный updateCount () {
System.out.println("Перед обработкой транзакции");
// Вызов метода класса делегата;
countImpl.updateCount();
System.out.println("После обработки транзакции");
}
}
3. ТестКаунт.java
Скопируйте код кода следующим образом:
пакет net.battier.test;
импортировать net.battier.dao.impl.CountImpl;
импортировать net.battier.dao.impl.CountProxy;
/**
*Класс подсчета тестов
*
* @author Администратор
*
*/
общественный класс TestCount {
public static void main(String[] args) {
CountImpl countImpl = новый CountImpl ();
CountProxy countProxy = новый CountProxy (countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}
Наблюдая за кодом, можно обнаружить, что каждый прокси-класс может обслуживать только один интерфейс. Таким образом, во время разработки программы неизбежно будет создано слишком много прокси. Более того, все операции прокси одинаковы, за исключением метода, который они вызывают. необходимо повторить в это время. Лучший способ решить эту проблему — использовать прокси-класс для выполнения всех функций прокси. В этом случае для его выполнения необходимо использовать динамический прокси.
Давайте посмотрим на динамический прокси:
Динамический прокси JDK содержит класс и интерфейс:
Интерфейс InvoctionHandler:
общедоступный интерфейс InvoctionHandler {
общедоступный вызов объекта (прокси-сервер объекта, метод метода, объект [] args) выдает Throwable;
}
Описание параметра:
Прокси объекта: относится к проксируемому объекту.
Метод метода: метод, который будет вызван
Object[] args: параметры, необходимые при вызове метода.
Вы можете думать о подклассе интерфейса InlocationHandler как о последнем классе операции прокси, заменяющем ProxySubject.
Класс прокси:
Класс Proxy — это класс, который специализируется на операциях прокси. Этот класс можно использовать для динамического создания классов реализации для одного или нескольких интерфейсов. Этот класс предоставляет следующие методы операций:
общедоступный статический объект newProxyInstance (загрузчик ClassLoader, интерфейсы Class<?>[],
Обработчик вызова h)
выдает IllegalArgumentException
Описание параметра:
Загрузчик ClassLoader: загрузчик классов
Интерфейсы Class<?>[]: получить все интерфейсы
InvoctionHandler h: получить экземпляр подкласса интерфейса InvokeHandler.
PS: загрузчик классов
Экземпляр класса ClassLoader требуется в методе newProxyInstance() в классе Proxy. ClassLoader фактически соответствует загрузчику классов. В Java существует три основных загрузчика классов;
Booststrap ClassLoader: этот загрузчик написан на C++ и его нельзя увидеть в общей разработке;
Расширение ClassLoader: используется для загрузки классов расширения, обычно соответствующих классам в каталоге jre/lib/ext;
AppClassLoader: (по умолчанию) загружает класс, указанный в classpath, который является наиболее часто используемым загрузчиком.
динамический прокси
В отличие от статического прокси-класса существует динамический прокси-класс. Байт-код динамического прокси-класса динамически генерируется механизмом отражения Java во время работы программы, без необходимости программистам вручную писать его исходный код. Динамические прокси-классы не только упрощают работу по программированию, но и улучшают масштабируемость программных систем, поскольку механизм отражения Java может генерировать динамические прокси-классы любого типа. Класс Proxy и интерфейс IndictionHandler в пакете java.lang.reflect предоставляют возможность генерировать динамические прокси-классы.
Пример динамического прокси:
1.BookFacade.java
Скопируйте код кода следующим образом:
пакет net.battier.dao;
общедоступный интерфейс BookFacade {
общественная недействительность addBook();
}
2.BookFacadeImpl.java
Скопируйте код кода следующим образом:
пакет net.battier.dao.impl;
импортировать net.battier.dao.BookFacade;
публичный класс BookFacadeImpl реализует BookFacade {
@Override
общественная недействительность addBook() {
System.out.println("Метод добавления книги...");
}
}
BookFacadeProxy.java
пакет net.battier.proxy;
импортировать java.lang.reflect.IndictionHandler;
импортировать java.lang.reflect.Method;
импортировать java.lang.reflect.Proxy;
/**
* Класс динамического прокси-сервера JDK
*
* @author студент
*
*/
публичный класс BookFacadeProxy реализует IndictionHandler {
цель частного объекта;
/**
* Привязываем объект делегата и возвращаем прокси-класс
* @param цель
* @возвращаться
*/
общественная привязка объекта (цель объекта) {
this.target = цель;
//Получаем прокси-объект
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //Для привязки интерфейса (это недостаток, cglib компенсирует этот недостаток)
}
@Override
/**
* Метод вызова
*/
Открытый вызов объекта (прокси-сервер объекта, метод метода, аргументы Object[])
бросает Throwable {
Результат объекта = ноль;
System.out.println("Все начинается");
//метод выполнения
результат = метод.invoke(цель, аргументы);
System.out.println("Конец всему");
вернуть результат;
}
}
3. ТестПрокси.java
Скопируйте код кода следующим образом:
пакет net.battier.test;
импортировать net.battier.dao.BookFacade;
импортировать net.battier.dao.impl.BookFacadeImpl;
импортировать net.battier.proxy.BookFacadeProxy;
общественный класс TestProxy {
public static void main(String[] args) {
BookFacadeProxy прокси = новый BookFacadeProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
}
}
Однако динамический прокси-сервер JDK опирается на реализацию интерфейса. Если некоторые классы не реализуют интерфейс, прокси-сервер JDK использовать нельзя, поэтому необходимо использовать динамический прокси-сервер cglib.
Динамический прокси Cglib
Механизм динамического прокси JDK может использовать только классы, реализующие интерфейсы. Классы, которые не могут реализовывать интерфейсы, не могут реализовать динамический прокси JDK. Его принцип заключается в создании подкласса для указанного целевого класса и переопределении методов для достижения улучшения. , но поскольку используется наследование, окончательный измененный класс не может быть проксирован.
Пример
1.BookFacadeCglib.java
Скопируйте код кода следующим образом:
пакет net.battier.dao;
общедоступный интерфейс BookFacade {
общественная недействительность addBook();
}
2.BookCadeImpl1.java
Скопируйте код кода следующим образом:
пакет net.battier.dao.impl;
/**
* Это класс реализации, который не реализует интерфейс
*
* @author студент
*
*/
общественный класс BookFacadeImpl1 {
общественная недействительность addBook() {
System.out.println("Общий метод добавления книг...");
}
}
3.BookFacadeProxy.java
Скопируйте код кода следующим образом:
пакет net.battier.proxy;
импортировать java.lang.reflect.Method;
импортировать net.sf.cglib.proxy.Enhancer;
импортировать net.sf.cglib.proxy.MethodInterceptor;
импортировать net.sf.cglib.proxy.MethodProxy;
/**
* Используйте динамический прокси cglib.
*
* @author студент
*
*/
публичный класс BookFacadeCglib реализует MethodInterceptor {
цель частного объекта;
/**
* Создать прокси-объект
*
* @param цель
* @возвращаться
*/
общественный объект getInstance (цель объекта) {
this.target = цель;
Enhancer Enhancer = новый Enhancer();
Enhancer.setSuperclass(this.target.getClass());
// метод обратного вызова
Enhancer.setCallback(это);
//Создаем прокси-объект
вернуть Enhancer.create();
}
@Override
// метод обратного вызова
перехват общедоступного объекта (Object obj, метод метода, Object[] args,
Прокси-сервер MethodProxy) выдает Throwable {
System.out.println("Все начинается");
proxy.invokeSuper(obj, args);
System.out.println("Конец всему");
вернуть ноль;
}
}
4. ТестCglib.java
Скопируйте код кода следующим образом:
пакет net.battier.test;
импортировать net.battier.dao.impl.BookFacadeImpl1;
импортировать net.battier.proxy.BookFacadeCglib;
общественный класс TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib = новый BookFacadeCglib ();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}