每天一個設計模式之代理模式
阿新 • • 發佈:2019-02-09
代理模式介紹
靜態代理沒有什麼好說的,不斷的寫新的類,實現與被代理類一樣的介面,從而來拓展功能。缺點太多,如介面變化,就要重寫新的代理類。
動態代理使用最多的可能就是傳說中的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>