此博客用于个人学习,来源于ssm框架的书籍,对知识点进行一个整理。 动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问。 Java中,代理技术由许多种,本篇主要讨论 Spring 常用的 JDK 代理技术和 CGLIB 代理技术。 需要借助接口才能创建代理对象,首先定义一个 HelloWorld 接口: 然后通过 HelloWorldImpl 这个类来实现接口: 进行动态代理: 第一步,建立代理对象与真实对象的关系,这里通过 bind 方法去完成,先是通过类的属性 target 保存了真实对象,然后通过下面的代码建立并生成代理对象。 对 newProxyInstance 方法进行解释: 第二步,实现代理逻辑方法。通过 invoke 函数实现: 这行代码相当于调度真实对象的方法,只是通过反射实现而已。 输出结果: 当我们创建 HelloWorld 对象的时候,就会进入代理的逻辑方法 invoke 中,因为 JDK 生成的代理类,它继承自 Proxy 实现我们定义的 HelloWorld 接口,在实现 HelloWorld 接口方法的内部,通过反射调用了 InvocationHandlerImpl 的 invoke 方法。 对于 JDK 动态代理技术来说,必须提供接口才能使用,在一些不能提供接口的环境中,只能采用其他的第三方技术,比如 CGLIB 动态代理。它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理。 这里用了 CGLIB 的加强者 Enhancer ,通过设置超类的方法(setSuperclass),然后通过 setCallback 方法设置哪个类成为它的代理类。其中,参数为 this 就意味着是当前对象,那就要求用这个 this 这个对象实现接口 MethodInterceptor 的方法——intercept,然后返回代理对象。在反射真实对象方法前后进行了打印,是通过如下代码完成的。 进行测试: CGLIB 动态代理和 JDK 动态代理是相似的,它们都是用 getProxy 方法生成代理对象,制定代理的逻辑类,而代理逻辑类要实现一个接口的一个方法,那么这个接口定义的方法就是代理对象的逻辑方法,它可以控制真实对象的方法。 设计者会为开发者设计一个拦截器供其使用,开发者只需要知道拦截器接口发方法,含义和作用即可,无须知道动态代理是怎么实现的。用 JDK 动态代理来实现一个拦截器的逻辑,先定义拦截器接口 Interceptor,代码如下: 其中要注意的是: 实现这个接口——MyInterceptor,代码如下: 接下来,使用 JDK 动态代理,就可以去实现这些方法在适当时的调用逻辑,此时,在 JDK 动态代理中使用拦截器。 代码执行步骤: 得到结果: 由此可见,拦截器已经生效。 设计者往往会用拦截器去替代动态代理,然后将拦截器的接口提供给开发者,从而简化开发者的开发难度,但是拦截器可能有多个。举个例子,一个程序员需要请假一周,这个时候把请假申请单看成一个对象,那么这个对象会经过项目经理,部门经理,人事部等多个角色的审批,这个时候,每个角色都有机会可以通过拦截这个申请单进行审批或者修改。如图所示: 首先,定义三个拦截器: 对拦截器进行测试: 然后就可以得到以下结果,注意观察方法的执行顺序。 可以看出,before 方法是按照从最后一个拦截器到第一个拦截器的加载顺序运行,而 after 方法正好相反。2.2 动态代理模式和责任链模式
先举个例子,能更好的理解代理模式。你的公司是一家软件公司,你作为一名软件工程师,平时的工作肯定是跟代码打交道。客户来你们公司,肯定不是直接找你谈,而是去找商务谈。此时,对于客户来说,上完就是代表整个公司。
客户是通过商务与软件工程师进行沟通,那么商务(代理对象)的作用是什么呢?商务可以进行谈判,比如项目启动前的商务谈判,软件的价格等等,商务也有可能谈判失败,此时就可以结束与客户的合作关系,这些都不需要软件工程师来处理。因此,代理的作用就是,在真实对象访问之前或者之后加入对应的逻辑,或者根据其他的规则控制是否使用真实对象。
我们需要在调用者调用对象之前产生一个地阿里对象,而这个代理对象需要和真实对象建立代理关系,所以代理分为两个步骤:
2.2.1 JDK 动态代理
public interface HelloWorld { public void sayHelloWorld(); }
public class HelloWorldImpl implements HelloWorld{ @Override public void sayHelloWorld() { System.out.println("Hello World!"); } }
public class JdkProxyExample implements InvocationHandler { //真实对象 private Object target = null; /** * 建立代理对象与真实对象的代理关系 * @param target 真实对象 * @return 返回代理对象 */ public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } /** * 代理方法逻辑 * @param proxy 代理对象 * @param method 当前调度方法 * @param args 当前方法参数 * @return 代理结果返回 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入代理逻辑方法"); System.out.println("在调度真实对象之前的服务"); //相当于调用sayHelloWorld方法 Object obj = method.invoke(target,args); System.out.println("在调度真实对象之后的服务"); return obj; } }
Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
Object obj = method.invoke(target,args);
进行测试:JdkProxyExample jdk = new JdkProxyExample(); //由于是挂在接口HelloWorld下,所以声明代理对象HelloWorld proxy HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl()); proxy.sayHelloWorld();
进入代理逻辑方法 在调度真实对象之前的服务 Hello World! 在调度真实对象之后的服务
2.2.2 CGLIB 动态代理
public class CglibProxyExample implements MethodInterceptor{ /** * 生成 CGLIB 代理对象 * @param cls class类 * @return Class类的 CGLIB 代理对象 */ public Object getProxy(Class cls){ //CGLIB enhancer 增强类对象 Enhancer enhancer = new Enhancer(); //设置增强类型 enhancer.setSuperclass(cls); //定义代理逻辑对象为当前对象,要求当前对象实现 MethodInterception 方法 enhancer.setCallback(this); //生成并返回代理对象 return enhancer.create(); } /** * 代理逻辑方法 * @param proxy 代理对象 * @param method 方法 * @param args 方法参数 * @param methodProxy 方法代理 * @return 代理逻辑返回 * @throws Throwable 异常 */ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)throws Throwable{ System.out.println("调用真实对象前"); //CGLIB 反射调用真实对象方法 Object result = methodProxy.invokeSuper(proxy,args); System.out.println("调用真实对象后"); return result; } }
Object result = methodProxy.invokeSuper(proxy,args);
public void testCGLIBProxy(){ CglibProxyExample cpe = new CglibProxyExample(); ReflectServiceImpl obj = (ReflectServiceImpl)cpe.getProxy(ReflectServiceImpl.class); obj.sayHello("张三"); }
2.2.3 拦截器
public interface Interceptor { public boolean before(Object proxy, Object target, Method method,Object[] args); public void around(Object proxy, Object target, Method method,Object[] args); public void after(Object proxy, Object target, Method method,Object[] args); }
public class MyInterceptor implements Interceptor{ @Override public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("反射方法前逻辑"); //不反射被代理对象的原有方法 return false; } @Override public void around(Object proxy, Object target, Method method, Object[] args) { System.out.println("反射方法后逻辑"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("取代了被代理对象的方法"); } }
public class InterceptorJdkProxy implements InvocationHandler { //真实对象 private Object target; //拦截器的全限定名 private String interceptorClass = null; public InterceptorJdkProxy(Object target,String interceptorClass){ this.target = target; this.interceptorClass = interceptorClass; } /** * 绑定委托对象并返回一个【代理占位】 * @param target 真实对象 * @param interceptorClass 拦截器全限定名 * @return 代理对象【占位】 */ public static Object bind(Object target,String interceptorClass){ //取得代理对象 return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InterceptorJdkProxy(target,interceptorClass)); } /** * 通过代理对象调用方法,首先进入这个方法 * @param proxy 代理对象 * @param method 方法,被调用的方法 * @param args 方法的参数 * @return 代理结果返回 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(interceptorClass == null){ //没有设置拦截器则直接反射原有方法 return method.invoke(target,args); } Object result = null; //通过反射生成拦截器 Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance(); //调用前置方法 if (interceptor.before(proxy,target,method,args)){ //反射原有对象方法 result = method.invoke(target,args); }else{ //返回false执行around方法 interceptor.around(proxy,target,method,args); } //调用后置方法 interceptor.after(proxy,target,method,args); return result; } }
拦截器可以进一步简化动态代理的使用方法,使程序变得更简单,进行测试:public static void main(String[] args) { HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),"ssm.learn.chapter2.interceptor.MyInterceptor"); proxy.sayHelloWorld(); }
反射方法前逻辑 反射方法后逻辑 取代了被代理对象的方法
2.2.4 责任链模式
我们称这种模式为责任链模式,它用于一个对象在多个角色中传递的场景,例如上面这个例子,申请单到了项目经理这里,可以修改申请时间等信息,然后从而影响后面的审批,即,后面的审批需要根据前面的结果进行。这个时候就可以考虑用层层代理来实现,当申请单到项目经理处,使用第一个动态代理 proxy1;当它走到部门经理处,项目经理会得到一个在项目经理的代理 proxy1 基础上生成的 proxy2 来处理部门经理的逻辑;当它走到人事处,会在 proxy2 的基础上生成 proxy3。如果还有其他角色,以此类推即可。public class Interceptor1 implements Interceptor { @Override public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("【拦截器1】的 before 方法"); return true; } @Override public void around(Object proxy, Object target, Method method, Object[] args) { } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("【拦截器1】的 after 方法"); } } public class Interceptor2 implements Interceptor { @Override public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("【拦截器2】的 before 方法"); return true; } @Override public void around(Object proxy, Object target, Method method, Object[] args) { } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("【拦截器2】的 after 方法"); } } public class Interceptor3 implements Interceptor { @Override public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("【拦截器3】的 before 方法"); return true; } @Override public void around(Object proxy, Object target, Method method, Object[] args) { } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("【拦截器3】的 after 方法"); } }
public static void main(String[] args) { HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),"ssm.learn.chapter2.responsibility.Interceptor1"); HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(proxy1,"ssm.learn.chapter2.responsibility.Interceptor2"); HelloWorld proxy3 = (HelloWorld) InterceptorJdkProxy.bind(proxy2,"ssm.learn.chapter2.responsibility.Interceptor3"); proxy3.sayHelloWorld(); }
【拦截器3】的 before 方法 【拦截器2】的 before 方法 【拦截器1】的 before 方法 Hello World! 【拦截器1】的 after 方法 【拦截器2】的 after 方法 【拦截器3】的 after 方法
从代码中可见,责任链模式的优点在于我们可以在传递链上加入新的拦截器,增加拦截逻辑,其缺点是会增加代理和反射,而代理和反射的性能不高。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算