>Java >java지도 시간 >디자인 패턴 동적 프록시

디자인 패턴 동적 프록시

巴扎黑
巴扎黑원래의
2017-06-26 09:35:481195검색

1. 동적 프록시 개념

동적 프록시는 JDK 동적 프록시와 cglib 동적 프록시의 두 가지 방법으로 나뉩니다.

jdk 동적 프록시는 Java 내부의 반사 메커니즘으로 구현되는 반면 cglib 동적 프록시의 하위 레이어는 asm의 도움으로 구현됩니다.

일반적으로 클래스를 생성하는 과정에서는 리플렉션 메커니즘이 더 효율적이고, 클래스 생성 후 관련 실행 과정에서는 asm이 더 효율적입니다. (asm 클래스 생성 프로세스의 비효율성은 생성된 클래스를 캐싱하여 해결할 수 있습니다.) asm 질문).

주의해야 할 또 다른 사항이 있습니다. jdk 동적 프록시를 적용하기 위한 전제 조건은 대상 클래스가 통합 인터페이스를 기반으로 해야 한다는 것입니다. 위의 전제조건이 없으면 jdk 동적 프록시를 적용할 수 없습니다.

이를 통해 jdk 동적 프록시에는 특정 제한 사항이 있음을 알 수 있습니다. cglib과 같은 타사 라이브러리로 구현된 동적 프록시는 더 널리 사용되고 효율성 면에서 더 많은 이점을 갖습니다.

2. JDK 동적 프록시

다음 코드는 프록시 모드를 사용하여 대문자와 소문자를 변환하는 기능을 구현합니다.

인터페이스 및 구현 클래스 정의:

ISomeService 인터페이스:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;/**
 * 接口类
 * 
 * @author Root */public interface ISomeService {
    
    String doFirst();    void doSecond();
}

SomeServiceImpl 구현 클래스:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;/**
 * 实现类
 * 
 * @author Root */public class SomeServiceImpl implements ISomeService {

    @Overridepublic String doFirst() {
        System.out.println("执行doFirst()...");
        String result = "abcde";return result;
    }

    @Overridepublic void doSecond() {
        System.out.println("执行doSecond()...");
    }

}

JDK 동적 프록시 클래스:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {final ISomeService target = new SomeServiceImpl();        // 使用JDK的Proxy动态代理,要求目标类和代理类必须实现相同的接口,因为其底层的执行原理与静态代理的相同ISomeService service = (ISomeService) Proxy.newProxyInstance(// 目标类的类加载器                target.getClass().getClassLoader(),// 目标类所实现的所有接口                target.getClass().getInterfaces(), new InvocationHandler() {// proxy:代理对象// method:目标方法// args:目标方法的参数列表                    @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 调用目标方法Object result = method.invoke(target, args);if (result != null) {
                            result = ((String) result).toUpperCase();
                        }return result;
                    }
                });
        String result = service.doFirst();
        System.out.println(result);

        service.doSecond();
    }
}

3. cglib 동적 프록시

Cglib는 우수한 동적 프록시 프록시 프레임워크의 최하위 계층은 ASM을 사용하여 메모리에 프록시 클래스의 하위 클래스를 동적으로 생성합니다. CGLIB를 사용하면 프록시 클래스가 인터페이스를 구현하지 않더라도 동적 프록시 기능을 구현할 수 있습니다. CGLIB는 간단하고 사용하기 쉬우며 JDK의 프록시 동적 프록시보다 훨씬 빠르게 실행됩니다.

CGLIB의 핵심 클래스:
net.sf.cglib.proxy.Enhancer - 주요 개선 클래스
net.sf.cglib 프록시. MethodInterceptor – 기본 메소드 차단 클래스입니다. 이는 콜백 인터페이스의 하위 인터페이스이며 사용자가 구현해야 합니다. net.sf.cglib.proxy.MethodProxy – JDK java.lang.reflect.Method의 프록시 클래스입니다.
Object o = methodProxy.invokeSuper(proxy, args);//첫 번째 매개변수가 프록시 객체이더라도 무한 루프 문제는 없습니다.

net.sf.cglib.proxy.MethodInterceptor 인터페이스는 가장 일반적인 콜백 유형으로 프록시 기반 AOP에서 인터셉트 메서드 호출을 구현하는 데 자주 사용됩니다. 이 인터페이스는 하나의 메소드만 정의합니다
공용 객체 인터셉트(Object 객체, java.lang.reflect.Method 메소드, Object[] args, MethodProxy 프록시)는 Throwable을 던집니다.

첫 번째 매개변수는 프록시 객체이고, 두 번째와 두 번째 매개변수는 세 가지 매개변수는 차단 방법과 방법의 매개변수입니다. 원래 메소드는 java.lang.reflect.Method 객체를 사용하거나 net.sf.cglib.proxy.MethodProxy 객체를 사용하여 일반 리플렉션을 통해 호출될 수 있습니다. net.sf.cglib.proxy.MethodProxy는 일반적으로 더 빠르기 때문에 선호됩니다.

다음 프로그램은 대소문자 변환 기능을 구현합니다.

구현 클래스 SomeService:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;/**
 * 实现类
 * 
 * @author Root */public class SomeService {public String doFirst() {
        System.out.println("执行doFirst()...");
        String result = "abcde";return result;
    }public void doSecond() {
        System.out.println("执行doSecond()...");
    }

}
Proxy 클래스 MyCglibFactory:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class MyCglibFactory implements MethodInterceptor {private SomeService target;    public MyCglibFactory() {super();
        target = new SomeService();
    }public SomeService myCglibCreator() {// 创建增强器对象Enhancer enhancer = new Enhancer();// 指定目标类,即父类enhancer.setSuperclass(SomeService.class);// 设置回调接口对象enhancer.setCallback(this);return (SomeService) enhancer.create();
    }

    @Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 调用目标方法Object result = method.invoke(target, args);if (result != null) {
            result = ((String) result).toUpperCase();
        }return result;
    }

}
Test:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;public class Main {public static void main(String[] args) {

        SomeService service = new MyCglibFactory().myCglibCreator();
        
        String result = service.doFirst();
        System.out.println("result = " + result);

        service.doSecond();
    }
}
실행 결과:

执行doFirst()...
result = ABCDE
执行doSecond()...

위 내용은 디자인 패턴 동적 프록시의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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