[Java-Grundlagen] Vertiefendes Verständnis der Reflexion und Anwendung der Reflexion (Fabrikmodus, Proxy-Modus)

1. Was ist der Java-Reflexionsmechanismus?

Der Java-Reflexionsmechanismus bezieht sich auf die 运行时动态地获取和操作类的信息、调用对象的方法和访问对象的属性的能力. Durch Reflexion können Struktur, Verhalten und Zustand von Klassen analysiert und geändert werden, während das Programm ausgeführt wird.

Der Java-Reflexionsmechanismus bietet die folgenden Funktionen:

  1. Klasseninformationen abrufen: Sie können den Klassennamen, Modifikatoren, die übergeordnete Klasse, die implementierte Schnittstelle usw. abrufen.
  2. Objekte erstellen: Objekte können durch Reflektion instanziiert werden, auch wenn der spezifische Klassenname nicht bekannt ist.
  3. Methode aufrufen: Sie können die Methoden der Klasse durch Reflektion abrufen und diese Methoden aufrufen.
  4. Auf Felder zugreifen und diese ändern: Feldwerte von Klassen können durch Reflektion ermittelt und festgelegt werden.
  5. Dynamischer Proxy: Mithilfe von Reflection können Sie Proxy-Objekte dynamisch generieren, um AOP (aspektorientierte Programmierung) und andere Funktionen zu implementieren.
  6. Manipulieren von Arrays: Array-Objekte können durch Reflektion erstellt, aufgerufen und geändert werden.
  7. Anmerkungsverarbeitung: Anmerkungen zu Klassen, Methoden und Feldern können durch Reflexion erhalten und entsprechend verarbeitet werden.

Es kann über den Reflexionsmechanismus 运行时动态地操作类和对象,解耦了编译时的依赖关系,提供了更大的灵活性和扩展性。verwendet werden. Es ist jedoch zu beachten, dass die Leistung beeinträchtigt werden kann und zusätzliche Berechtigungen erforderlich sind, da bei der Reflexion die Klassenstruktur dynamisch generiert und geändert wird.

1.2 Java-Reflexionsbeispiel

Ortho:
Wenn wir unter normalen Umständen eine bestimmte Klasse verwenden, kennen wir die Klasse und wissen, wofür wir sie verwenden sollen. Wir können sie direkt übergeben new实例化创建对象und dann dieses Objekt verwenden, um die Klasse zu bearbeiten. Dies gehört zur
Klasse Orthographic ~ Student

		public class Student {
    
    
		    private int id;
		
		    public void setId(int id) {
    
    
		        this.id = id;
		    }
		    public int getId() {
    
    
		        return this.id;
		    }
		}
		Student student = new Student();
        student.setId(1);
        System.out.println("正射获取ID :"+student.getId());
        
		//输出:正射获取ID :1

Orthographie ist leicht zu verstehen, daher werde ich nicht viel darüber sagen. Lassen Sie uns nun über Reflexion sprechen. Sie können auch Objekte erstellen, Objektmethoden aufrufen usw. Was Sie mit Orthographie tun können, kann durch Reflexion erreicht werden.
Betrachtung:
Reflexion steht am Anfang und dient hauptsächlich dazu 不知道要初始化的是什么类, zu erreichen, dass zur Laufzeit nur bekannt ist, welche Klasse betrieben werden soll, und dies ist Reflexion无法使用new来实例化创建对象JDK提供的反射API获取到类的完整构造以及调用对应的方法

		//1、通过 Class.forName 方法获取 Srudent类的 Class 对象
        Class<?> clz = Class.forName("Reflect.Student");  
		//2、通过 getConstructor 方法获取类的无参构造方法
      //  Constructor<?> constructor = clz.getConstructor();//可省略
        //3、通过 newInstance 方法实例化对象
       // Object stu = constructor.newInstance();//可省略
       Student stu = (Student) clz.newInstance();//(代替2-3)直接通过字节码对象Class.newInstance()实例化对象
		//4、通过 getMethod 方法获取类的方法信息("setId", int.class) setId为方法名  int.class为方法参数类型
        Method setId = clz.getMethod("setId", int.class);
        //5、通过 invoke 方法调用该方法
        setId.invoke(stu,3);
       //也可以直接通过对象stu   调用Student类的方法
        Method getId = clz.getMethod("getId");
       
        System.out.println("反射获取ID :"+getId.invoke(stu));
        
		//输出:反射获取ID :3

Die Zusammenfassung lautet:
Der im obigen Beispiel dargestellte Aufrufprozess ist, wie Sie sehen können 获取一个类的反射对象, der Hauptprozess:

  1. Rufen Sie das Klasseninstanzobjekt der Klasse ab
  2. Rufen Sie das Konstruktorobjekt entsprechend dem Klasseninstanzobjekt ab
  3. Rufen Sie dann das Reflexionsobjekt der Klasse gemäß der newInstance-Methode des Konstruktorobjekts ab

获取到类的反射对象后,就可以对类进行操作了~ Der Prozess zum Aufrufen der Methode der Klasse im obigen Beispiel ist beispielsweise:

  1. Rufen Sie das Methodenobjekt der Klasse gemäß dem Klasseninstanzobjekt ab

  2. Rufen Sie dann die Methode der jeweiligen Klasse entsprechend der Aufrufmethode des Methodenobjekts auf

Im umgekehrten Aufrufprozess des obigen Beispiels Class.forName("类的全局定名")erhalten wir auf diese Weise das Klasseninstanzobjekt der Klasse. Darüber hinaus gibt es zwei weitere häufig verwendete

2. Welche drei Möglichkeiten gibt es, eine Klasse im Java-Reflexionsmechanismus zu erhalten, und welche Unterschiede gibt es?

Es gibt drei gängige Möglichkeiten, das java.lang.Class-Instanzobjekt einer Klasse abzurufen:

  1. Durch MyClass.classden Erhalt bezieht sich MyClass hier auf die spezifische Klasse ~~
  2. Durch Class.forName("类的全局定名")den Erwerb ist der globale Name Paketname + Klassenname
  3. Durch new MyClass().getClass()den Erhalt bezieht sich MyClass hier auf die spezifische Klasse ~
		Class<?> clz = Class.forName("Reflect.Student");		  //全类名获取
        Class<Student> clz = Student.class;                      //类.class获取
        Class<? extends Student> clz = new Student().getClass();//newClass().getClass()获取

Der Unterschied besteht darin:

  • Die über MyClass.class abgerufene JVM verwendet den ClassLoader-Klassenlader, um die Klasse in den Speicher zu ladenFührt keine Klasseninitialisierungsarbeit durch und gibt das java.lang.Class-Objekt zurück
  • Erhalten durch Class.forName („globale Benennung der Klasse“), wird die Klasse in ähnlicher Weise von der JVM in den Speicher geladen undEs führt eine statische Initialisierung der Klasse durch und gibt das java.lang.Class-Objekt zurück
  • Diese Methode wird von newMyClass().getClass() abgerufen und verwendetnew wird instanziiert, sodass sowohl die statische als auch die nicht statische Initialisierung funktionierenDie getClass-Methode gehört zur Methode in der Object-Klasse der obersten Ebene. Jedes Unterklassenobjekt kann aufgerufen werden, welche Unterklasse aufruft, und gibt das java.lang.Class-Objekt dieser Unterklasse zurück

Spezifische Manifestationen finden Sie unter dem Link: Justin in meinen drei Provinzen ----->Java-Reflexionsmechanismusprinzip, verschiedene Methoden zum Klassenerwerb und Anwendungsszenarien

Zusammenfassen:

  • MyClass.class不会做任何类的初始化工作
  • Class.forName führt den Unterricht durch静态初始化工作
  • new MyClass().getClass 静态初始化und 非静态初始化die Arbeit wird erledigt sein
  • Wenn Sie eine dieser drei Methoden verwenden, wird sie schließlich von der JVM in den Speicher geladen 内存地址相同(der übergeordnete Delegierungsmechanismus des JVM-Klassenladens, die Klasse wird nur einmal geladen).

3. Was sind die Anwendungsszenarien des Java-Reflexionsmechanismus?

3.1. Optimierung des statischen Factory-Modus (Entkopplung)

3.1.1 Vor der Optimierung (Kopplung von Fabrikklasse und Produktklasse)

Einfaches Fabrikbeispiel:

Schritt 1: Erstellen Sie eine abstrakte Produktklasse

public interface Product {
    
    
      void show();
}

Schritt 2: Erstellen Sie eine konkrete Produktklasse:

public class ProductA implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("生产了产品A");
    }
}
public class ProductB implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("生产了产品B");
    }
}

public class ProductC implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("生产了产品C");
    }
}

Schritt 3: Erstellen Sie eine einfache Factory-Klasse

/**
 * 静态工厂
 */
public class Product_factory {
    
    
	 /**
     * todo 常规工厂 (工厂和产品耦合)
     */
    public static Product createProduct(String productName) throws Exception {
    
    
        Product product = null;
        if ("A".equals(productName)) {
    
    
            product = new ProductA();

        }else if("B".equals(productName)){
    
    
            product = new ProductB();

        }else if("C".equals(productName)){
    
    
            product = new ProductC();

        }else{
    
    
            throw new Exception("没有该产品");
        }
        return product;
    }
}

Schritt 4: Rufen Sie die einfache Factory-Klasse auf

    public static void main(String[] args) throws Exception {
    
    

        //通过工厂生产对象A
        Product A = Product_factory.createProduct("A");
        //调用A对象的方法
        A.show();

        Product B = Product_factory.createProduct("B");
        B.show();

        Product C = Product_factory.createProduct("C");
        C.show();

    }

Ausgabe:

A产品被生产了
B产品被生产了
B产品被生产了

Nachteile vor der Optimierung
Jedes Mal, wenn eine Unterklasse einer Schnittstelle hinzugefügt wird, muss die Logik der Factory-Klasse geändert werden

Wenn ich beispielsweise ein Produkt C hinzufügen muss, muss ich die Fabrik ändern und den Produktionsprozess von Produkt C hinzufügen

public class ProductD implements Product{
    
    
    @Override
    public void show() {
    
    
        System.out.println("D产品被生产了");
    }
}

Fügen Sie hier eine Bildbeschreibung ein
Dies verstößt gegen das Prinzip des Öffnens und Schließens (beim Hinzufügen neuer Produkte sollte der ursprünglich vorhandene Code nicht geändert, sondern auf der ursprünglichen Basis erweitert werden).

Zu diesem Zeitpunkt kann die Reflexion diesen Nachteil überwinden (Entkopplung von Produkten und Fabriken).

3.1.2 Nach der Reflexionsoptimierung (Entkopplung von Fabrikklasse und Produktklasse)

Optimiert

Optimieren Sie die Factory-Klasse

    /**
     * todo 反射工厂(通过产品全类名来创建产品) (工厂和产品解耦合)
     */
    public static Product createProductReflect(String Full_product_name ) {
    
    
        Product product = null;
        try {
    
    
      	  //根据产品类的全类名反射生成产品类的class字节对象
            Class<?> aClass = Class.forName(Full_product_name);
            //通过产品类的字节码对象  创建真实对象
            product = (Product) aClass.newInstance();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
        return product;
    }

Testklasse:

        //全类名反射通过工厂生产产品
        Product A = Product_factory.createProductReflect("factory.Simple_factory.ProductA");
        A.show();

        Product B = Product_factory.createProductReflect("factory.Simple_factory.ProductB");
        B.show();

        Product C = Product_factory.createProductReflect("factory.Simple_factory.ProductC");
        B.show();

Ausgabe:

A产品被生产了
B产品被生产了
B产品被生产了

Wenn Sie also Produkt D hinzufügen möchten, müssen Sie nur Produkt D hinzufügen, ohne die Fabrik zu ändern. Sie müssen der Fabrik nur den vollständigen Klassennamen des Produkts eingeben, um das Produktklassenobjekt zu erstellen, und dann Produkt D hinzufügen Produkt D wird benötigt
.

public class ProductD implements Product{
    
    
    @Override
    public void show() {
    
    
        System.out.println("D产品被生产了");
    }
}

Produzieren Sie Produktklassenobjekte, indem Sie der Factory den vollständigen Klassennamen des Produkts übergeben

  Product D = Product_factory.createProductReflect("factory.Simple_factory.ProductD");
  D.show();

Ausgabe:

D产品被生产了

Nachdem Sie den Java-Reflexionsmechanismus zur Optimierung des einfachen Fabrikmodells verwendet haben, können Sie dies erkennen und 不论具体产品类更新多频繁,都不需要再修改工厂类so das Problem der hohen Betriebskosten und der hohen Systemkomplexität des gewöhnlichen einfachen Fabrikmodells lösen

3.1.3 Neuoptimierung mithilfe von Reflektion (Konfigurationsdateikonfiguration, vollständige Klassennamenzuordnung)

Nachdem die Factory-Klasse des einfachen Factory-Modus durch den Java-Reflexionsmechanismus optimiert wurde, besteht derzeit noch ein solches Problem. Tatsächlich ist es 子类的全局定名(包名+类名)是写死的für Entwickler jedoch schwierig, die globale Benennung aller Unterklassen im Voraus vorherzusagen (Paketname +). Klassenname), daher ist eine zweite Optimierung erforderlich~

Optimierungsideen:

Über die Konfigurationsdateimethode 统一定义类名对应全局定名(包名+类名),将配置文件存放到资源目录下läuft das Programm über ClassLoader类加载器动态获取到配置文件中定义的子类的全局定名~

Optimieren Sie Schritt 2 erneut: Konfigurieren Sie den Klassennamen entsprechend dem globalen Namen (Paketname + Klassenname),
um die Attributkonfigurationsdatei Product.properties zu erstellen

//产品抽象类Product相关子类的全局定名(包名+类名)定义
//key            value
ProductA = com.justin.java.lang.ProductA
ProductB = com.justin.java.lang.ProductB
ProductC = com.justin.java.lang.ProductC

Optimieren Sie Schritt 3 erneut: Ändern Sie die aufrufende Factory-Klasse

public class FactoryTest {
    
    
    @Test
    public void test() throws IOException {
    
    
        ClassLoader classLoader = this.getClass().getClassLoader();
        Properties prop = new Properties();
        prop.load(classLoader.getResourceAsStream("Product.properties"));

        String className = "";
        try {
    
    
            className = prop.getProperty("ProductA");
            Product productA = Factory.getInstance(className);
            productA.show();
        } catch (NullPointerException e) {
    
    
            System.out.println("没有A这款产品,无法生产~");
        }

        try {
    
    
            className = prop.getProperty("ProductB");
            Product productA = Factory.getInstance(className);
            productA.show();
        } catch (NullPointerException e) {
    
    
            System.out.println("没有B这款产品,无法生产~");
        }

        try {
    
    
            className = prop.getProperty("ProductC");
            Product productA = Factory.getInstance(className);
            productA.show();
        } catch (NullPointerException e) {
    
    
            System.out.println("没有C这款产品,无法生产~");
        }
    }
}

Ausgabe:

生产了产品A
生产了产品B
生产了产品C

Im Vergleich zu vor der Optimierung wird der vollständige Kategoriename, der der Produktkategorie entspricht, in die Konfigurationsdatei eingefügt. Bei der Herstellung von Produkten wird der vollständige Kategoriename, der der Produktkategorie entspricht, gemäß der folgenden Konfiguration aus der Konfigurationsdatei abgerufen und dann entsprechend der vollständige Kategoriename Konstruiert reflektierend das Produktobjekt:

		ClassLoader classLoader = this.getClass().getClassLoader();
        Properties prop = new Properties();
        prop.load(classLoader.getResourceAsStream("Product.properties"));

classLoader.getResourceAsStream("Product.properties") Es dient dazu, den Eingabestream der Ressourcendatei „Product.properties“ über den Klassenlader abzurufen. Die Methode getResourceAsStream() ist eine Methode der Klasse java.lang.ClassLoader, die dies kann根据给定的路径从类路径中查找并返回对应的资源文件的输入流。

prop.load()ist eine Methode der Klasse java.util.Properties, die 将输入流中的数据加载到属性对象中。in dieser Codezeile verwendet wird, wobei prop ein Eigenschaftsobjekt ist, indem die Methode prop.load() aufgerufen und eingefügt wird类加载器获取到的资源文件输入流作为参数,实现将资源文件的内容加载到属性对象中。

Alles in allem ergibt diese Codezeile Folgendes:使用类加载器加载名为 "Product.properties" 的资源文件,并将其读取为属性对象。这样可以方便地获取和操作资源文件中定义的属性值。

3.2 Dynamische Proxy-Implementierung im Proxy-Modus

Was ist der Proxy-Modus?
Der Proxy-Modus ist ein Entwurfsmodus.通过代理对象来访问目标对象,还可以在不修改目标对象的情况下,对代理对象进行拓展,增强目标对象的功能~

3.2.1 Statischer Proxy

statischer ProxyEs ist in 编译时就已经确定代理类和被代理类的关系der Proxy-Klasse und der Proxy-Klasse enthalten 实现同一个接口或继承同一个父类. Die Proxy-Klasse enthält vor oder nach dem Aufruf der Zielmethode einen Verweis auf das Proxy-Objekt (das Proxy-Objekt) 执行一些额外的逻辑. Der Code des statischen Proxys wurde zur Kompilierungszeit bestimmt, daher muss die Proxy-Klasse für jede Proxy-Klasse eine entsprechende Proxy-Klasse schreiben. Der Vorteil dieser Methode besteht darin, dass sie einfach und intuitiv, leicht zu verstehen und zu beherrschen ist. Wenn jedoch viele Proxy-Klassen vorhanden sind,会产生大量的重复代码。

Das heißt, eine Proxy-Klasse entspricht einer Proxy-Klasse, aber wenn es viele Proxy-Klassen gibt,会产生大量的重复代码。
Fügen Sie hier eine Bildbeschreibung ein

In Laien ausgedrückt ist der statische Proxy tatsächlich 被代理类和代理类共同实现一个接口die Methode zur Implementierung der Schnittstelle 代理类通过声明被代理类的实例化对象(代理对象)(dh die Beziehung zwischen der Proxy-Klasse und der Proxy-Klasse wurde zur Kompilierungszeit bestimmt) 通过调用和被代理类一样的方法(aus diesem Grund muss eine Schnittstellenmethode vorhanden sein). gemeinsam implementiert) und 在代理类方法中通过代理对象调用被代理类的方法(kann in der Methode der Proxy-Klasse die Einstellung der Erweiterung der Proxy-Klasse vornehmen), um den Effekt einer Proxy- oder Proxy-Verbesserung zu erzielen

3.2.2 Dynamischer Proxy

dynamischer Proxyist in 运行时生成代理类,不需要对每个被代理类都编写一个对应的代理类. Dies geschieht zur Laufzeit mithilfe des Reflexionsmechanismus von Java 动态地创建代理类和代理对象. 代理类实现一个统一的接口或继承一个父类und enthält ein InvocationHandler-Objekt als Aufrufprozessor. Beim Aufrufen der Zielmethode 代理类会将方法调用转发给 InvocationHandler 处理器,并可以在调用之前或之后添加额外的逻辑besteht der Vorteil des dynamischen Proxys darin, dass er Proxy-Objekte flexibler und dynamischer erstellen kann, wodurch das wiederholte Schreiben von Proxy-Klassen reduziert wird und sich für Szenarien eignet, in denen viele Proxy-Klassen vorhanden sind oder eine dynamische Verwaltung von Proxy-Objekten erforderlich ist.

3.2.2.1 Dynamischer JDK-Proxy (Reflection Construction Proxy-Objekt)

Der native dynamische JDK-Proxy verwendet hauptsächlich die JDK-API
java.lang.reflect.Proxyund java.lang.relfect.InnvocationHandlerdiese beiden Klassen, um ~ zu erreichen

通过java.lang.reflect.Proxy代理类的newProxyInstance方法, Übergabe von 3 Parametern, nämlich:

  1. Der Loader des Zielobjekts wird durch Object.getClass().getClassLoader abgerufen
  2. Der Implementierungsschnittstellentyp des Zielobjekts wird durch Object.getClass().getInterfaces() abgerufen
  3. Der InnvocationHandler-Ereignishandler wird erhalten, indem das Objekt mit new instanziiert und die Aufrufmethode neu geschrieben wird

Schritt:

  1. Erstellen Sie die Schnittstelle der Proxy-Klasse und lassen Sie die Proxy-Klasse die Schnittstellenmethode implementieren
  2. Erstellen Sie eine Proxy-Klasse und fügen Sie das Proxy-Klassenobjekt über den Konstruktor in die Proxy-Klasse ein
  3. Durch Festlegen von 3 Parametern (1. Der Loader des Zielobjekts, 2. Der Implementierungsschnittstellentyp des Zielobjekts, 3. InnvocationHandler-Ereignishandler (die Methode zur Erweiterung des Zielobjekts))
  4. Schreiben Sie eine Methode, um ein Proxy-Objekt zurückzugeben: Übergeben Sie drei Parameter über die newProxyInstance-Methode der Proxy-Proxy-Klasse und geben Sie das generierte Proxy-Objekt zurück.
  5. In der Testklasse wird das Proxy-Klassenobjekt durch die Parameterkonstruktion der Proxy-Klasse eingeführt und dann das Proxy-Objekt generiert, um die erweiterte Methode auszuführen

Beispiel:
ProduktklassenschnittstelleProduct_interface

/**
 * 被代理类接口
 */
public interface Product_interface {
    
    
    void sell();
}

ProduktkategorieProduct

/**
 * @Description TODO 被代理类
 **/
public class Product implements Product_interface{
    
    
    @Override
    public void sell() {
    
    
        System.out.println("生产了一台iphone 15 pro max");
    }
}

Proxy-KlasseProductProxy

/**
 * @Description TODO 动态代理类
 **/
public class ProductProxy {
    
    
    private  Object  target;//被代理的对象

    public ProductProxy (Object target){
    
    //通过构造方法引入被代理对象
        this.target = target;
    }

    /**
     * 利用JDK API获取到代理对象
     * @return
     */
    public Object getProxyInstance(){
    
    
        //目标对象的加载器
        ClassLoader classLoader = target.getClass().getClassLoader();//反射

        //目标对象的实现接口类型
        Class<?>[] interfaces = target.getClass().getInterfaces();//反射

        //InvocationHandler事件处理器实例对象
        InvocationHandler invocationHandler = new InvocationHandler() {
    
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                //前置增强
               System.out.println("提前接到消息的黄牛正在蹲抢中.............");
                // 执行目标对象方法
                Object value = method.invoke(target, args);
                //后置增强
                System.out.println("无货......................");
                return null;//若无返回值  就直接返回   若需要返回一个返回值  就如实返回
            }
        };
        //传入3个参数,创建代理类的实例对象,并返回
        return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
    }
}

TestklasseProductBuyTest

    public static void main(String[] args) {
    
    

        Product_interface product = new Product();//创建被代理类对象

        ProductProxy productProxy = new ProductProxy(product);//将被代理类的对象交给代理类

        Product_interface proxy = (Product_interface) productProxy.getProxyInstance();//由代理类生成代理对象

        proxy.sell();//通过代理对象执行被代理类的增强方法

    }

Ausgabe:

提前接到消息的黄牛正在蹲抢中.............
富士康生产了一台iphone 15 pro max
无货......................

Im nativen dynamischen JDK-Proxy wird beim Abrufen des Proxy-Beispielobjekts der Klassenlader des Zielobjekts abgerufen und mithilfe des Java-Reflexionsmechanismus ~ target.getClass().getClassLoader获取到目标对象的类加载器realisierttarget.getClass()方式获取目标对象的Class实例对象

3.2.2.2 cglib dynamischer Proxy (ohne Reflexion)

CGLIB (Code Generation Library) ist eine 基于ASM(一个Java字节码操作框架)的代码生成库, sie kann 运行时动态地生成目标类的子类also in sein 实现对目标类的代理.

Bei der Verwendung muss eine cglib-Abhängigkeit eingeführt werden

      <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

ProduktkategorieProduct

/**
 *  被代理类
 */
public class Product {
    
    

    public void sell() {
    
    
        System.out.println("富士康生产了一台iphone 15 pro max");
    }
}

Proxy-KlasseCglibProxy

/**
 * @Description: 代理类  用来获取代理对象
 */
public class CglibProxy implements MethodInterceptor {
    
    

    private  Object  target;//被代理的对象

    public CglibProxy (Object target){
    
    //通过构造方法引入被代理对象
        this.target = target;
    }

    /**
     * 用于构造代理对象
     * @return
     */
    public Object getProxyObject() {
    
    
        //创建Enhancer对象,类似于JDK代理中的Proxy类
        Enhancer enhancer = new Enhancer();
        //设置父类的字节码对象。指定父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        Object proxyObject =  enhancer.create();
        return proxyObject;
    }
    /*
     * 拦截器
     *       	1.目标对象的方法调用
     *       	2.行为增强
     *      参数 o: cglib 动态生成的代理类的实例
     *          method:实体类所调用的都被代理的方法的引用
     *          objects 参数列表
     *          methodProxy:生成的代理类对方法的代理引用
     * */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        //前置增强
        System.out.println("提前接到消息的黄牛正在蹲抢中.............");
        //要调用目标对象的方法
        Object obj = method.invoke(target, objects);
        //后置增强
        System.out.println("无货......................");
        return null;
    }
}

Ausgabe:

提前接到消息的黄牛正在蹲抢中.............
富士康生产了一台iphone 15 pro max
无货......................

Umsetzungsschritte:

  1. Führen Sie die cglib-Abhängigkeit ein
  2. Erstellen Sie eine Proxy-Klasse
  3. Erstellen Sie eine cglib-Proxy-Klasse, implementieren Sie die MethodInterceptor-Schnittstelle und schreiben Sie die Intercept-Methode neu
  4. Fügen Sie das Proxy-Klassenobjekt über die Konstruktionsmethode ein, um das Proxy-Objekt zuzuweisen
  5. Schreiben Sie eine Methode, um ein Proxy-Objekt zurückzugeben:
    1. Erstellen Sie ein Enhancer-Objekt,
    2. Legen Sie das Bytecode-Objekt der übergeordneten Klasse (die Proxy-Klasse) für das Enhancer-Objekt fest,
    3. Legen Sie eine Rückruffunktion für das Enhancer-Objekt fest,
    4. Erstellen Sie ein Proxy-Objekt und gibt das Proxy-Objekt zurück
  6. Rufen Sie die Methode des Zielobjekts in der Intercept-Methode auf (erweitert)
  7. In der Testklasse wird das Proxy-Klassenobjekt durch die Parameterkonstruktion der Proxy-Klasse eingeführt und dann das Proxy-Objekt generiert, um die erweiterte Methode auszuführen

Die Referenz stammt aus:
Java – Reflection Mechanism Principle, Multiple Class Acquisition Methods and Application Scenarios – Autor: Justin Wuri Sansheng

Supongo que te gusta

Origin blog.csdn.net/weixin_45618869/article/details/132623197
Recomendado
Clasificación