1. 程式人生 > >每天一個設計模式之代理模式

每天一個設計模式之代理模式

代理模式介紹

靜態代理沒有什麼好說的,不斷的寫新的類,實現與被代理類一樣的介面,從而來拓展功能。缺點太多,如介面變化,就要重寫新的代理類。

動態代理使用最多的可能就是傳說中的aop了。它解決了靜態代理的缺點,即使介面變化了,代理類也不需要變化。動態代理實現方式主要有兩種:1、jdk自帶的 2、cglib技術

個人覺得代理模式的用處就是在不對原有類進行修改的情況下,對類的功能進行增強。有前置增強、後置增強、環繞增強、丟擲增強、引入增強等。其中前四種增強是對類的方法的增強,叫做織入(Weaving),丟擲增強可以對異常進行處理。引入增強是對類進行增強,如給類新增新的方法等。

jdk實現動態代理

介面:

public interface HelloWorld {
  void say();
}

被代理類:

public class Hello implements HelloWorld {

    @Override public void say() {
        System.out.println("Hello World");
    }
}

動態代理類:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public
class JdkDynamicProxy { private static class HelloWorldDynamicProxy implements InvocationHandler{ Object target; public HelloWorldDynamicProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Hello Dota"
); method.invoke(target, args); System.out.println("Hello Dota2"); return null; } //Object像下轉型為T,會有警告,這裡利用了泛型,否則呼叫完的結果還需要強制轉換 @SuppressWarnings("unchecked") public <T> T getProxy(){ return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } } public static void main(String args[]){ Hello hello = new Hello(); HelloWorld proxy = new HelloWorldDynamicProxy(hello).getProxy(); proxy.say(); } }

結果:

Hello Dota
Hello World
Hello Dota2

Cglib動態代理技術

jdk中的動態代理需要被代理類實現了某個介面。但是cglib可以代理一個沒有實現任何介面的類。cglib建立代理的速度比較慢,但是建立代理後執行的速度卻非常快,而jdk動態代理卻正好相反。還是用上面的例子,cglib的代理類如下。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibDynamicProxy implements MethodInterceptor {

    private static CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy();

    public static CglibDynamicProxy getInstance(){
        return cglibDynamicProxy;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> cls){
        return (T) Enhancer.create(cls,this);
    }

    @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("dota");
        Object object = methodProxy.invokeSuper(o,objects);
        System.out.println("dota2");
        return object;
    }

    public static void main(String args[]){
    CglibDynamicProxy.getInstance().getProxy(Hello.class).say();
    }

}

另外如果工程用maven管理,使用cglib需要新增maven依賴

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>