>  기사  >  Java  >  동적 프록시의 두 가지 방법은 무엇입니까?

동적 프록시의 두 가지 방법은 무엇입니까?

青灯夜游
青灯夜游원래의
2022-01-06 17:32:0519156검색

두 가지 방법은 다음과 같습니다. 1. 리플렉션 메커니즘을 사용하여 프록시 인터페이스를 구현하는 익명 클래스를 생성하고 특정 메서드를 호출하기 전에 InvokeHandler를 호출하는 JDK 동적 프록시 2. asm 오픈 소스 패키지를 사용하는 CGLIB 동적 프록시 객체 클래스를 프록시하려면 클래스 파일이 로드되고 해당 바이트코드를 수정하여 처리되어 하위 클래스를 생성합니다.

동적 프록시의 두 가지 방법은 무엇입니까?

이 튜토리얼의 운영 환경: windows7 시스템, java8 버전, DELL G3 컴퓨터.

동적 프록시는 리플렉션의 매우 중요한 적용 시나리오입니다. 동적 프록시는 일부 Java 프레임워크에서 자주 사용됩니다. 예를 들어 Spring의 AOP와 Dubbo의 SPI 인터페이스는 Java 동적 프록시를 기반으로 구현됩니다.

동적 프록시에는 두 가지 방법이 있습니다.

  • JDK 동적 프록시: 리플렉션 메커니즘을 사용하여 프록시 인터페이스를 구현하는 익명 클래스를 생성하고 특정 메서드를 호출하기 전에 InvokeHandler를 호출합니다.

  • CGLIB 동적 프록시: ASM(오픈 소스 Java 바이트코드 편집 라이브러리, 운영 바이트코드) 오픈 소스 패키지를 사용하여 프록시 객체 클래스의 클래스 파일을 로드하고 해당 바이트코드를 수정하여 처리할 하위 클래스를 생성합니다.

차이점: JDK 에이전트는 인터페이스를 구현하는 클래스에 대한 에이전트만 생성할 수 있습니다. CGlib는 클래스에 대한 에이전트를 구현하고 지정된 클래스에 대한 하위 클래스를 생성하며 그 안에 있는 메서드를 재정의합니다. 프록시 최종 수정 클래스.

CGlib 사용을 강제합니다

<!-- proxy-target-class="false"默认使用JDK动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<aop-config proxy-target-class="true">
<!-- 切面详细配置 -->
</aop-config>

구체적인 코드 예:

/**
 * 目标接口类
 */
public interface UserManager {    
    public void addUser(String id, String password);    
    public void delUser(String id);    
}
/**
 * 接口实现类
 */
public class UserManagerImpl implements UserManager {    
    
    @Override
    public void addUser(String id, String password) {    
        System.out.println("调用了UserManagerImpl.addUser()方法!");
    }    
    
    @Override
    public void delUser(String id) {    
        System.out.println("调用了UserManagerImpl.delUser()方法!");
    }    
}
/**
 * JDK动态代理类
 */
public class JDKProxy implements InvocationHandler {    
    
    // 需要代理的目标对象
    private Object targetObject;    
    
    public Object newProxy(Object targetObject) {
        // 将目标对象传入进行代理    
        this.targetObject = targetObject;
        // 返回代理对象 
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }    
    
    // invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 进行逻辑处理的函数
        checkPopedom();
        Object ret = null;
        // 调用invoke方法
        ret = method.invoke(targetObject, args);
        return ret;
    }    
    
    private void checkPopedom() {
        // 模拟检查权限   
        System.out.println("检查权限:checkPopedom()!");    
    }    
}
/**
 * CGlib动态代理类
 */
 public class CGLibProxy implements MethodInterceptor {    
    
    // CGlib需要代理的目标对象
    private Object targetObject;
    
    public Object createProxyObject(Object obj) {
        this.targetObject = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }
    
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        // 过滤方法
        if ("addUser".equals(method.getName())) {
            // 检查权限
            checkPopedom();
        }
        obj = method.invoke(targetObject, args);
        return obj;
    }    
    
    private void checkPopedom() {
        System.out.println("检查权限:checkPopedom()!");
    }
}
/**
 * 测试类
 */
public class ProxyTest {
    
    public static void main(String[] args) {
        UserManager userManager = (UserManager)new CGLibProxy().createProxyObject(new UserManagerImpl());
        System.out.println("CGLibProxy:");
        userManager.addUser("tom", "root");
        System.out.println("JDKProxy:");
        JDKProxy jdkProxy = new JDKProxy();
        UserManager userManagerJDK = (UserManager)jdkProxy.newProxy(new UserManagerImpl());
        userManagerJDK.addUser("tom", "root");
    }
}
// 运行结果
CGLibProxy:
检查权限checkPopedom()!
调用了UserManagerImpl.addUser()方法!
JDKProxy:
检查权限checkPopedom()!
掉用了UserManagerImpl.addUser()方法!

요약:

1 JDK 에이전트는 리플렉션 메커니즘을 사용하여 AOP 동적 프록시를 구현하고 CGLIB 에이전트는 바이트코드 처리 프레임워크 asm을 사용하여 수정합니다. 바이트 코드 생성 하위 클래스. 따라서 jdk 동적 프록시 방법은 프록시 객체 생성 효율성이 높고 실행 효율성이 낮은 반면, cglib는 생성 효율성이 낮고 실행 효율성이 높습니다.

2 JDK 동적 프록시 메커니즘은 특히 인터페이스 클래스의 동적 구현입니다. 동적으로 생성됩니다. 구현 클래스는 원래 구현 클래스 메서드를 호출하도록 핸들러에 맡깁니다. 특히, 프록시 클래스와 프록시 클래스는 상속 관계이므로 프록시 클래스에 할당할 수 있습니다. 프록시 클래스에 인터페이스가 있으면 프록시 클래스를 인터페이스에 할당할 수도 있습니다.

(추천 튜토리얼: Java 입문 튜토리얼)

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

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