Динамический прокси-сервер Java часто используется для переноса исходных вызовов методов, чтобы улучшить или переписать логику существующих методов.Он широко используется в области технологии Java.Вы можете увидеть его в сериализации платформы Ali Sofa RPC, Hibernate.Улучшение функции класс сущности также решается с помощью динамического прокси, и им также решается функция AOP прав хвастовства Spring. Далее давайте рассмотрим пример, который используется для печати предложения до и после вызова исходного метода, что также является усовершенствованием исходного метода класса.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface IHello {
void say(String s);
}
// 待加强的目标类
class RealHello implements IHello {
@Override
public void say(String s) {
System.out.println("hello " + s);
}
}
// 增强器
class HelloDelegate implements InvocationHandler {
private IHello target; // 原始对象
public HelloProxy(IHello target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before print");
method.invoke(target, args); // 调用原始对象的方法
System.out.println("after print");
return null;
}
}
public class DynamicProxy {
public static void main(String[] args) {
IHello hello = enhanceHello(new RealHello()); # 增强原始方法
hello.say("world");
}
public static IHello enhanceHello(IHello target) {
return (IHello) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class<?>[] { IHello.class },
new HelloDelegate(target));
}
}
вывод
before print
hello world
after print
Для простоты понимания мы используем диаграммы для представления взаимосвязей вышеуказанных объектов. мы называемProxy.newProxyInstance
Генерируется экземпляр анонимного класса, который также реализует интерфейс IHello, и его роль заключается в замене нативного.RealHello
пример. Этот анонимный экземпляр содержит ссылку на экземпляр HelloDelegate, и когда вы выполняете вызов метода для этого анонимного экземпляра, он делегирует логику вызова методу вызова экземпляра HelloDelegate. Экземпляр HelloDelegate также содержит ссылку на собственный объект RealHello, поэтому пользователь может реализовать любую дополнительную логику в методе вызова и вызвать собственный объект RealHello.
Вышеупомянутая технология динамического прокси, которая поставляется с jdk, Ее недостаток заключается в том, что интерфейс должен быть определен для реализации улучшения метода целевого объекта, и даже невозможно использовать абстрактный класс для его замены. Поэтому на рынке с открытым исходным кодом появилось несколько динамических прокси-библиотек, которые заменили нативную технологию динамического прокси jdk.Они не только более мощные, но и используют внутренние усовершенствования байт-кода, а их производительность также лучше, чем нативная jdk, намного выше.
javaassist
javaassist — наиболее широко используемая библиотека с открытым исходным кодом для динамических прокси. Ниже мы используем javaassist для реализации примера улучшения исходного метода без определения интерфейса.
import java.lang.reflect.Method;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
class RealHello {
public void say(String s) {
System.out.println("hello " + s);
}
}
class HelloDelegate<T> implements MethodHandler {
private T target;
public HelloDelegate(T target) {
this.target = target;
}
@Override
public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Throwable {
System.out.println("before print");
method.invoke(target, args);
System.out.println("after print");
return null;
}
}
public class DynamicProxy {
public static void main(String[] args) {
RealHello hello = enhanceHello(new RealHello());
hello.say("world");
}
@SuppressWarnings("unchecked")
public static <T> T enhanceHello(T target) {
ProxyFactory proxy = new ProxyFactory();
proxy.setSuperclass(RealHello.class);
try {
HelloDelegate<T> delegate = new HelloDelegate<T>(target);
// create方法传递了两个空数组
// 分别代表构造器的参数类型数组和构造器的参数实例数组
return (T) proxy.create(new Class<?>[0], new Object[0], delegate);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
вывод
before print
hello world
after print
Похоже, он не сильно отличается от динамического прокси, предоставляемого родным jdk, и эффект тот же. Просто здесь все гораздо проще, опуская определение класса интерфейса. ProxyFactory javaassist также предоставляет фильтры методов, которые могут выборочно улучшать определенные методы.
Python
Python — это динамический язык, и он смеется над описанными выше сложными методами динамического прокси.
Давайте посмотрим, как Python реализует так называемую динамическую прокси-функцию.
class Proxy(object):
def __init__(self, target):
self.target = target
def __getattribute__(self, name):
target = object.__getattribute__(self, "target")
attr = object.__getattribute__(target, name)
def newAttr(*args, **kwargs): # 包装
print "before print"
res = attr(*args, **kwargs)
print "after print"
return res
return newAttr
class RealHello(object):
def prints(self, s):
print 'hello', s
if __name__ == '__main__':
t = RealHello()
p = Proxy(t)
p.prints("world")
вывод
before print
hello world
after print
мы использовали магию__getattribute__
метод. В Python все атрибуты (методы) класса являются объектами.Сначала мы получаем объект метода класса.attr
, затем оберните объект метода класса, а затем верните обернутый новый объект методаnewAttr
.
Обратите внимание, что при получении целевого объекта вы не можете использовать его напрямуюself.target
, потому что self.target будет вызван снова__getattribute__
метод, который приведет к бесконечному циклу и заставит стек быть слишком глубоким, чтобы выдать исключение. Вместо этого вы должны использоватьobject.__getattribute__
метод для получения значения свойства объекта.
Выше приведено решение для реализации динамического прокси в Python Читатели, как вы думаете, Python проще? Все желающие могут поругаться в комментариях.
Читайте больше интересных статей, обратите внимание на паблик-аккаунт "Code Cave"