Java代理是什么?為什么要用代理?以及代理的分類


Java 動態代理作用是什么?為什么要動態代理

轉載自:https://blog.csdn.net/u010325193/article/details/83307473

① 首先你要明白靜態代理的作用
我們有一個字體提供類,有多種實現(從磁盤,從網絡,從系統)

public interface FontProvider {
 
Font getFont(String name);
 
}
 
 
 
public abstract class ProviderFactory {
 
public static FontProvider getFontProvider() {
 
return new FontProviderFromDisk();
 
}
 
}
 
 
 
public class Main() {
 
public static void main(String[] args) {
 
FontProvider fontProvider = ProviderFactory.getFontProvider();
 
Font font = fontProvider.getFont("微軟雅黑");
 
......
 
}
 
}
現在我們希望給他加上一個緩存功能,我們可以用靜態代理來完成

 
public class CachedFontProvider implements FontProvider {
 
private FontProvider fontProvider;
 
private Map<String, Font> cached;
 
 
 
public CachedFontProvider(FontProvider fontProvider) {
 
this.fontProvider = fontProvider;
 
}
 
 
 
public Font getFont(String name) {
 
Font font = cached.get(name);
 
if (font == null) {
 
font = fontProvider.getFont(name);
 
cached.put(name, font);
 
}
 
return font;
 
}
 
}
 
 
 
 
 
/* 對工廠類進行相應修改,代碼使用處不必進行任何修改。
 
這也是面向接口編程以及工廠模式的一個好處 */
 
public abstract class ProviderFactory {
 
public static FontProvider getFontProvider() {
 
return new CachedFontProvider(new FontProviderFromDisk());
 
}
 
}

 

當然,我們直接修改FontProviderFromDisk類也可以實現目的,但是我們還有FontProviderFromNet, FontProviderFromSystem等多種實現類,一一修改太過繁瑣且易出錯。

況且將來還可能添加日志,權限檢查,異常處理等功能顯然用代理類更好一點。

② 然而為什么要用動態代理?
考慮以下各種情況,有多個提供類,每個類都有getXxx(String name)方法,每個類都要加入緩存功能,使用靜態代理雖然也能實現,但是也是略顯繁瑣,需要手動一一創建代理類。

public abstract class ProviderFactory {
 
public static FontProvider getFontProvider() {...}
 
public static ImageProvider getImageProvider() {...}
 
public static MusicProvider getMusicProvider() {...}
 
......
 
}

 

使用動態代理怎么完成呢?

public class CachedProviderHandler implements InvocationHandler {
 
private Map<String, Object> cached = new HashMap<>();
 
private Object target;
 
 
 
public CachedProviderHandler(Object target) {
 
this.target = target;
 
}
 
 
 
public Object invoke(Object proxy, Method method, Object[] args)
 
throws Throwable {
 
Type[] types = method.getParameterTypes();
 
if (method.getName().matches("get.+") && (types.length == 1) &&
 
(types[0] == String.class)) {
 
String key = (String) args[0];
 
Object value = cached.get(key);
 
if (value == null) {
 
value = method.invoke(target, args);
 
cached.put(key, value);
 
}
 
return value;
 
}
 
return method.invoke(target, args);
 
}
 
}
 
 
 
public abstract class ProviderFactory {
 
public static FontProvider getFontProvider() {
 
Class<FontProvider> targetClass = FontProvider.class;
 
return (FontProvider) Proxy.newProxyInstance(targetClass.getClassLoader(),
 
new Class[] { targetClass },
 
new CachedProviderHandler(new FontProviderFromDisk()));
 
}
 
}

 

③ 這也是為什么Spring這么受歡迎的一個原因

Spring容器代替工廠,Spring AOP代替JDK動態代理,讓面向切面編程更容易實現。
在Spring的幫助下輕松添加,移除動態代理,且對源代碼無任何影響。

===================================================================================================

代理的分類

1、動態代理和靜態代理

2. 動靜態代理的區別,什么場景使用?(2015-11-25)
靜態代理通常只代理一個類,動態代理是代理一個接口下的多個實現類。
靜態代理事先知道要代理的是什么,而動態代理不知道要代理什么東西,只有在運行時才知道。
動態代理是實現 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是你的
業務類必須要實現接口,通過 Proxy 里的 newProxyInstance 得到代理對象。
還有一種動態代理 CGLIB,代理的是類,不需要業務類繼承接口,通過派生的子類來實現代理。通過在運行
時,動態修改字節碼達到修改類的目的。
AOP 編程就是基於動態代理實現的,比如著名的 Spring 框架、Hibernate 框架等等都是動態代理的使用例子。
3、寫一個 ArrayList 的動態代理類
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * @author cdlr
 * @version 1.0
 * @description:
 * @date 2020/4/28 11:05
 */
public class ArrayListProxyDemo {

    public static void main(String[] agrs){
        final List<String> list = new ArrayList<String>();

        List<String> proxyInstance = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(),  new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return method.invoke(list, args);
            }
        });

        proxyInstance.add("ArrayList動態代理");
        System.out.println(list);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM