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

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

青灯夜游
青灯夜游원래의
2019-11-18 17:17:153910검색

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

java프록시란 무엇인가요?

Proxy는 대상 개체에 액세스하는 또 다른 방법, 즉 프록시 개체를 통해 대상 개체에 액세스하는 방법을 제공하는 디자인 패턴입니다. 대상 개체를 수정하지 않고도 대상 개체의 기능을 확장할 수 있습니다.

에이전트의 역할: 코드 중복을 줄입니다.

프록시 모드의 구현은 정적 구현과 동적 구현의 두 가지 범주로 나뉩니다. 동적 구현은 구현 방법에 따라 구분됩니다: jdk 동적 구현, cglib 동적 구현

Java의 세 가지 프록시 모드

달성하고 싶습니다. 위의 요구 사항을 충족하는 세 가지 방법이 있습니다. 이 부분에서는 세 가지 모드에 대한 코드를 작성하는 방법만 살펴보고 구현 원칙을 먼저 다루지 않습니다.

1. 정적 프록시

public interface ISinger {
    void sing();
}

/**
 *  目标对象实现了某一接口
 */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}

/**
 *  代理对象和目标对象实现相同的接口
 */
public class SingerProxy implements ISinger{
    // 接收目标对象,以便调用sing方法
    private ISinger target;
    public UserDaoProxy(ISinger target){
        this.target=target;
    }
    // 对目标对象的sing方法进行功能扩展
    public void sing() {
        System.out.println("向观众问好");
        target.sing();
        System.out.println("谢谢大家");
    }
}

Test

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        //目标对象
        ISinger target = new Singer();
        //代理对象
        ISinger proxy = new SingerProxy(target);
        //执行的是代理的方法
        proxy.sing();
    }
}

장점: 대상 객체의 기능을 수정하지 않고 대상 기능을 확장합니다.

단점: 이 구현 방법은 매우 직관적이고 간단하지만 단점은 프록시 객체를 반드시 사용해야 한다는 것입니다. 인터페이스 계층이 변경되면 프록시 객체의 코드도 유지되어야 합니다. 프록시 객체를 런타임에 동적으로 작성할 수 있다면 프록시 클래스 코드의 수를 크게 줄일 수 있을 뿐만 아니라 지속적인 유지 관리 문제도 줄일 수 있지만 런타임 효율성에는 확실히 영향을 미칩니다. 이 방법은 다음 동적 프록시입니다.

2. JDK 프록시

정적 프록시의 전제는 여전히 Singer 객체를 확장합니다

public interface ISinger {
    void sing();
}

/**
 *  目标对象实现了某一接口
 */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}

이번에는 Java의 하위 계층이 구현 세부 사항을 캡슐화하므로 직접 테스트합니다. 나중에 자세히 설명) 코드도 기본적으로 매우 간단합니다.

Proxy 클래스의 정적 메소드인 newProxyInstance를 호출하면 됩니다. 이 메소드는 프록시 클래스 객체를 반환합니다

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

수신된 세 가지 매개변수는 다음과 같습니다.

 ●ClassLoader 로더: 클래스 로더를 사용할 현재 대상 객체, 쓰기 메소드를 지정합니다. 고정됨

 ● 클래스>[] 인터페이스: 대상 객체가 구현하는 인터페이스 유형, 작성 방법이 고정됨

● InvocationHandler h: 이벤트 처리 인터페이스, 구현 클래스가 전달되어야 함, 일반적으로 익명 내부 클래스를 직접 사용

테스트 코드

public class Test{
    public static void main(String[] args) {
  Singer target = new Singer();
        ISinger proxy  = (ISinger) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("向观众问好");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("谢谢大家");
                        return returnValue;
                    }
                });
        proxy.sing();
    }
}

장점 : 대상 객체의 로직을 변경하지 않고 동적으로 확장을 구현함

단점 : 정적 프록시와 JDK 프록시에는 공통적인 단점, 즉 대상 객체가 있다는 것을 알 수 있습니다. 하나 이상의 인터페이스를 구현해야 합니다. 그렇지 않으면 동적 프록시를 구현할 수 없습니다.

3. Cglib 에이전트

전제조건:

● Spring의 핵심 패키지에는 이미 Cglib 기능이 포함되어 있으므로 spring-core-3.2.5.jar을 직접 도입할 수도 있습니다. 대상 클래스는 final일 수 없습니다

●대상 개체의 메서드가 final/static이면 가로채지 않습니다. 즉, 대상 개체의 추가 비즈니스 메서드가 실행되지 않습니다

/**
 * 目标对象,没有实现任何接口
 */
public class Singer{

    public void sing() {
        System.out.println("唱一首歌");
    }
}
/**
 * Cglib子类代理工厂
 */
public class ProxyFactory implements MethodInterceptor{
    // 维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("向观众问好");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("谢谢大家");
        return returnValue;
    }
}

여기 코드도 매우 고정, 노란색 부분만 직접 작성해야 합니다.

test

/**
 * 测试类
 */
public class Test{
    public static void main(String[] args){
        //目标对象
        Singer target = new Singer();
        //代理对象
        Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        proxy.sing();
    }
}

장점: 대상 개체의 논리를 변경하지 않고 확장을 동적으로 구현합니다.

단점: 대상에서 인터페이스를 구현해야 합니다. 그렇지 않으면 동적 프록시를 구현할 수 없습니다.

요약: 세 가지 프록시 모드에는 각각 고유한 장점, 단점 및 해당 응답이 있습니다. 적용 범위는 주로 대상 개체가 인터페이스를 구현하는지 여부에 따라 다릅니다. Spring 프레임워크에서 선택한 프록시 모드를 예로 들어보세요

Spring의 AOP 프로그래밍에서:
컨테이너에 추가된 대상 개체에 구현 인터페이스가 있으면 JDK 프록시를 사용하세요.

대상 개체가 인터페이스를 구현하지 않으면 Cglib를 사용하세요. 프록시

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

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