Inhaltsverzeichnis
Konzept
Fall
statischer Proxy
Dynamischer JDK-Proxy-Modus
Heim Java javaLernprogramm So implementieren Sie den dynamischen JDK-Proxy in Java

So implementieren Sie den dynamischen JDK-Proxy in Java

Apr 30, 2023 am 08:49 AM
java jdk

Konzept

Agent: Um das A-Objekt zu steuern, wird ein neues B-Objekt erstellt und das B-Objekt führt stattdessen alle Operationen des A-Objekts aus , der als Agent bezeichnet wird. Die Einrichtung eines Agentursystems umfasst drei beteiligte Rollen: reales Objekt (A), Proxy-Objekt (B) und Kunde.

Das Proxy-Objekt (B) spielt eine Vermittlerrolle und verbindet das reale Objekt (A) und den Client. Bei weiterer Erweiterung kann das Proxy-Objekt komplexere Logik implementieren, beispielsweise die Zugriffskontrolle für das reale Objekt Objekt.

Fall

Anforderungen: Die Mitarbeiter-Business-Layer-Schnittstelle erfordert eine Administratorberechtigung zum Speichern von Anrufen, und für die Anrufliste ist keine Berechtigung erforderlich, wenn ein Anruf ohne Erlaubnis erfolgt.

statischer Proxy

/**
 * 代理接口
 */
public interface IEmployeeService {
    void save();
 
    void list();
}
Nach dem Login kopieren
/**
 * 真实对象
 */
public class EmployeeServiceImpl implements IEmployeeService {
    @Override
    public void save() {
        System.out.println("EmployeeServiceImpl-正常的save....");
    }
    @Override
    public void list() {
        System.out.println("EmployeeServiceImpl-正常的list....");
    }
}
Nach dem Login kopieren
/**
 * 模拟当前登录用户对象
 */
public class SessionHolder {
    private static String currentUser;
    public static String  getCurrentUser(){
        return currentUser;
    }
    public static void   setCurrentUser(String currentUser){
        SessionHolder.currentUser = currentUser;
    }
}
Nach dem Login kopieren
/**
 * 代理对象
 */
public class EmployeeProxy implements IEmployeeService {
    //真实对象
    private EmployeeServiceImpl employeeService;
    public EmployeeProxy(EmployeeServiceImpl employeeService){
        this.employeeService = employeeService;
    }
    @Override
    public void save() {
        //权限判断
        if("admin".equals(SessionHolder.getCurrentUser())){
            employeeService.save();
        }else{
            throw new RuntimeException("当前非admin用户,不能执行save操作");
        }
    }
    @Override
    public void list() {
        employeeService.list();
    }
}
Nach dem Login kopieren
public class App {
    public static void main(String[] args) {
        System.out.println("----------------真实对象--------------------");
        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();
        employeeService.list();
        employeeService.save();
        System.out.println("----------------代理对象--------------------");
        SessionHolder.setCurrentUser("dafei");  //设置权限(当前登录用户)
        EmployeeProxy employeeProxy = new EmployeeProxy(employeeService);
        employeeProxy.list();
        employeeProxy.save();
    }
}
Nach dem Login kopieren
----------------真实对象--------------------
EmployeeServiceImpl-正常的list....
EmployeeServiceImpl-正常的save....
----------------代理对象--------------------
EmployeeServiceImpl-正常的list....
Exception in thread "main" java.lang.RuntimeException: 当前非admin用户,不能执行save操作
	at com.langfeiyes.pattern.proxy.demo.EmployeeProxy.save(EmployeeProxy.java:20)
	at com.langfeiyes.pattern.proxy.demo.App.main(App.java:16)
Nach dem Login kopieren

Beim direkten Aufruf über das reale Objekt EmployeeServiceImpl kann sowohl auf die Liste als auch auf das Speichern direkt zugegriffen werden, es erfüllt jedoch nicht die Anforderungen an die Administratorberechtigungsbeschränkungen. Wenn Sie das Proxy-Objekt EmployeeProxy verwenden, können Sie die Anforderungen erfüllen.

Vervollständigen Sie die Proxy-Logik, indem Sie direkt eine neue Klasse von Proxy-Objekten erstellen. Diese Methode wird als statischer Proxy-Modus bezeichnet.

Dynamischer JDK-Proxy-Modus

Zu den häufig verwendeten dynamischen Proxy-Modi in Java gehören der dynamische JDK-Proxy und der dynamische Cglib-Proxy. Hier konzentrieren wir uns auf den dynamischen JDK-Proxy 🎜#Immer noch die ursprüngliche Anforderung, der vorherige IEmployeeService EmployeeServiceImpl SessionHolder hat sich nicht geändert, ein neuer JDK-Proxy-Controller-EmployeeInvocationHandler

/**
 * jdk动态代理控制类,由它牵头代理类获取,代理方法的执行
 */
public class EmployeeInvocationHandler  implements InvocationHandler {
    //真实对象-EmployeeServiceImpl
    private Object target;
    public EmployeeInvocationHandler(Object target){
        this.target = target;
    }
    //获取jvm在内存中生成代理对象
    public Object getProxy(){
        return  Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }
    //代理对象控制执行方法
    //参数1:代理对象
    //参数2:真实对象的方法(使用方式得到方法对象)
    //参数3:真实对象方法参数列表
    //此处是代理对象对外暴露的可编辑的方法处理场所,代理对象每调用一个次方法,就会执行一次invoke
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        if("save".equals(name) && !"admin".equals(SessionHolder.getCurrentUser())){
            throw new RuntimeException("当前非admin用户,不能执行save操作");
        }
        return method.invoke(target, args);
    }
}
Nach dem Login kopieren

Die Test-App-Klasse wurde leicht geändert:

# 🎜🎜#

public class App {
    public static void main(String[] args) {
        System.out.println("----------------真实对象--------------------");
        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();
        employeeService.list();
        employeeService.save();
 
        System.out.println("----------------代理对象--------------------");
        SessionHolder.setCurrentUser("dafei");
        EmployeeInvocationHandler handler = 
            new EmployeeInvocationHandler(employeeService);
        IEmployeeService proxy = (IEmployeeService) handler.getProxy();
        proxy.list();
        proxy.save();
 
    }
}
Nach dem Login kopieren
Der obige Code kann auch die Anforderungen erfüllen. Der Unterschied zum statischen Proxy besteht darin, dass weniger Proxy-Objekte erstellt werden. An dieser Stelle stellt sich die Frage: Warum kann der Proxy-Klassenaufruf implementiert werden? ?

Prinzipielle Analyse

Lassen Sie uns zunächst die Schlussfolgerung ziehen: Das zugrunde liegende Implementierungsprinzip des dynamischen JDK-Proxys: Verwenden Sie dann die Schnittstellenimplementierungsmethode, um zur Laufzeit dynamisch eine Klasse zu erstellen kompilieren und ausführen. Diese Klasse wird nur einmal verwendet. Wenn die JVM gestoppt wird, verschwindet die Proxy-Klasse.

Teilnehmende Rolle

Um das Prinzip des dynamischen JDK-Proxys zu verstehen, müssen Sie zunächst die am dynamischen JDK-Proxy beteiligten Klassen verstehen

#🎜🎜 #

InvocationHandlerSo implementieren Sie den dynamischen JDK-Proxy in Java: Aufrufhandler für echte Objektmethoden, integrierte Aufrufmethode, ihre Funktion: Proxy-Logik für reale Objekte anpassen

#🎜🎜 #EmployeeInvocationHandler#🎜 🎜#: Handler für reale Objektmethoden des Mitarbeiterdienstes. Diese Klasse hat drei Zwecke: 1> Festlegen des realen Objekts

     //真实对象-EmployeeServiceImpl
    private Object target;
    public EmployeeInvocationHandler(Object target){
        this.target = target;
    }
Nach dem Login kopieren
2> Anpassen der Implementierungslogik der Proxy-Methode

#🎜 🎜# um real zu sein. Die Methode zum Speichern von Objekten fügt Berechtigungsüberprüfungslogik hinzu.

    //代理对象控制执行方法
    //参数1:代理对象
    //参数2:真实对象的方法(使用方式得到方法对象)
    //参数3:真实对象方法参数列表
    //此处是代理对象对外暴露的可编辑的方法处理场所,代理对象每调用一个次方法,就会执行一次invoke
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        if("save".equals(name) && !"admin".equals(SessionHolder.getCurrentUser())){
            throw new RuntimeException("当前非admin用户,不能执行save操作");
        }
        return method.invoke(target, args);
    }
Nach dem Login kopieren
3> wobei X die Seriennummer ist, im Allgemeinen standardmäßig 0), wird diese Proxy-Klasse dynamisch vom JDK erstellt.
    //获取jvm在内存中生成代理对象
    public Object getProxy(){
        return  Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }
Nach dem Login kopieren

Proxy

: Die dynamische Proxy-Steuerklasse ist die übergeordnete Klasse der vom JDK dynamisch generierten $ProxyX-Klasse. Ihre Funktion ist wie folgt:

1>By Aufruf der ProxyBuilder-Klasse Die Builder-Methode erstellt die Proxy-Objektklasse

private static Constructor<?> getProxyConstructor(Class<?> caller,
                                                      ClassLoader loader,
                                                      Class<?>... interfaces){
            return proxyCache.sub(intf).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
}
Nach dem Login kopieren

2> gibt eine Instanz der $ProxyX-Klasse über die newProxyInstance-Methode

   public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
    //...
   }
Nach dem Login kopieren

$Proxy0 zurück

: App-Klassenlaufzeit, die vom JDK dynamisch erstellte Proxy-Klasse, geerbt von der Proxy-Klasse

public class App {
    public static void main(String[] args) {
        //System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        System.out.println("----------------真实对象--------------------");
        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();
        employeeService.list();
        employeeService.save();
        System.out.println("----------------代理对象--------------------");
        SessionHolder.setCurrentUser("dafei");
        EmployeeInvocationHandler handler = 
                     new EmployeeInvocationHandler(employeeService);
        IEmployeeService proxy = (IEmployeeService) handler.getProxy();
        proxy.list();
        proxy.save();
 
    }
}
Nach dem Login kopieren
Standardmäßig speichert die JVM keine dynamisch erstellten Proxy-Klassen-Bytecode-Objekte. Sie können das konfigurieren Proxy-Parameter in der Hauptmethode, um Bytes zuzulassen Code-Aufbewahrung
//JDK8之前
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//JDK8之后
System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
Nach dem Login kopieren

Nach der Ausführung wird das Bytecode-Objekt der Proxy-Klasse im Projektstammverzeichnis generiert.

Um die Interpretation zu erleichtern, nach dem Entfernen einiger unnötiger Methoden

$Proxy0-Klasse#🎜🎜 #

public class $Proxy0 extends Proxy implements IEmployeeService {
    private static Method m4;
    private static Method m3;
    static {
        try {
            m4 = Class.forName("com.langfeiyes.proxy.demo.IEmployeeService")
                 .getMethod("save");
            m3 = Class.forName("com.langfeiyes.proxy.demo.IEmployeeService")
                 .getMethod("list");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public $Proxy0(InvocationHandler var1) throws Throwable {
        super(var1);
    }
    public final void save() throws Throwable {
        super.h.invoke(this, m4, (Object[])null);
    }
 
    public final void list() throws  Throwable{
        super.h.invoke(this, m3, (Object[])null);
    }
}
Nach dem Login kopieren

Aus dem Quellcode die Eigenschaften von $Proxy0: So implementieren Sie den dynamischen JDK-Proxy in Java

1>Erbt die Proxy-Klasse , implementiert die IEmployeeService-Schnittstelle

2> spiegelt die Speicher- und Listenmethoden der IEmployeeService-Schnittstelle über statische Blöcke wider, um ihre Methodenobjekte abzurufen. Methode

    3> Um den übergeordneten Klassenkonstruktor aufzurufen, müssen Sie den InvocationHandler-Parameter übergeben Die IEmployeeService-Schnittstelle basiert auf der .invoke-Methode des h-Attributs der übergeordneten Klasse Proxy
  • Die Wahrheit wird enthüllt
  • Alle teilnehmenden Klassen im dynamischen Proxy werden unten angezeigt: #🎜 🎜#
  • Das Bild unten ist das Betriebszeitdiagramm des obigen Bildes, folgen Sie ihm einfach#🎜 🎜#
  • # 🎜🎜#

Das obige ist der detaillierte Inhalt vonSo implementieren Sie den dynamischen JDK-Proxy in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
2 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Repo: Wie man Teamkollegen wiederbelebt
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Abenteuer: Wie man riesige Samen bekommt
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Quadratwurzel in Java Quadratwurzel in Java Aug 30, 2024 pm 04:26 PM

Leitfaden zur Quadratwurzel in Java. Hier diskutieren wir anhand eines Beispiels und seiner Code-Implementierung, wie Quadratwurzel in Java funktioniert.

Perfekte Zahl in Java Perfekte Zahl in Java Aug 30, 2024 pm 04:28 PM

Leitfaden zur perfekten Zahl in Java. Hier besprechen wir die Definition, Wie prüft man die perfekte Zahl in Java?, Beispiele mit Code-Implementierung.

Zufallszahlengenerator in Java Zufallszahlengenerator in Java Aug 30, 2024 pm 04:27 PM

Leitfaden zum Zufallszahlengenerator in Java. Hier besprechen wir Funktionen in Java anhand von Beispielen und zwei verschiedene Generatoren anhand ihrer Beispiele.

Weka in Java Weka in Java Aug 30, 2024 pm 04:28 PM

Leitfaden für Weka in Java. Hier besprechen wir die Einführung, die Verwendung von Weka Java, die Art der Plattform und die Vorteile anhand von Beispielen.

Armstrong-Zahl in Java Armstrong-Zahl in Java Aug 30, 2024 pm 04:26 PM

Leitfaden zur Armstrong-Zahl in Java. Hier besprechen wir eine Einführung in die Armstrong-Zahl in Java zusammen mit einem Teil des Codes.

Smith-Nummer in Java Smith-Nummer in Java Aug 30, 2024 pm 04:28 PM

Leitfaden zur Smith-Zahl in Java. Hier besprechen wir die Definition: Wie überprüft man die Smith-Nummer in Java? Beispiel mit Code-Implementierung.

Fragen zum Java Spring-Interview Fragen zum Java Spring-Interview Aug 30, 2024 pm 04:29 PM

In diesem Artikel haben wir die am häufigsten gestellten Fragen zu Java Spring-Interviews mit ihren detaillierten Antworten zusammengestellt. Damit Sie das Interview knacken können.

Brechen oder aus Java 8 Stream foreach zurückkehren? Brechen oder aus Java 8 Stream foreach zurückkehren? Feb 07, 2025 pm 12:09 PM

Java 8 führt die Stream -API ein und bietet eine leistungsstarke und ausdrucksstarke Möglichkeit, Datensammlungen zu verarbeiten. Eine häufige Frage bei der Verwendung von Stream lautet jedoch: Wie kann man von einem Foreach -Betrieb brechen oder zurückkehren? Herkömmliche Schleifen ermöglichen eine frühzeitige Unterbrechung oder Rückkehr, aber die Stream's foreach -Methode unterstützt diese Methode nicht direkt. In diesem Artikel werden die Gründe erläutert und alternative Methoden zur Implementierung vorzeitiger Beendigung in Strahlverarbeitungssystemen erforscht. Weitere Lektüre: Java Stream API -Verbesserungen Stream foreach verstehen Die Foreach -Methode ist ein Terminalbetrieb, der einen Vorgang für jedes Element im Stream ausführt. Seine Designabsicht ist

See all articles