代理模式,是很多框架中应用到的基础,例如mybatis中对于配置环境的元素的读取,以及推荐使用的mapper的接口,其中使用到的就是JDK动态代理技术,然而在spring中也有对应的体现,然而会产生疑问,仅提供一个接口,怎么会执行呢?其实代理的本质就是继承。
好了,我们慢慢的一点点解答:
JDK静态代理:
我们设计了一个HelloService接口和其对应的实现类HelloServiceImpl类:public interface HelloService { public void sayHello(String name); }对应的实现类:
public class HelloServiceImpl implements HelloService { @Override public void sayHello(String name) { // TODO Auto-generated method stub System.out.println("hello " + name); } }如果我们先通过代理的方法来实现的话,我们首先要做的是构建一个代理类,代理类也需要实现HelloService接口:
public class JDKSTA implements HelloService { private HelloServiceImpl helloServiceImpl; public JDKSTA(HelloServiceImpl helloServiceImpl){ this.helloServiceImpl = helloServiceImpl; } @Override public void sayHello(String name) { System.out.println("我准备说hello了"); helloServiceImpl.sayHello(name); System.out.println("我说过hello了"); } }对应的测试类:
public class JDKstatEST { public static void main(String[] args) { //创建JDK代理对象 HelloService proxy= new JDKSTA(new HelloServiceImpl()); proxy.sayHello("zhang san"); } }这样则完成了JDK的静态代理的过程。
JDK动态代理:
HelloService接口和其对应的实现类都不变,我们重新设计一个新的代理类,这次的代理类需要继承InvocationHandler接口,其他的说明在注释中体现了:
扫描二维码关注公众号,回复:
1106330 查看本文章
public class HelloServiceProxy implements InvocationHandler{ private Object target; /** * 帮绑定委托对象并方辉一个代理类 * @param target * @return */ public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override /** * 通过代理对象调用方法首先进入这个方法 * @param proxy 代理对象 * @param method 被调用的方法 * @param 方法的参数 */ public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ System.out.println("############JDK动态代理#########"); Object result = null; System.out.println("我准备说hello"); // //执行方法,相当于调用helloServiceImpl类的sayHello方法 // //此invoke方法为Method类里面的incoke方法,而不是reflect里面的invoke方法 // //此方法实现真正的由接口调用实现类的方法 result =method.invoke(target, args); // //反射方法后调用 System.out.println("我说过hello了"); return result; } }对应的测试类为:
public class HelloServiceMain { public static void main(String[] args) { // TODO Auto-generated method stub //生成一个代理类对象 HelloServiceProxy HelloHandler = new HelloServiceProxy(); //代理接口 HelloService proxy = (HelloService)HelloHandler.bind(new HelloServiceImpl()); proxy.sayHello("zhang san"); } }
CGlib动态代理:
JDK代理需要我们提供接口,必须有接口才能够实现动态,静态代理的过程,而CGlib可以不用提供接口,仅提供实现类就可以完成动态代理的工作,当然也可以完成有接口的动态代理,当然这个就体现不了CGlib的优势。重新设计一个符合CGlib使用的动态代理类:
public class HelloServiceCGlib implements MethodInterceptor{ private Object target; public Object getInstance (Object target){ this.target = target; //下面类似于JDK动态代理的绑定过程 Enhancer enhancer = new Enhancer(); //指定父类,不必指定接口 enhancer.setSuperclass(this.target.getClass()); //回调方法 enhancer.setCallback(this); //创建代理对象 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // TODO Auto-generated method stub System.out.println("###########我是CGLIB###########"); //反射方法的调用 System.out.println("我准备说hello"); Object returnObj = proxy.invokeSuper(obj, args); System.out.println("我说过hello了"); return returnObj; } }对应的测试类:
public class HelloServiceMain { public static void main(String[] args) { // TODO Auto-generated method stub //生成一个代理类对象 //cglib需要指定父类和回调方法。当然cglib也可以与Java动态代理一样面向接口,因为本质是继承。 HelloServiceCGlib HelloHandler = new HelloServiceCGlib(); //代理接口 HelloService proxy = (HelloService)HelloHandler.getInstance(new HelloServiceImpl()); proxy.sayHello("zhang san"); } }
测试结果为: