>  기사  >  Java  >  자바 프록시 란 무엇입니까?

자바 프록시 란 무엇입니까?

angryTom
angryTom원래의
2019-11-13 11:37:374625검색

자바 프록시 란 무엇입니까?

Java 프록시란 무엇인가요?

프록시란 무엇인가요? , 실제로 이해하기 쉽습니다. 즉, 대상에 직접 액세스하지 않고 다음과 같이 중간 계층을 통해 액세스합니다.

자바 프록시 란 무엇입니까?

# 🎜🎜#Java 정적 프록시

예를 들어 바나나, 사과 등과 같은 과일을 Java 코드로 작성하면 다음과 같을 것입니다.

(추천 튜토리얼: #🎜 🎜#java tutorial)

//Fruit.java/**
 * 水果的接口
 */public interface Fruit {    /**
     * 获取水果的名字
     */
    public String getName();
}//Apple.javapublic class Apple implements Fruit {    @Override
    public String getName() {        return "苹果";
    }
}//Banana.javapublic class Banana implements Fruit {    @Override
    public String getName() {        return "香蕉";
    }
}
과일을 먹으면 껍질을 벗겨야 하는데 매번 할 수는 없습니다. 각 과일에 대한 하위 클래스를 작성하고 클래스에서 껍질 벗기기를 처리합니다. 그러므로 사과를 먹기 전에 약재를 만들어서 껍질을 벗길 수 있습니다. 다음과 같이 원본 과일을 레이어로 포장합니다.

//PeelFruitProxy.java/**
 * 代理,让每个水果去皮
 */public class PeelFruitProxy implements Fruit {    private Fruit mFruit;    public PeelFruit(Fruit fruit) {        this.mFruit = fruit;
    }    @Override
    public String getName() {
        System.out.println("proxt:" + proxy.getClass().getName());        return "去皮的" + mFruit.getName();
    }
}

테스트 클래스를 추가했는데, 테스트 클래스는 다음과 같습니다.

//Main.javapublic class Main {    public static void main(String[] args) {
        Apple apple=new Apple();//原始的苹果
        Banana banana=new Banana();//原始的香蕉

        PeelFruitProxy peelApple=new PeelFruitProxy(apple);//代理,添加去皮功能
        PeelFruitProxy peelBanana=new PeelFruitProxy(banana);//代理,添加去皮功能
        System.out.println(peelApple.getName());
        System.out.println(peelBanana.getName());
    }
}

위는 Java의 정적 프록시는 간단히 말하면 원래 대상 객체를 하나의 레이어로 래핑하고 새로운 것을 추가한 다음 대상 자체를 호출하는 것을 의미합니다. 그런데 그냥 이런 정적 프록시라면 인터페이스에 프록시가 필요한데, 구현하기가 많이 번거롭나요?

Java의 동적 프록시

Java에는 Proxy라는 클래스가 있는데 직접 리플렉션, 프록시 가로채기를 사용할 수 있습니다. 먼저 이 클래스를 간단히 소개하겠습니다. 실제로 가장 일반적으로 사용되는 정적 메서드는 Proxt.newProxyInstance()입니다. 이는 다음과 같습니다.

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

먼저 InvocationHandler를 구현하고 호출 메서드를 구현해야 합니다. 대상 개체를 호출하면 호출 메서드가 먼저 호출되고 구현자는 이 메서드에서 피호출자 메서드를 적극적으로 호출해야 합니다.

//FruitInvocationHandler.java/**
 * 调用方法拦截器
 */public class FruitInvocationHandler implements InvocationHandler {    private Fruit mFruit;    public FruitInvocationHandler(Fruit fruit) {        this.mFruit = fruit;
    }    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String result = (String) method.invoke(mFruit, args);//需要在这个方法里面,主动调用被代理的对象。
        return "去皮的" + result;
    }
}

실행:

//Main.Javapublic class Main {    public static void main(String[] args) {
        Apple apple = new Apple();
        Fruit proxyApple = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new FruitInvocationHandler(apple));
        System.out.println(proxyApple.getClass().getName());
        System.out.println(proxyApple.getName());

        Banana banana = new Banana();
        Fruit proxyBanana = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new FruitInvocationHandler(banana));
        System.out.println(proxyApple.getClass().getName());
        System.out.println(proxyBanana.getName());
    }
}

자바 프록시 란 무엇입니까?이 방법은 위에서 언급한 대로 PeelFruitProxy를 생성하는 것입니다(물론 우리가 본 것은 그의 이름은 com.sun.proxy.$Proxy0)이며 매번 작성할 필요가 없도록 동적으로 생성됩니다. 이는 런타임에 모든 클래스를 프록시할 수 있기 때문에 동적 프록시라고 불리는 이유이기도 합니다. 많은 프로그램에서 AOP가 이런 방식으로 구현되지만 몇 가지 특징을 발견했습니다. newProxyInstance()의 두 번째 매개변수는 인터페이스 목록입니다.

동적으로 생성된 프록시 클래스도 인터페이스를 구현해야 하기 때문에 쉽게 하향 변환되어 메소드를 사용할 수 있습니다. 그렇지 않으면 생성된 클래스의 클래스 이름이 com.sun.proxy입니다. $Proxy0 이 방법으로 메모리에 있으면 생성된 메서드를 호출할 수 없습니다. ** 따라서 이 동적 프록시 메서드에는 치명적인 단점이 있습니다. 즉, 프록시된 클래스가 인터페이스를 구현해야 한다는 것입니다. **

CGLib 프록시

cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime.
또 다른 유명한 Java 프록시 구현은 ASM 기반 코드인 CGLib(Code Generation Library)입니다. 생성 프레임워크 클래스를 동적으로 생성한 다음 메서드 가로채기를 구현하는 데 사용할 수 있습니다. 이렇게 하면 인터페이스를 구현하기 위해 대상 클래스가 필요한 JDK의 동적 프록시 문제를 피할 수 있습니다. 즉, CGLib를 사용하여 위에서 언급한 PeelFruitProxy를 생성할 수 있습니다.

사용 방법을 간단히 소개하겠습니다. 우선 이 CGLib은 타사 라이브러리이므로 이에 의존해야 합니다.

compile 'cglib:cglib :3.2.8'#🎜 🎜#

최신 버전은 여기(새 버전)에서 볼 수 있습니다. [https://github.com/cglib/cglib/releases] 그럼 한번 시도해 보세요. 위의 프록시를 구현합니다.# 🎜🎜#

//FruitMethodInterceptor.java/**
 * CGLib代理的方法拦截器
 */public class FruitMethodInterceptor implements MethodInterceptor{    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String result = (String) proxy.invokeSuper(obj, args);//主要,这里调用的是父类,也就是说, 生成的类和原始类是继承关系
        return "去皮的"+result;
    }
}//Main.javapublic class Main {    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Apple.class);
        enhancer.setCallback(new FruitMethodInterceptor());
        Apple apple = (Apple) enhancer.create();
        System.out.println(apple.getClass().getName());
        System.out.println(apple.getName());
    }
}

실행 효과는 다음과 같습니다.

동일한 기능이 구현된 것을 볼 수 있지만, Apple은 더 이상 원래 Apple 클래스가 아니며 com.zjiecode.learn.java.proxy.Apple$$EnhancerByCGLIB$$44ade224가 되었습니다. 예, 실제로는 원래 Apple이 아닌 이 클래스를 사용하고 있습니다. Apple 클래스에 대한 프록시를 구현했습니다. 이런 방식으로 상속이 사용되므로 프록시된 클래스가 인터페이스를 구현할 필요가 없습니다. 물론 인터페이스를 통해 에이전트를 구현할 수도 있습니다.

자바 프록시 란 무엇입니까?

Summary

첫 번째 유형의 프록시는 여기서 언급되지 않으며 단일 인터페이스 프록시에만 적합하며 컴파일 타임에 결정됩니다. . 두 번째와 세 번째 유형의 프록시는 모두 동적 프록시이지만 차이점이 있습니다.

1) JDK의 동적 프록시는 인터페이스 프록시만 구현할 수 있으며, 패키지된 프록시 객체(클래스의 인스턴스) 즉, 프록시 프로세스 중에 프록시 객체와 대상 객체라는 두 개의 객체가 프록시 객체에 패키지됩니다.

2) CGLib의 프록시는 대상 개체를 상속하고 새 클래스를 생성한 후 프록시를 구현합니다. 이렇게 하면 메모리에 프록시 개체가 있고 대상 개체가 없습니다. 상속 방식

런타임에 프록시 클래스를 생성하는데, 이는 컴파일 타임에 클래스를 생성하는 javapoet와 다릅니다.

위 내용은 자바 프록시 란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.