Java與Spring的代理

1.靜態代理

靜態代理,顧名思義,手動代碼代理。通過代理類實現被代理類的接口,進而完成代理過程。其實就是才能重寫了,原本的接口方法,手動去在目標方法執行前中后,進行切割,進而實現代理。

public class TestStaticProxy {

    public static void main(String[] args) {
        IRegisterService iRegisterService = new RegisterServiceImpl();
        IRegisterService proxy = new RegisterServiceProxy(iRegisterService);
        proxy.register("RyanLee", "123");
    }
}
interface IRegisterService {
    void register(String name, String pwd);
}

class RegisterServiceImpl implements IRegisterService {
    @Override
    public void register(String name, String pwd) {
        System.out.println(String.format("【向數據庫中插入數據】name:%s,pwd:%s", name, pwd));
    }
}

class RegisterServiceProxy implements IRegisterService {
    IRegisterService iRegisterService;

    public RegisterServiceProxy(IRegisterService iRegisterService) {
        this.iRegisterService = iRegisterService;
    }

    @Override
    public void register(String name, String pwd) {
        System.out.println("[Proxy]一些前置處理");
        System.out.println(“開始執行被代理的方法”);
        iRegisterService.register(name, pwd);
        System.out.println("[Proxy]一些后置處理");

    }
}

2.JDK代理

JDK代理,動態代理類和被代理類必須繼承同一個接口。動態代理只能對接口中聲明的方法進行代理,有一定限制。每一個動態代理實例都有一個關聯的InvocationHandler。通過代理實例調用方法,方法調用請求會被轉發給InvocationHandler的invoke方法。(這里就可以看出為啥在實例化代理類時,要傳入目標類的接口,這樣在代理類實現的invoke方法里可以直接執行接口方法實現了目標類被代理的過程)。實際上我們發現JDK的動態代理是基于反射的,而實現方式和靜態代理很像,那為啥又說是動態代理呢?其實,細心的小伙伴就已經發現,JDK動態代理這種方式是一種對目標方法的增強,他不關心你目標方法,而是通過newProxyInstance方法來生成新的 \color{#2196F3}{實現接口}的代理對象,只管代理執行,此處解耦。而對比靜態代理就需要靜態代理類知道目標類的信息,實現目標類的接口,限制很多。而動態代理在實現代理的時候,是傳遞需要代理類,的實現,無關接口 所以并不需要為每一種接口都寫一個代理類了。

 public static void main(String[] args) {
        Target tar = new Target();
        ProxyHandler handler = new ProxyHandler();
        BBQ proxy = (BBQ) handler.getProxy(tar);
        proxy.sayBBQ("LF");
    }

    static class Target implements BBQ {
        @Override
        public void sayBBQ(String s) {
            System.out.println("這是原方法執行的 say bbq " + s);
        }
    }

    interface BBQ {
        void sayBBQ(String s);
    }

    static class ProxyHandler implements InvocationHandler {
        Object obj;

        public Object getProxy(Object obj) {
            this.obj = obj;
            Object o = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
            return o;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            doBefore();
            Object result = method.invoke(obj, args);
            doAfter();
            return result;
        }

        private void doBefore() {
            Thread thread = Thread.currentThread();
            System.out.println("[Proxy]一些前置處理" + thread.getName() + " " + thread.getId());
        }

        private void doAfter() {
            System.out.println("[Proxy]一些后置處理");
        }
    }

3.cglib代理

JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。

public static void main(String[] args) {
        Target tar = new Target();
        CGLIBProxyDemo handler = new CGLIBProxyDemo();
        Target proxy = (Target) handler.getProxy(tar);
        proxy.sayBBQ("cglib代理");
    }

    static class Target implements JDKProxyUtil.BBQ {
        @Override
        public void sayBBQ(String s) {
            System.out.println("這是原方法執行的 say bbq " + s);
        }
    }

    interface BBQ {
        void sayBBQ(String s);
    }

    static class CGLIBProxyDemo implements MethodInterceptor {
        private Object target;

        public Object getProxy(Object obj) {
            this.target = obj;
            Enhancer enhancer = new Enhancer();
            //生成子類
            enhancer.setSuperclass(this.target.getClass());
            // 回調方法
            enhancer.setCallback(this);
            // 創建代理對象
            return enhancer.create();
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] param, MethodProxy methodProxy) throws Throwable {
            doBefore();
            Object result = methodProxy.invokeSuper(obj, param);
            doAfter();
            return result;
        }

        private void doBefore() {
            Thread thread = Thread.currentThread();
            System.out.println("[Proxy]一些前置處理" + thread.getName() + " " + thread.getId());
        }

        private void doAfter() {
            System.out.println("[Proxy]一些后置處理");
        }


    }

結語

仔細觀察會發現:\color{#2196F3}{代理}的原理依據,就是多態,要么實現接口生成代理類,要么繼承目標類生成代理類,而\color{#2196F3}{動態}的手段就是反射,利用反射來獲取被代理類的信息,進而才能實現不需要了解目標信息來構建多態,從而動態解耦。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容