>  기사  >  Java  >  Java 동적 프록시에 대한 완전한 숙달

Java 동적 프록시에 대한 완전한 숙달

WBOY
WBOY앞으로
2022-07-26 13:55:021624검색

이 기사에서는 java에 대한 관련 지식을 제공합니다. 동적 프록시는 프로그램 실행 시 결정되는 프록시 클래스와 대상 클래스 간의 관계를 의미합니다. 고객이 프록시 클래스를 통해 대상 객체를 호출하는 방법은 다음과 같습니다. 대상 클래스의 프록시 객체는 프로그램이 실행될 때 필요에 따라 동적으로 생성됩니다. 다음은 사례를 통해 Java 동적 프록시의 원리와 구현을 자세히 설명하겠습니다.

Java 동적 프록시에 대한 완전한 숙달

추천 학습: "java 비디오 튜토리얼"

"에이전트"라는 단어는 모두가 익숙하다고 생각합니다. 간단히 말하면 제조업체를 대신하여 상품을 판매하는 것을 의미하며 에이전트가 제조업체를 대신하여 판매합니다. 상품, 고객은 상품을 구매할 대리인을 찾습니다. 즉, 1) 고객과 제조업체의 관계는 눈에 보이지 않으며 고객은 제조업체가 그 배후에 있는지 알지 못합니다. 2) 에이전트는 고객을 "포지셔닝"하고 필요한 고객 그룹에 보다 정확하게 판매할 수 있습니다.

프록시 모드

프록시 모드: 이 객체에 대한 액세스를 제어하기 위해 다른 객체에 프록시를 제공합니다. 즉, 클라이언트와 대상 객체 사이의 중개자로서 프록시 객체를 생성하는 것이 주요 목적입니다. 대상 개체를 강화합니다

프록시 패턴을 사용하면 일반적으로 다음 두 가지 이점이 있습니다.

1) 프록시 클래스의 구현을 숨길 수 있습니다

2) 코드를 수정하지 않고도 클라이언트와 프록시 클래스 간의 분리를 달성할 수 있습니다. 이 경우 몇 가지 추가 처리가 수행될 수 있습니다

정적 프록시

소위 동적 프록시는 명확한 프록시 클래스를 선언하여 소스 개체에 액세스하는 것입니다. n개의 제품, N개의 에이전트가 필요하며 이는 비즈니스 개발에 도움이 되지 않습니다.

예: 마우스와 키보드라는 두 개의 인터페이스가 있고 각 인터페이스에는 구현 클래스가 있습니다

구현 클래스의 코드는 다음과 같습니다.

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

이제 우리가 해야 할 일은 에이전트를 call sell() 이전에 판매 전 이해에 대한 문장을 출력하고, 호출 후에는 A/S에 대한 문장을 출력합니다 sell()前输出一句售前了解,调用后输出一句售后服务

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

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("售后服务");
    }
}

最终执行为:

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

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

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

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

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

动态代理

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

JDK动态代理

JDK从1.3版本就开始支持动态代理类的创建。主要核心类只有2个:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

그러면 프록시 클래스 MouseProxy2개만 작성하면 됩니다. > 및 KeyboardProxy

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

최종 실행은 다음과 같습니다.

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

출력:
사전 판매 이해
로지텍 마우스 판매
애프터 서비스사전 판매 이해
HHKB 키보드 판매
애프터 서비스

정적 프록시의 코드는 매우 간단하고 이해하기 쉽습니다. 명백한 단점:

많은 수의 중복 프록시 클래스가 있으며 여기에는 인터페이스가 두 개뿐입니다. n개의 인터페이스가 있는 경우 n개의 프록시 클래스를 정의해야 합니다.

인터페이스가 변경되면 프록시 클래스와 프록시 클래스를 모두 변경해야 합니다.

그러면 이때 동적 프록시를 사용하여 문제를 해결할 수 있습니다

동적 프록시

프로그램 실행 시 프록시 클래스가 프록시를 생성하는 방식을 동적 프록시라고 하는데, 이는 프록시 클래스가 정의되어 있지 않다는 의미입니다. Java 코드이지만

JDK 동적 프록시는 런타임에 동적으로 생성됩니다.

JDK는 버전 1.3부터 ​​동적 프록시 클래스 생성을 지원했습니다. 주요 핵심 클래스는 java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler 두 개뿐입니다.

위의 예에서도 다음과 같이 JDK 동적 프록시를 사용하세요. :

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

프록시 클래스 개체의 메서드를 호출하면 이 "호출"이 호출 메서드로 전달됩니다.

    프록시 클래스 개체는 프록시 매개변수로 전달됩니다.
  • 매개변수 메서드는 어떤 메서드를 식별하는지 식별합니다. 우리가 호출하는 프록시 클래스,
  • args는 이 메소드의 매개변수입니다.
  • 이런 방식으로 프록시 클래스의 메서드에 대한 모든 호출은 호출 호출이 되므로 호출 메서드에 통일된 처리 논리를 추가할 수 있습니다(메서드 매개변수를 기반으로 다양한 프록시 클래스에 대해 서로 다른 메서드를 만들 수도 있습니다). 처리). 따라서 중개 클래스의 호출 메소드에서 사전 판매 이해를 구현한 다음 프록시 클래스의 메소드를 호출하여 애프터 서비스를 제공할 수 있습니다.

코드 실행🎜
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();
    }
}
🎜인터페이스가 아무리 많아도 프록시 클래스는 하나만 필요하다는 것을 알 수 있습니다. 🎜🎜CGLIB 동적 프록시🎜🎜에이전트 클래스: 🎜rrreee🎜실행 코드: 🎜rrreee🎜JDK 프록시와 CGLIB 프록시의 차이점🎜🎜🎜JDK 동적 프록시는 인터페이스를 구현합니다. CGLIB 동적 상속 아이디어🎜🎜JDK 동적 프록시(대상이 객체에 인터페이스가 있음)실행 효율성이 CIGLIB🎜🎜보다 높습니다. 객체에 인터페이스 구현이 있으면 JDK 프록시를 선택하세요. 인터페이스 구현이 없으면 CGILB 프록시를 선택하세요🎜🎜🎜권장 학습: "🎜java 비디오 튜토리얼🎜" 🎜

위 내용은 Java 동적 프록시에 대한 완전한 숙달의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jb51.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제