代理模式如同字面意思自己做不了的事交给别人代理,代理无论是在生活中还是在编码中都会常常遇见,比如最近比较火的微商,厂商给供货给微商,微商代理厂商卖商品。这个就是代理,那么它在编程中有什么作用呢?
说的通俗一点就是为其他对象提供一种代理以控制对这个对象的访问。主要解决的问题是:在直接访问对象时带来的问题,比如说,要访问的对象在远程的机器上。
举例说明
为了更好的理解代理模式,我为大家举个追女孩的案例。
//我先定义一个男孩的类
public interface Boy {
//定义一个追的方法。
void zhui(String name);
}
//定义一个不害羞人的类代理害羞人做表白的事。
public class BuHaiXiu implements Boy {
Boy beiWoBangMang = null;
public void setBeiWoBangMang(Boy beiWoBangMang) {
this.beiWoBangMang = beiWoBangMang;
}
@Override
public void zhui(String name) {
if("nvsheng".equals(name)){
System.out.println("我自己亲自追求");
}else{
beiWoBangMang.zhui(name);
}
}
}
//害羞人的类
public class HaiXiu implements Boy{
@Override
public void zhui(String name) {
System.out.println("我想追求" + name);
System.out.println("我的套路......");
}
}
大家在上面的代码中很容易就可以看出不害羞的人这个类是代理类,害羞的人每次表白都会被代理类拦截,当害羞的人追求的目标是女神时,代理的那个不害羞的人就不再帮害羞的人,而是自己追求。所以在代理模式中可以做到访问权限的控制。
动态代理模式
1.什么是动态代理:
代理类在运行时创建的代理方式称为动态代理。动态代理与静态代理最大的不同是动态代理的代理类不是在java代码中定义的,而是在运行时根据我们的java代码 “指示”动态生成的。这样的不同给动态代理带来的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
2.那么动态代理是如何实现的呢?
要了解动态代理的实现首先要了解java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口。首先我们先来理解下Proxy这个类,这个类的作用主要是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法
比如:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
这个方法的作用就是得到一个动态的代理对象,接收三个参数,那么这三个参数,代表的是什么呢?
第一个参数:用来加载动态生成的代理类,定义了由哪个ClassLoader对象,并对动态生成的代理类进行加载。
第二个参数:被代理类实现的接口,以便 Proxy 这个工具类要知道哪些方法可以被代理,此参数是个数组。
第三个参数:就是被代理的所有方法都转到 InvocationHandler 的 Invoke 方法去执行。
InvocationHandler接口
介绍完proxy这个方法,接下来我们来了解下InvocationHandler这个接口,每个动态代理类都必须实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由这个接口的(唯一的方法) invoke 方法来进行调用。那么invoke方法是由什么组成的呢?
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
由此可以看出invoke方法由三个参数组成,这三个方法所代表的含义是:
第一个参数:proxy 就是动态生成的代理类的对象
第二个参数:method 被代理类的当前被调用的方法
第三个参数:args 被代理类的当前被调用的方法的参数数据
介绍完proxy类和InvocationHandler接口后,接下来就举个例子,具体说明下吧。
//首先定义一个MyInfo接口里面有两个方法。
public interface MyInf {
void insert(String s);
void update();
}
//注解我这里为了减少代码的边幅,把数据库的连接写成了输出
public class MyInfImpl implements MyInf {
@Override
public void insert() {
System.out.println("insert in myinfimpl");
}
@Override
public void update() {
System.out.println("update in myinfimpl");
}
}
public class MyInvocationHandler implements InvocationHandler {
private MyInf myInf;
//set方法,给我们要代理的真实对象赋初值
public void setMyInf(MyInf myInf) {
this.myInf = myInf;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----before-----");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object result= method.invoke(myInf,args);
System.out.println("----after-----");
return result;
}
最后测试类
public class Main {
public static void main(String[] args) {
MyInf myInf = new MyInfImpl();
InvocationHandler invocationHandler = new MyInvocationHandler();
((MyInvocationHandler) invocationHandler).setMyInf(myInf);
MyInf proxy = (MyInf) Proxy.newProxyInstance(myInf.getClass().getClassLoader(),
myInf.getClass().getInterfaces() ,invocationHandler );
if(proxy!=null) {
proxy.insert();
}
}
}
结果
----before-----
insert in myinfimpl
----after-----
就这样一个简单的动态代理就完成了。还有注意的一细节:
Proxy 这种动态代理机制,有一个前提:被代理类有实现接口,如果没有, Proxy 工具类就无效
其次为什么这行代码要转类型呢?
MyInf proxy = (MyInf) Proxy.newProxyInstance(myInf.getClass().getClassLoader(),
myInf.getClass().getInterfaces() ,invocationHandler );
原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是MyInf类型,所以就可以将其转化为MyInf类型了。
另外想了解jdbc中的动态代理的朋友可以加qq:1402485086我们一起探讨下。
网友评论