Heim  >  Artikel  >  Java  >  Vollständige Beherrschung dynamischer Java-Proxys

Vollständige Beherrschung dynamischer Java-Proxys

WBOY
WBOYnach vorne
2022-07-26 13:55:021624Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über Java. Dynamischer Proxy bedeutet, dass die Beziehung zwischen der Proxy-Klasse und der Zielklasse bestimmt wird, wenn das Programm ausgeführt wird. Die Methode, mit der der Kunde das Zielobjekt über die Proxy-Klasse aufruft Das Proxy-Objekt der Zielklasse wird bei Bedarf dynamisch erstellt, wenn das Programm ausgeführt wird. Im Folgenden werden das Prinzip und die Implementierung des dynamischen Java-Proxy anhand von Beispielen ausführlich erläutert. Ich hoffe, dass dies für alle hilfreich ist.

Vollständige Beherrschung dynamischer Java-Proxys

Empfohlene Studie: „Java-Video-Tutorial

Ich glaube, jeder kennt das Wort „Agent“. Einfach ausgedrückt bedeutet es, Waren im Namen des Herstellers zu verkaufen, und der Agent ersetzt den Hersteller, um ihn zu verkaufen Waren, und Kunden finden Agenten, um Waren zu kaufen. Das heißt: 1) Die Beziehung zwischen Kunde und Hersteller ist unsichtbar und der Kunde weiß nicht, wer der Hersteller dahinter ist. 2) Agenten können Kunden „positionieren“ und gezielter an die bedürftigen Kundengruppen verkaufen.

Proxy-Modus

Proxy-Modus: Stellen Sie einen Proxy für andere Objekte bereit, um den Zugriff auf dieses Objekt zu steuern, dh erstellen Sie ein Proxy-Objekt als Vermittler zwischen dem Client und dem Zielobjekt. Der Hauptzweck besteht darin, das Zielobjekt zu schützen Verbessern Sie die Zielobjekte

Die Verwendung des Proxy-Musters hat normalerweise die folgenden zwei Vorteile:

1) Es kann die Implementierung der Proxy-Klasse verbergen

2) Es kann die Entkopplung zwischen dem Client und der Proxy-Klasse realisieren, ohne den Code zu ändern In diesem Fall kann eine zusätzliche Verarbeitung durchgeführt werden

Statischer Proxy

Der sogenannte dynamische Proxy besteht darin, auf das Quellobjekt zuzugreifen, indem eine klare Proxy-Klasse deklariert wird Da es sich um n Arten von Produkten handelt, werden N Agenten benötigt, was der Geschäftsentwicklung nicht förderlich ist.

Beispiel: Wir haben zwei Schnittstellen, Maus und Tastatur. Jede Schnittstelle hat eine Implementierungsklasse call Geben Sie vor sell() einen Satz über das Pre-Sales-Verständnis und nach dem Aufruf einen Satz über den After-Sales-Service aus

Dann müssen wir nur noch zwei Proxy-Klassen MouseProxyschreiben > und KeyboardProxy

public class LogitechMouse implements Mouse{
    @Override
    public void sell() {
        System.out.println("出售罗技鼠标");
    }
}
public class HHKBKeyboard implements Keyboard{
    @Override
    public void sell() {
        System.out.println("出售HHKB键盘");
    }
}

Die endgültige Ausführung ist:

public class MouseProxy implements Mouse {
    private Mouse mouse;

    public MouseProxy(Mouse mouse) {
        this.mouse = mouse;
    }
    @Override
    public void sell() {
        System.out.println("售前了解");
        mouse.sell();
        System.out.println("售后服务");
    }
}
public class KeyboardProxy implements Keyboard{
    private Keyboard keyboard;
    public KeyboardProxy(Keyboard keyboard) {
        this.keyboard = keyboard;
    }
    @Override
    public void sell() {
        System.out.println("售前了解");
        keyboard.sell();
        System.out.println("售后服务");
    }
}

Ausgabe:
Vorverkaufsverständnis
Verkauf einer Logitech-Maus
KundendienstVorverkaufsverständnis
Verkauf einer HHKB-Tastatur
Kundendienst

Der Code des statischen Proxys ist sehr einfach und leicht zu verstehen, obwohl dieses Modell gut ist offensichtliche Mängel:

sell()前输出一句售前了解,调用后输出一句售后服务

那我们只需写两个代理类MouseProxyKeyboardProxy

public class Test {
    public static void main(String[] args) {
        Mouse logitechMouse = new LogitechMouse();
        MouseProxy mouseProxy = new MouseProxy(logitechMouse);
        mouseProxy.sell();
        Keyboard hhkbKeyboard = new HHKBKeyboard();
        KeyboardProxy keyboardProxy = new KeyboardProxy(hhkbKeyboard);
        keyboardProxy.sell();
    }
}

最终执行为:

public class JDKProxy implements InvocationHandler {
    private Object object;
    public JDKProxy(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("售前了解");
        Object invoke = method.invoke(object, args);
        System.out.println("售后服务");
        return invoke;
    }
}

输出:
售前了解
出售罗技鼠标
售后服务
售前了解
出售HHKB键盘
售后服务

静态代理的代码非常简单易懂,这种模式虽好,但是也有明显的缺点:

  • 会存在大量冗余的代理类,这里只有两个接口,如果有n个接口,那么就要定义n个代理类。
  • 不易维护,一旦接口更改,代理类和被代理类都要更改。

那么这个时候就可以使用动态代理来解决了

动态代理

代理类在程序运行时创建代理的方式叫动态代理,也就是说代理类并不是在java代码中定义的,而是在运行的时候动态生成的

JDK动态代理

JDK从1.3版本就开始支持动态代理类的创建。主要核心类只有2个:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandlerEs wird eine große Anzahl redundanter Proxy-Klassen geben, und hier gibt es nur zwei Schnittstellen. Wenn es n Schnittstellen gibt, müssen n Proxy-Klassen definiert werden.

Es ist nicht einfach zu warten. Sobald sich die Schnittstelle ändert, müssen sowohl die Proxy-Klasse als auch die Proxy-Klasse geändert werden.

Dann können Sie zu diesem Zeitpunkt einen dynamischen Proxy verwenden, um das Problem zu lösen

Dynamischer Proxy

Die Art und Weise, wie die Proxy-Klasse den Proxy erstellt, wenn das Programm ausgeführt wird, wird als dynamischer Proxy bezeichnet, was bedeutet, dass die Proxy-Klasse nicht in definiert ist Der Java-Code, aber der

Dynamische JDK-Proxy wird zur Laufzeit dynamisch generiert

JDK unterstützt seit Version 1.3 die Erstellung dynamischer Proxy-Klassen. Es gibt nur zwei Hauptkernklassen: java.lang.reflect.Proxy und java.lang.reflect.InvocationHandler

Im obigen Beispiel wird der dynamische JDK-Proxy wie folgt verwendet :

public class Test {
    public static void main(String[] args) {
        Mouse logitechMouse = new LogitechMouse();
        JDKProxy jdkProxy = new JDKProxy(logitechMouse);
        Mouse mouse= (Mouse)Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Mouse.class}, jdkProxy);
        mouse.sell();
        HHKBKeyboard hhkbKeyboard = new HHKBKeyboard();
        JDKProxy jdkProxy1 = new JDKProxy(hhkbKeyboard);
        Keyboard keyboard = (Keyboard)Proxy.newProxyInstance(jdkProxy1.getClass().getClassLoader(), new Class[]{Keyboard.class}, jdkProxy1);
        keyboard.sell();
    }
}

Wenn wir die Methode des Proxy-Klassenobjekts aufrufen, wird dieser „Aufruf“ an die Aufrufmethode übergeben.

Das Proxy-Klassenobjekt wird als Proxy-Parameter übergeben.

Die Parametermethode identifiziert die Proxy-Klasse, die wir aufrufen.

args sind die Parameter dieser Methode.

Auf diese Weise werden alle unsere Aufrufe von Methoden in der Proxy-Klasse zu Aufrufen zum Aufrufen, sodass wir der Aufrufmethode eine einheitliche Verarbeitungslogik hinzufügen können (wir können auch unterschiedliche Methoden für verschiedene Proxy-Klassen basierend auf dem Methodenparameter erstellen). Verarbeitung). Daher können wir das Pre-Sales-Verständnis in der Aufrufmethode der Zwischenklasse implementieren, dann die Methode der Proxy-Klasse aufrufen und dann den After-Sales-Service bereitstellen.

  • Führen Sie den Code aus
  • public class CGLIBProcy implements MethodInterceptor {
        private Enhancer enhancer = new Enhancer();
        private Object object;
        public CGLIBProcy(Object object) {
            this.object = object;
        }
        public Object getProxy(){
            //设置需要创建子类的类
            enhancer.setSuperclass(object.getClass());
            enhancer.setCallback(this);
            //创建代理对象
            return enhancer.create();
        }
        // o: cglib 动态生成的代理类的实例
        // method:实体类所调用的都被代理的方法的引用
        // objects 参数列表
        // methodProxy:生成的代理类对方法的代理引用
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("售前了解");
            Object invoke = method.invoke(object, objects);
            System.out.println("售后处理");
            return invoke;
        }
    }
  • Sie sehen, dass unabhängig von der Anzahl der Schnittstellen nur eine Proxy-Klasse benötigt wird.
  • CGLIB dynamischer Proxy
Agentenklasse:

public class Test {
    public static void main(String[] args) {
        Mouse logitechMouse = new LogitechMouse();
        CGLIBProcy cglibProcy = new CGLIBProcy(logitechMouse);
        Mouse proxy = (Mouse)cglibProcy.getProxy();
        proxy.sell();
        cglibProcy = new CGLIBProcy(new HHKBKeyboard());
        Keyboard keyboard = (Keyboard)cglibProcy.getProxy();
        keyboard.sell();
    }
}
Ausführungscode: rrreee

Der Unterschied zwischen JDK-Proxy und CGLIB-Proxy🎜🎜🎜JDK dynamischer Proxy implementiert die Schnittstelle, CGLIB dynamische Vererbungsidee🎜🎜JDK dynamischer Proxy (wenn das Ziel Objekt hat eine Schnittstelle) Die Ausführungseffizienz ist höher als bei CIGLIB. 🎜🎜 Wenn das Objekt über eine Schnittstellenimplementierung verfügt, wählen Sie den JDK-Proxy. Wenn keine Schnittstellenimplementierung vorhanden ist, wählen Sie den CGILB-Proxy. 🎜

Das obige ist der detaillierte Inhalt vonVollständige Beherrschung dynamischer Java-Proxys. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:jb51.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen