代理模式
代理模式为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个 客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间 起到中介的作用。
代理模式一般涉及到三个角色
1>抽象角色:声明真实对象和代理对象的共同接口;
2>代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象迚行封装。
3>真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
一、我们自己建一个简单的代理模式
1.新建一个抽象角色:Subject接口
package com.kaishengit.proxy; public interface Subject { public void sales();//销售 }
2.新建一个真实角色:RealSubject(实现Subject接口)
package com.kaishengit.proxy; //Dell public class RealSubject implements Subject{ @Override public void sales() { System.out.println("Dell销售电脑"); } }
3.新建一个代理角色:SubjectProxy(实现Subject接口)
package com.kaishengit.proxy; //代理 public class SubjectProxy implements Subject{ private Subject subject; /** * 传进去要代理的对象 * @param subject */ public SubjectProxy(Subject subject){ this.subject = subject; } @Override public void sales() { System.out.println("忽悠");//销售之前做点... subject.sales(); System.out.println("送东西");//销售之后做点... } }
4.我们测试一下:
package com.kaishengit.proxy; public class Test { public static void main(String[] args) { //被代理对象 RealSubject rs = new RealSubject(); //代理 SubjectProxy sp = new SubjectProxy(rs); sp.sales(); } }
运行结果:
--------------------------------------
忽悠
Dell销售电脑
送东西
--------------------------------------
ok......
二、Java动态代理
Java中动态代理一定要面向接口编程,也就是被代理对象必须实现接口,这是Java动态代理的缺陷。Java动态代理借助的是InvocationHandler接口。
Spring中的AOP使用到Java动态代理
1.由于被代理对象必须实现接口,我们先新建一个接口(Dao)
package com.kaishengit.proxy.java; public interface Dao { public void save(); }
接下来我们创建被代理对象(实现接口):UserDao
package com.kaishengit.proxy.java; public class UserDao implements Dao{ @Override public void save() { System.out.println("save success!"); } }
2.我们创建一个实现InvocationHandler接口的类:MyInvocationHandler
package com.kaishengit.proxy.java; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler{ private Object obj; //传进去被代理对象 public MyInvocationHandler(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before");//之前做点什么 Object result = method.invoke(obj, args);//执行被代理对象的方法 System.out.println("after");//之后做点什么 return result; } }
3.我们测试一下:
package com.kaishengit.proxy.java; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { UserDao ud = new UserDao();//被代理对象 MyInvocationHandler mih = new MyInvocationHandler(ud);//我们新建的实现InvocationHandler接口的类 //创建代理proxyDao Dao proxyDao = (Dao) Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), mih); proxyDao.save(); } }
运行结果:
------------------------------------------
before
save success!
after
------------------------------------------
三、使用CGLib进行动态代理
需要导入cglib的jar包,原理:如果被代理对象没有实现接口,动态产生一个子类来实现代理模式;否则采用Java动态代理模式。需要借助的是cglib包中的MethodInterceptor接口。
Spring中就导入了cglib的jar包,因为其中的AOP用到代理模式,以应对被代理对象没有实现接口
1.我们新建一个被代理对象:UserDao(呵呵,没有实现任何接口啊)
package com.kaishengit.proxy.cglib; public class UserDao { public void save(){ System.out.println("save success!"); } }
2.我们新建一个类实现 MethodInterceptor接口:DaoIntercept
package com.kaishengit.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class DaoIntercept implements MethodInterceptor{ @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before");//执行之前做点... //注意是methodProxy和invokeSuper Object result = methodProxy.invokeSuper(object, args); System.out.println("after");//执行之后做点... return result; } }
3,我们测试一下:
package com.kaishengit.proxy.cglib; import net.sf.cglib.proxy.Enhancer; public class Test { public static void main(String[] args) { UserDao dao = new UserDao(); //Enhancer同样是cglib包中的 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(dao.getClass()); enhancer.setCallback(new DaoIntercept()); //创建代理对象 UserDao proxyDao = (UserDao) enhancer.create(); proxyDao.save(); } }
运行结果:
----------------------------------------------------
before
save success!
after
----------------------------------------------------
----end----