[Java 기초] Reflection에 대한 심층적인 이해 및 Reflection 적용(팩토리 모드, 프록시 모드)

1. Java 반사 메커니즘이란 무엇입니까?

Java 리플렉션 메커니즘은 运行时动态地获取和操作类的信息、调用对象的方法和访问对象的属性的能力. Reflection을 통해 프로그램이 실행되는 동안 클래스의 구조, 동작, 상태를 분석하고 수정할 수 있습니다.

Java 리플렉션 메커니즘은 다음 기능을 제공합니다.

  1. 클래스 정보 가져오기: 클래스 이름, 수정자, 상위 클래스, 구현된 인터페이스 등을 가져올 수 있습니다.
  2. 객체 생성: 특정 클래스 이름을 알 수 없는 경우에도 리플렉션을 통해 객체를 인스턴스화할 수 있습니다.
  3. 호출 메서드: 리플렉션을 통해 클래스의 메서드를 가져오고 이러한 메서드를 호출할 수 있습니다.
  4. 필드 접근 및 수정: 클래스의 필드 값은 리플렉션을 통해 획득하고 설정할 수 있습니다.
  5. 동적 프록시: 리플렉션을 사용하여 프록시 개체를 동적으로 생성하여 AOP(관점 지향 프로그래밍) 및 기타 기능을 구현할 수 있습니다.
  6. 배열 조작: 배열 객체는 리플렉션을 통해 생성, 액세스 및 수정할 수 있습니다.
  7. 주석 처리: 클래스, 메소드, 필드에 대한 주석을 리플렉션을 통해 얻고 그에 따라 처리할 수 있습니다.

리플렉션 메커니즘을 통해 运行时动态地操作类和对象,解耦了编译时的依赖关系,提供了更大的灵活性和扩展性。사용할 수 있으나, 리플렉션에는 클래스 구조를 동적으로 생성하고 수정하는 작업이 포함되므로 성능에 영향을 미칠 수 있으며 추가 권한이 필요하다는 점에 유의해야 합니다.

1.2 자바 반영 예시

직교:
일반적인 상황에서 특정 클래스를 사용할 때 클래스와 그 용도를 알고 직접 전달할 수 있으며 new实例化创建对象이 객체를 사용하여 클래스에 대해 작업을 수행합니다. 이는 직교 ~
학생 클래스 에 속합니다.

		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

철자법은 이해하기 쉬우므로 자세한 설명은 생략하겠습니다. 이제 반사에 대해 이야기하겠습니다. 객체 생성, 객체 메소드 호출 등도 가능합니다. 철자법으로 할 수 있는 작업은 반사를 통해 수행할 수 있습니다.
반사:
리플렉션은 처음에 주로 달성 不知道要初始化的是什么类无法使用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

요약은 다음과 같습니다.
위의 예에 반영된 호출 프로세스는 보시다시피 获取一个类的反射对象주요 프로세스는 다음과 같습니다.

  1. 클래스의 Class 인스턴스 객체를 가져옵니다.
  2. Class 인스턴스 객체에 따라 Constructor 객체를 가져옵니다.
  3. 그런 다음 생성자 개체의 newInstance 메서드에 따라 클래스의 반사 개체를 가져옵니다.

获取到类的反射对象后,就可以对类进行操作了~ 예를 들어 위 예제에서 클래스의 메소드를 호출하는 과정은 다음과 같습니다.

  1. Class 인스턴스 객체에 따라 클래스의 Method 객체를 얻습니다.

  2. 그런 다음 Method 객체의 호출 메소드에 따라 특정 클래스의 메소드를 호출합니다.

위 예제의 역호출 과정에서는 Class.forName("类的全局定名")이런 방식으로 클래스의 Class 인스턴스 객체를 획득하는데, 이 외에도 일반적으로 사용되는 두 가지 방법이 더 있습니다.

2. Java 리플렉션 메커니즘에서 클래스를 얻는 세 가지 방법과 차이점은 무엇입니까?

클래스의 java.lang.Class 인스턴스 객체를 얻는 일반적인 방법은 세 가지가 있습니다.

  1. MyClass.class여기서 MyClass는 특정 클래스를 획득하는 것을 의미합니다 ~~
  2. 획득을 통해 Class.forName("类的全局定名")전역 이름은 패키지 이름 + 클래스 이름입니다.
  3. 여기서 MyClass는 획득 함으로써 new MyClass().getClass()특정 클래스를 의미합니다~
		Class<?> clz = Class.forName("Reflect.Student");		  //全类名获取
        Class<Student> clz = Student.class;                      //类.class获取
        Class<? extends Student> clz = new Student().getClass();//newClass().getClass()获取

차이점은 다음과 같습니다.

  • MyClass.class를 통해 얻은 JVM은 ClassLoader 클래스 로더를 사용하여 클래스를 메모리에 로드하지만클래스 초기화 작업을 수행하지 않고 java.lang.Class 객체를 반환합니다.
  • Class.forName("클래스의 전역 이름 지정")에서 얻은 것과 유사하게 클래스는 JVM에 의해 메모리에 로드됩니다.클래스의 정적 초기화를 수행하고 java.lang.Class 객체를 반환합니다.
  • newMyClass().getClass()에 의해 획득된 이 메소드는 다음을 사용합니다.new는 인스턴스화되므로 정적 초기화와 비정적 초기화가 모두 작동합니다., getClass 메소드는 최상위 Object 클래스의 메소드에 속하며, 하위 클래스가 호출하는 모든 하위 클래스 객체를 호출하고 해당 하위 클래스의 java.lang.Class 객체를 반환할 수 있습니다.

구체적인 표현에 대해서는 다음 링크를 참조하십시오: 내 세 지역의 Justin------>Java 반사 메커니즘 원리, 여러 클래스 획득 방법 및 응용 시나리오

요약하다:

  • MyClass.class不会做任何类的初始化工作
  • Class.forName이 수업을 수행합니다.静态初始化工作
  • new MyClass().getClass 静态初始化非静态初始化작업이 완료됩니다.
  • 이 세 가지 방법 중 하나를 사용하면 결국 JVM에 의해 메모리에 로드됩니다 内存地址相同(jvm 클래스 로딩의 상위 위임 메커니즘, 클래스는 한 번만 로드됨).

3. Java 반사 메커니즘의 적용 시나리오는 무엇입니까?

3.1 정적 팩토리 모드 최적화(디커플링)

3.1.1 최적화 전(공장 클래스와 제품 클래스 결합)

간단한 팩토리 예:

1단계: 추상 제품 클래스 생성

public interface Product {
    
    
      void show();
}

2단계: 구체적인 제품 클래스 만들기:

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");
    }
}

3단계: 간단한 팩토리 클래스 만들기

/**
 * 静态工厂
 */
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;
    }
}

4단계: 간단한 팩터리 클래스 호출

    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();

    }

산출:

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

최적화 전 단점
인터페이스의 하위 클래스가 추가될 때마다 팩토리 클래스의 논리를 수정해야 합니다.

예를 들어 C 제품을 추가해야 한다면 공장을 수정하고 C 제품의 생산 공정을 추가해야 합니다.

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

여기에 이미지 설명을 삽입하세요
이는 개폐원칙에 위배됩니다. (신제품 추가시 기존의 기존 코드를 수정하지 말고, 원본 기반으로 확장해야 합니다.)

이때, Reflection을 통해 이러한 단점을 극복할 수 있습니다. (제품과 공장의 분리)

3.1.2 반영 최적화 후(공장 클래스와 제품 클래스 분리)

최적화됨

팩토리 클래스 최적화

    /**
     * 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;
    }

테스트 클래스:

        //全类名反射通过工厂生产产品
        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();

산출:

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

이런 식으로 제품 D를 추가하려면 공장을 수정하지 않고 제품 D만 추가하면 되며, 제품 클래스 개체를 생산하려면 제품의 전체 클래스 이름을 공장에 도입하고 제품 D를 추가할 때 제품을 추가하면 됩니다. D 제품이 필요합니다
.

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

제품의 전체 클래스 이름을 공장에 도입하여 제품 클래스 개체를 생산합니다.

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

산출:

D产品被生产了

不论具体产品类更新多频繁,都不需要再修改工厂类Java 반사 메커니즘을 사용하여 단순 팩토리 모델을 최적화한 후 일반 단순 팩토리 모델의 높은 운영 비용과 높은 시스템 복잡성 문제를 해결한 것을 볼 수 있습니다 ~

3.1.3 리플렉션을 사용하여 다시 최적화(구성 파일 구성 전체 클래스 이름 매핑)

단순 팩토리 모드의 팩토리 클래스가 Java 반사 메커니즘에 의해 최적화된 후에도 현시점에서는 여전히 그런 문제가 있지만 실제로 子类的全局定名(包名+类名)是写死的개발자가 모든 하위 클래스의 전역 이름을 미리 예측하기는 어렵습니다(패키지 이름 + 클래스명)이므로 2차 최적화가 필요합니다~

최적화 아이디어:

구성 파일 방법을 통해 统一定义类名对应全局定名(包名+类名),将配置文件存放到资源目录下프로그램은 ClassLoader类加载器动态获取到配置文件中定义的子类的全局定名~를 통해 실행됩니다.

재최적화 2단계: 전역 이름(패키지 이름 + 클래스 이름)에 해당하는 클래스 이름을 구성하여
속성 구성 파일 Product.properties 를 생성합니다.

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

3단계 다시 최적화: 호출 팩토리 클래스 수정

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这款产品,无法生产~");
        }
    }
}

산출:

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

최적화 전과 비교하면 제품 카테고리에 해당하는 전체 카테고리 이름이 구성 파일에 위치하며, 제품 생산 시 다음 구성에 따라 구성 파일에서 제품 카테고리에 해당하는 전체 카테고리 이름을 가져온 후 다음과 같이 구성합니다. 전체 카테고리 이름은 제품 객체를 반영적으로 구성합니다.

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

classLoader.getResourceAsStream("Product.properties") 클래스 로더를 통해 리소스 파일 "Product.properties"의 입력 스트림을 얻는 것입니다. getResourceAsStream() 메소드는 java.lang.ClassLoader 클래스의 메소드입니다.根据给定的路径从类路径中查找并返回对应的资源文件的输入流。

prop.load()이 코드 줄에서 사용되는 java.util.Properties 클래스의 메서드입니다 将输入流中的数据加载到属性对象中。. 여기서 prop은 prop.load() 메서드를 호출하고 다음을 입력하여 속성 객체입니다.类加载器获取到的资源文件输入流作为参数,实现将资源文件的内容加载到属性对象中。

이 모든 것을 종합하면 이 코드 줄이 수행하는 작업은 다음과 같습니다.使用类加载器加载名为 "Product.properties" 的资源文件,并将其读取为属性对象。这样可以方便地获取和操作资源文件中定义的属性值。

3.2 프록시 모드에서 동적 프록시 구현

프록시 모드란 무엇입니까?
프록시 모드는 디자인 모드이며,通过代理对象来访问目标对象,还可以在不修改目标对象的情况下,对代理对象进行拓展,增强目标对象的功能~

3.2.1 정적 프록시

정적 프록시그것은 编译时就已经确定代理类和被代理类的关系프록시 클래스와 프록시 클래스 에 있습니다 实现同一个接口或继承同一个父类. 프록시 클래스는 대상 메소드를 호출하기 전이나 후에 프록시 객체(프록시 객체)에 대한 참조를 보유합니다 执行一些额外的逻辑. 정적 프록시의 코드는 컴파일 타임에 결정되므로 프록시 클래스는 각 프록시 클래스에 해당하는 프록시 클래스를 작성해야 합니다. 이 방법의 장점은 간단하고 직관적이며 이해하기 쉽고 숙달하기 쉽다는 것입니다. 그러나 프록시된 클래스가 많은 경우에는会产生大量的重复代码。

즉, 프록시 클래스는 프록시 클래스에 해당하지만, 프록시 클래스가 많은 경우에는会产生大量的重复代码。
여기에 이미지 설명을 삽입하세요

실제로 일반인의 관점에서 보면 정적 프록시는 이고 被代理类和代理类共同实现一个接口, 인터페이스를 구현하는 방법은 代理类通过声明被代理类的实例化对象(代理对象)(즉, 프록시 클래스와 프록시 클래스 간의 관계는 컴파일 타임에 결정됩니다), 通过调用和被代理类一样的方法(이것이 인터페이스 메서드가 다음과 같아야 하는 이유입니다. 함께 구현됨) 및 在代理类方法中通过代理对象调用被代理类的方法(프록시 클래스의 방법에서 프록시 클래스 설정이 향상될 수 있음) 프록시 또는 프록시 향상의 효과를 달성하기 위해

3.2.2 동적 프록시

동적 프록시에 있습니다 运行时生成代理类,不需要对每个被代理类都编写一个对应的代理类. 이는 Java의 리플렉션 메커니즘을 사용하여 런타임에 수행됩니다 动态地创建代理类和代理对象. 代理类实现一个统一的接口或继承一个父类이며 호출 프로세서로 InvocationHandler 개체를 보유합니다. 대상 메소드를 호출할 때 代理类会将方法调用转发给 InvocationHandler 处理器,并可以在调用之前或之后添加额外的逻辑동적 프록시의 장점은 프록시 객체를 보다 유연하고 동적으로 생성할 수 있어 반복되는 프록시 클래스 작성을 줄일 수 있다는 점이며, 프록시 클래스가 많거나 프록시 객체의 동적 관리가 필요한 시나리오에 적합합니다.

3.2.2.1 JDK 동적 프록시(반사 구성 프록시 개체)

JDK 네이티브 동적 프록시는 주로 JDK API
java.lang.reflect.Proxyjava.lang.relfect.InnvocationHandler이 두 클래스를 사용하여 ~를 달성합니다.

通过java.lang.reflect.Proxy代理类的newProxyInstance方法, 다음과 같은 3개의 매개변수를 전달합니다.

  1. 대상 객체의 로더는 Object.getClass().getClassLoader에 의해 획득됩니다.
  2. 대상 객체의 구현 인터페이스 유형은 Object.getClass().getInterfaces()에 의해 획득됩니다.
  3. InnvocationHandler 이벤트 핸들러는 객체를 new로 인스턴스화하고 호출 메소드를 다시 작성하여 얻습니다.

단계:

  1. 프록시 클래스의 인터페이스를 생성하고 프록시 클래스가 인터페이스 메서드를 구현하도록 합니다.
  2. 프록시 클래스를 생성하고 생성자를 통해 프록시 클래스 객체를 프록시 클래스에 주입합니다.
  3. 3가지 매개변수 설정(1. 대상 객체의 로더, 2. 대상 객체의 구현 인터페이스 유형, 3. InnvocationHandler 이벤트 핸들러(대상 객체 강화 방법))
  4. 프록시 객체를 반환하는 메서드를 작성합니다. Proxy 프록시 클래스의 newProxyInstance 메서드를 통해 세 개의 매개변수를 전달하고 생성된 프록시 객체를 반환합니다.
  5. 테스트 클래스에서는 프록시 클래스 매개변수 생성을 통해 프록시 클래스 객체를 도입한 후, 향상된 메소드를 실행하기 위해 프록시 객체를 생성한다.

예:
제품 클래스 인터페이스Product_interface

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

제품 카테고리Product

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

프록시 클래스ProductProxy

/**
 * @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);
    }
}

테스트 클래스ProductBuyTest

    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();//通过代理对象执行被代理类的增强方法

    }

산출:

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

JDK 네이티브 동적 프록시에서는 프록시 예제 객체를 획득하는 과정에서 대상 객체의 클래스 로더를 획득하고 이는 Java 리플렉션 메커니즘을 사용하여 target.getClass().getClassLoader获取到目标对象的类加载器구현 됩니다~target.getClass()方式获取目标对象的Class实例对象

3.2.2.2 cglib 동적 프록시(리플렉션 없음)

CGLIB(Code Generation Library)는 하나이므로 基于ASM(一个Java字节码操作框架)的代码生成库있을 수 있습니다 .运行时动态地生成目标类的子类实现对目标类的代理

사용할 때 cglib 종속성을 도입해야 합니다.

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

제품 카테고리Product

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

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

프록시 클래스CglibProxy

/**
 * @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;
    }
}

산출:

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

구현 단계:

  1. cglib 종속성 소개
  2. 프록시 클래스 생성
  3. cglib 프록시 클래스를 생성하고 MethodInterceptor 인터페이스를 구현하여 인터셉트 메서드를 다시 작성합니다.
  4. 프록시 객체를 할당하기 위해 생성 메소드를 통해 프록시 클래스 객체를 주입합니다.
  5. 프록시 객체를 반환하는 메소드 작성:
    1. Enhancer 객체 생성,
    2. Enhancer 객체에 대한 상위 클래스(프록시 클래스)의 바이트코드 객체 설정,
    3. Enhancer 객체에 대한 콜백 함수 설정,
    4. 생성 프록시 객체를 생성하고 프록시 객체를 반환합니다.
  6. Intercept 메소드에서 대상 객체의 메소드 호출(향상)
  7. 테스트 클래스에서는 프록시 클래스 매개변수 생성을 통해 프록시 클래스 객체를 도입한 후, 향상된 메소드를 실행하기 위해 프록시 객체를 생성한다.

참조 출처:
Java - 반사 메커니즘 원리, 여러 클래스 획득 방법 및 응용 시나리오 - 저자: Justin Wuri Sansheng

추천

출처blog.csdn.net/weixin_45618869/article/details/132623197