代理模式,为其他对象提供一种代理以控制对这个对象的访问。【大话设计模式】
一张图,说明代理模式的结构。代理在客户端和目标对象起到的是中介的作用,一种桥梁,也如大话设计模式中所言,为他人做嫁衣。
代理模式按照创建时期可以分为两类:静态代理、动态代理。
静态代理
首先介绍一下静态代理,静态代理的结构完全契合于上图,需要首先定义个接口,业务实现接口,然后定义代理类,且需要实现所有的相同的接口。
首先,定义一个业务接口:
public interface Account { public void save(); }
然后,定义代理类,实现业务接口
public class AccountImpl implements Account { @Override public void save() { System.out.println("保存中。。。。。"); } }
接下来,实现代理类
public class AccountProxy implements Account { private AccountImpl accountImpl; public AccountProxy(AccountImpl accountImpl) { this.accountImpl = accountImpl; } @Override public void save() { System.out.println("开始保存啦。。。。。"); accountImpl.save(); System.out.println("保存结束啦。。。。。"); } }
客户端类:
public class TestAccount { public static void main(String[] args) { AccountImpl accountImpl = new AccountImpl(); AccountProxy proxy = new AccountProxy(accountImpl); proxy.save(); } }
结果如下:
开始保存啦。。。。。
保存中。。。。。
保存结束啦。。。。。
这样静态的代理模式就可以完成了。但是,有个问题,就是代理类要实现所有的业务接口,这样就会造成很多代码重复,为了解决这些,需要用接下来的动态代理模式来实现。
动态代理模式
我们接着用上边的例子,通过动态代理模式实现代理。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy implements InvocationHandler { private Object target; public Object newInstance(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("begin"); result = method.invoke(target, args); System.out.println("end"); return result; } }
客户端调用如下:
import com.huawei.model.proxy.Account; import com.huawei.model.proxy.AccountImpl; public class TestProxy { public static void main(String[] args) { DynamicProxy proxy = new DynamicProxy(); //在这里进行真正的对象传入 Account account= (Account )proxy.newInstance(new AccountImpl()); account.save(); } }
通过对比,我们可以发现,通过动态代理,我们省略了关于代理接口的实现方法,不用讲所有需要被代理的全部方法都要实现,即可实现代理功能。
通过以上方法实现,我们仍然是需要接口的,如果没有接口,该怎么办?
CGLib动态代理
CGLib是一个类库,它可以在运行期间动态生成字节码,动态生成代理类。
代码如下:
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { public <T> T getProxy(Class<T> cls) { return (T)Enhancer.create(cls, this); } @Override public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy proxy) throws Throwable { System.out.println("开始保存啦。。。。。"); Object result = proxy.invokeSuper(obj, arg2); System.out.println("保存结束啦。。。。。"); return result; } }
客户端调用代码:
import com.huawei.model.proxy.Account; import com.huawei.model.proxy.AccountImpl; public class TestProxy { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Account account = proxy.getProxy(AccountImpl.class); account.save(); } }
输出结果:
开始保存啦。。。。。
保存中。。。。。
保存结束啦。。。。。
虽然该方法比上述两种方式均更加灵活,但是其也有自己的缺点,就是会拦截被代理类的所有方法。
参考链接:
https://www.zhihu.com/question/20794107
http://blog.csdn.net/wangyongxia921/article/details/46240877