JDK 동적 프록시의 원리 분석 및 코드 구현

프록시는 다음과 같습니다. 구매자(클라이언트) - 판매(프록시 개체) - 공장(대상)

        구매자는 공장에 직접 가서 살 필요가 없지만 판매를 통해 직접 구매할 수 있습니다.공장에서 컵을 생산한다고 가정하면 공장에서 컵을 제공하기만 하면 됩니다. 컵의 생산 과정 광고. 그것의 판매를 증가하십시오.

      프록시 모드 에서 프록시 객체는 프록시 객체의 중개자 역할을 하며 클라이언트는 프록시 객체에 직접 액세스하는 대신 프록시 객체를 통해 프록시 객체에 액세스합니다. 주요 목적은 원래 개체를 변경하지 않고 추가 기능을 제공하거나 액세스를 제어하는 ​​것입니다. 향상된 코드 보안 및 유연성.

1. 동적 프록시란 무엇입니까?

      프록시 클래스와 프록시 클래스 간의 관계는 컴파일 시 정적 프록시 에서 결정되며 프록시 클래스는 수동으로 작성됩니다. 정적 프록시에서는 각 프록시 클래스에 대해 프록시 클래스를 작성해야 합니다. 프록시 클래스를 수동으로 작성해야 하므로 프록시 클래스가 많을 때 코드 중복이 발생합니다. 따라서 이 경우 동적 프록시를 사용해야 합니다.

        동적 프록시는 프록시 클래스를 수동으로 작성하지 않고 런타임에 프록시 클래스와 프록시 개체를 동적으로 생성합니다. 동적 프록시에서 프록시 클래스는 런타임에 리플렉션 메커니즘을 통해 동적으로 생성됩니다. 동적 프록시의 장점은 코드 중복을 줄일 수 있다는 점이며 단점은 구현이 정적 프록시보다 약간 더 복잡하다는 것입니다.

2. JDK 동적 프록시 구현

        다음은 브로커 프록시 객체를 호출하여 스타의 댄스, 랩 메소드를 호출하는 예제 코드입니다. 스타는 업무만 담당하고 브로커 방식에 돈을 모으는 기능이 추가된다.

인터페이스 정의: 먼저 댄스와 랩의 두 가지 인터페이스가 있는 Star 인터페이스를 정의했습니다.

public interface Star {

    /**
     * 跳舞
     */
    public void dance();

    /**
     * 说唱
     */
    public void rap();
}

Star 인터페이스 구현 클래스 만들기: 이 클래스에서 두 가지 메서드를 구현합니다.

public class OnePeople implements Star{

    @Override
    public void dance() {
        System.out.println("我跳舞了");
    }

    @Override
    public void rap() {
        System.out.println("我唱了rap");
    }
}

InvocationHandler 구현 클래스를 만듭니다 .

//当调用代理对象的方法时,实际上是调用了invoke()方法。在invoke()方法中,可以根据需要执行一些前置或后置操作,然后将方法调用转发给实际的对象。
public class MyInvocationHandler implements InvocationHandler {
    //被代理对象
    Object object;
    public MyInvocationHandler (Object o){
        object = o;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我已经收好钱了,我的boss可以开始工作了");
        //通过反射调用被代理对象的方法。
        Object invoke = method.invoke(object, args);
        System.out.println("我们已经工作完毕,拍拍屁股离开");
        return invoke;
    }
}

프록시 개체를 만듭니다.

public class Demo {
    public static void main(String[] args) {
        OnePeople onePeople = new OnePeople();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(onePeople);
        //newProxyInstance()接受三个参数:类加载器、要实现的接口列表和一个InvocationHandler对象
        // 返回的是实现指定接口的代理类的实例。这个实例可以被强制转换为接口类型,以便在代码中使用。
        Star star = (Star) Proxy.newProxyInstance(onePeople.getClass().getClassLoader(),
                onePeople.getClass().getInterfaces(), myInvocationHandler);
        //调用跳舞方法
        star.dance();
        //调用rap方法
        star.rap();
    }
}

작업 결과:

참고: JDK 동적 프록시는 특정 클래스가 아닌 인터페이스만 프록시할 수 있습니다. 특정 클래스를 프록시하려는 경우 다른 프록시 메커니즘(CGLIB 메커니즘) 사용을 고려할 수 있습니다.

3. 동적 프록시의 장점

  1. 유연성: 동적 프록시는 컴파일 타임에 프록시 객체 유형을 결정할 필요 없이 런타임에 프록시 객체를 생성할 수 있습니다. 이는 동적 프록시를 보다 유연하게 만들고 필요에 따라 다양한 유형의 프록시 객체를 동적으로 생성할 수 있습니다.

  2. 확장성: 동적 프록시는 InvocationHandler 인터페이스를 구현하여 프록시 개체의 동작을 사용자 지정할 수 있습니다. InvocationHandler에 커스텀 로직을 작성함으로써 프록시 객체의 메소드 호출 전후에 로깅, 성능 모니터링, 트랜잭션 관리 등과 같은 추가 작업을 수행할 수 있습니다. 이러한 확장성은 동적 프록시를 많은 시나리오에서 유용하게 만듭니다.

  3. 낮은 결합: 동적 프록시는 프록시 객체 생성과 프록시 논리 구현을 분리하여 낮은 결합을 달성할 수 있습니다. 프록시 객체 생성은 프록시 팩토리 또는 종속성 주입 컨테이너에서 수행할 수 있으며 프록시 논리 구현은 InvocationHandler에서 수행할 수 있습니다. 이 낮은 결합은 코드를 더 명확하고 유지 관리 및 확장하기 쉽게 만듭니다.

  4. 역학: 동적 프록시는 런타임에 프록시 개체의 동작을 동적으로 수정할 수 있습니다. 이는 프록시 개체의 메서드를 필요에 따라 동적으로 추가, 수정 또는 삭제할 수 있으므로 보다 유연한 프록시 논리를 실현할 수 있음을 의미합니다.

추천

출처blog.csdn.net/qq_64680177/article/details/132142832