После прочтения технологии динамических прокси в Java - Pythoner улыбнулся

Java задняя часть Python открытый источник
После прочтения технологии динамических прокси в Java - Pythoner улыбнулся

Динамический прокси-сервер 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"