Heim  >  Artikel  >  Java  >  Welche zwei Möglichkeiten gibt es für einen dynamischen Proxy?

Welche zwei Möglichkeiten gibt es für einen dynamischen Proxy?

青灯夜游
青灯夜游Original
2022-01-06 17:32:0519204Durchsuche

Die beiden Methoden sind: 1. Dynamischer JDK-Proxy, der den Reflexionsmechanismus verwendet, um eine anonyme Klasse zu generieren, die die Proxy-Schnittstelle implementiert, und InvokeHandler aufruft, bevor die spezifische Methode aufgerufen wird. 2. Dynamischer CGLIB-Proxy, der das ASM-Open-Source-Paket verwendet. zum Proxy-Objektklassen Die Klassendatei wird geladen und verarbeitet, indem ihr Bytecode geändert wird, um eine Unterklasse zu generieren.

Welche zwei Möglichkeiten gibt es für einen dynamischen Proxy?

Die Betriebsumgebung dieses Tutorials: Windows7-System, Java8-Version, DELL G3-Computer.

Dynamischer Proxy ist ein sehr wichtiges Anwendungsszenario der Reflexion. In einigen Java-Frameworks werden häufig dynamische Proxys verwendet. Beispielsweise werden die AOP-Schnittstelle von Spring und die SPI-Schnittstelle von Dubbo basierend auf dem dynamischen Java-Proxy implementiert.

Es gibt zwei Methoden für dynamische Proxys:

  • Dynamischer JDK-Proxy: Verwenden Sie den Reflexionsmechanismus, um eine anonyme Klasse zu generieren, die die Proxy-Schnittstelle implementiert, und rufen Sie InvokeHandler auf, bevor Sie die spezifische Methode aufrufen.

  • Dynamischer CGLIB-Proxy: Verwenden Sie das Open-Source-Paket ASM (Open-Source-Java-Bytecode-Bearbeitungsbibliothek, Betriebsbytecode), um die Klassendatei der Proxy-Objektklasse zu laden und deren Bytecode zu ändern, um eine Unterklasse für die Verarbeitung zu generieren.

Unterschied: Der JDK-Agent kann nur Agenten für Klassen generieren, die Schnittstellen implementieren. CGlib generiert eine Unterklasse für die angegebene Klasse und überschreibt die darin enthaltenen Methoden Proxy endgültig geänderte Klassen.

Die Verwendung von CGlib erzwingen

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

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

Spezifisches Codebeispiel:

/**
 * 目标接口类
 */
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()方法!

Zusammenfassung:

1. Der JDK-Agent verwendet den Reflexionsmechanismus, um den dynamischen Proxy von aop zu implementieren Rahmen asm zu Ändern Sie die Bytes-Codegenerierungsunterklasse. Daher ist die dynamische Proxy-Methode von JDK effizienter bei der Erstellung von Proxy-Objekten und weist eine geringere Ausführungseffizienz auf.

2 Der dynamische Proxy-Mechanismus von JDK ist ein Delegierungsmechanismus Schnittstellenklassen werden dynamisch generiert. Die Implementierungsklasse beauftragt den Handler, die ursprüngliche Implementierungsklassenmethode aufzurufen. CGLIB verwendet insbesondere Vererbungsbeziehungen, sodass die Proxy-Klasse der Proxy-Klasse zugewiesen werden kann. Wenn die Proxy-Klasse über eine Schnittstelle verfügt, kann die Proxy-Klasse auch der Schnittstelle zugewiesen werden.

(Empfohlenes Tutorial: Java-Einführungs-Tutorial)

Das obige ist der detaillierte Inhalt vonWelche zwei Möglichkeiten gibt es für einen dynamischen Proxy?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn