在之前的代码调用阶段,我们用action调用service的方法实现业务即可。
由于之前在service中实现的业务可能不能够满足当先客户的要求,需要我们重新修改service中的方法,但是service的方法不只在我们这个模块使用,在其他模块也在调用,其他模块调用的时候,现有的service方法已经能够满足业务需求,所以我们不能只为了我们的业务而修改service,导致其他模块授影响。
那怎么办呢?
可以通过动态代理的方式,扩展我们的service中的方法实现,使得在原油的方法中增加更多的业务,而不是实际修改service中的方法,这种实现技术就叫做动态代理。
动态代理:在不修改原业务的基础上,基于原业务方法,进行重新的扩展,实现新的业务。
例如下面的例子:
1、 旧业务
买家调用action,购买衣服,衣服在数据库的标价为50元,购买流程就是简单的调用。
2、 新业务
在原先的价格上可以使用优惠券,但是这个功能在以前没有实现过,我们通过代理类,代理了原先的接口方法,在这个方法的基础上,修改了返回值。
代理实现流程:
1、 书写代理类和代理方法,在代理方法中实现代理Proxy.newProxyInstance
2、 代理中需要的参数分别为:被代理的类的类加载器soneObjectclass.getClassLoader(),被代理类的所有实现接口new Class[] { Interface.class },句柄方法new InvocationHandler()
3、 在句柄方法中复写invoke方法,invoke方法的输入有3个参数Object proxy(代理类对象), Method method(被代理类的方法),Object[] args(被代理类方法的传入参数),在这个方法中,我们可以定制化的开发新的业务。
4、 获取代理类,强转成被代理的接口
5、 最后,我们可以像没被代理一样,调用接口的认可方法,方法被调用后,方法名和参数列表将被传入代理类的invoke方法中,进行新业务的逻辑流程。
上代码:
IBoss.java
/** * 这是一个业务的接口,这个接口中的业务就是返回衣服的价格 * @author wilson * */public interface IBoss { //接口 int yifu(String size);}
Boss.java
/** * 实现了卖衣服的接口 * 自定义了自己的业务,卖裤子 * @author wilson * */public class Boss implements IBoss{ public int yifu(String size){ System.err.println("天猫小强旗舰店,老板给客户发快递----衣服型号:"+size); //这件衣服的价钱,从数据库读取 return 50; } public void kuzi(){ System.err.println("天猫小强旗舰店,老板给客户发快递----裤子"); }}
SaleAction.java
public class SaleAction { /** * 不使用代理,直接调用方法 * 方法中规定什么业务,就只能调用什么业务,规定什么返回值,就只能输出什么返回值 */ @Test public void saleByBossSelf() throws Exception { IBoss boss = new Boss(); System.out.println("老板自营!"); int money = boss.yifu("xxl");// 老板自己卖衣服,不需要客服,结果就是没有聊天记录 System.out.println("衣服成交价:" + money); /* 程序输出: 天猫小强旗舰店,老板给客户发快递----衣服型号:xxl 老板自营! 衣服成交价:50 */ }}
使用动态代理:
ProxyBoss.java
public class ProxyBoss { /** * 对接口方法进行代理 */ @SuppressWarnings("unchecked") //写法一:通过参数传入代理对象的Class ,更灵活,更方便的适配 public staticT getProxy(final int discountCoupon,final Class interfaceClass, final Class implementsClass) throws Exception { return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[] { interfaceClass }, new InvocationHandler() { public Object invoke(Object proxy, Method method,Object[] args) throws Throwable { Integer returnValue = (Integer) method.invoke(implementsClass.newInstance(), args);// 调用原始对象以后返回的值 return returnValue - discountCoupon; } }); } //写法二:在方法内部指定对象的Class public static IBoss getProxyBoss(final int discountCoupon) throws Exception { Object proxedObj = Proxy.newProxyInstance(Boss.class.getClassLoader(),new Class[] { IBoss.class }, new InvocationHandler() { public Object invoke(Object proxy, Method method,Object[] args) throws Throwable { Integer returnValue = (Integer) method.invoke(new Boss(),args);// 调用原始对象以后返回的值 return returnValue - discountCoupon; } }); return (IBoss)proxedObj; }}
调用动态代理:
ProxySaleAction.java
/** * 什么是动态代理? 简单的写一个模板接口,剩下的个性化工作,好给动态代理来完成! */public class ProxySaleAction { /** *使用代理,在这个代理中,只代理了Boss的yifu方法 *定制化业务,可以改变原接口的参数、返回值等 */ @Test public void saleByProxy() throws Exception { /* * 将代理的方法实例化成接口 10是要打折的价格数 * 如下这种写法对应的是ProxyBoss.java中的public staticT getProxy(final int...这种方法 * IBoss boss = ProxyBoss.getProxy(10,IBoss.class,Boss.class); */ //如下这种写法对应的是ProxyBoss.java中的public static IBoss getProxyBoss(final int 这种方法.... IBoss boss = ProxyBoss.getProxyBoss(10);// 将代理的方法实例化成接口 System.out.println("代理经营!"); //调用接口的方法,实际上调用方式没有变 调用了invoke()方法 int money = boss.yifu("xxl"); System.out.println("衣服成交价:" + money); /* 程序输出: 代理经营! 衣服成交价:40 天猫小强旗舰店,老板给客户发快递----衣服型号:xxl */ }}
//==================另外一个总结=======================
上代码:
Waiter.java
public interface Waiter { public void server(); public String sayHello(String name);}
GirWaiter.java
public class GirlWaiter implements Waiter{ @Override public void server() { System.out.println("服务中………………"); } @Override public String sayHello(String name) { return "Hello"+name; }}
ProxyDemo2.java
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import org.junit.Test;public class ProxyDemo2 { @Test public void demo1(){ //用当前的java类文件来获得ClassLoader对象. ClassLoader loader = ProxyDemo2.class.getClassLoader(); //这是个数组,要用大括号括起来,而且返回的得到的是Class对象. Class[] interfaces = {Waiter.class}; /** loader - 定义代理类的类加载器 interfaces - 代理类要实现的接口列表 h - 指派方法调用的调用处理程序 newProxyInstance方法中需要传递三个参数: * loader: * interfaces:代理类要实现的接口列表 * h: h - 指派方法调用的调用处理程序 * 应付一下: * ClassLoader: * Class[] 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于: Proxy.getProxyClass(loader, interfaces). getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler }); 想为Waiter接口的一个实现类生成一个代理.就需要传入你这个类的实现接口的class.为什么是一个数组,一个类可以实现多个接口. 想生成这个Waiter接口的代理类....传入Waiter.class Proxy.newProxyInstance返回的是个Object类型,需要去强转 MyInvocationHandler类中没有含有参数的构造方法,所以在new一个MyInvocationHandler的时候 一定要传入一个参数. 这样才能编译通过.才能真正new出一个MyInvocationHandler对象. */ Waiter waiter = (Waiter) Proxy.newProxyInstance(loader, interfaces, new MyInvocationHandler(new GirlWaiter())); //调用waiter中的方法就相当域调用invoke的方法. waiter.server(); String s = waiter.sayHello("张三"); System.out.println(s); }}//InvocationHandler 是代理实例的调用处理程序 实现的接口。class MyInvocationHandler implements InvocationHandler{ /* //在这个MyInvocationHandler的构造方法中传入一个GirlWaiter对象 public MyInvocationHandler(GirlWaiter girlWaiter){ } */ /* 对这个接口生成了一个代理类了....到底是生成一个接口的代理类还是生成这个接口的实现类的代理类.... 两个都可以,但是接口相当于其实现类的父类 但是接口更通用...所以一般都是生成接口的代理类. */ private Waiter waiter; public MyInvocationHandler(Waiter waiter){ //传入参数的这个地方也用接口来做,更通用. this.waiter = waiter; } @Override /**不要忘记invoke()方法也是有参数的!! * invoke方法: * * 调用waiter的某个方法都相当于调用invoke方法. * * invoke方法的参数: * * proxy:代理对象. * * method:正在执行的方法. * * args:方法的参数列表. */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //只想增强一个固定的方法,方法名是固定的,通过if判断进行筛选... /* * debug.... * demo1中waiter.server() 的时候 * method.getName = server ; args = null ; obj = null; * demo1中waiter.sayHello("张三"); * method.getName = sayHello ; args = '张三' ; obj = "Hello张三" */ Object obj = null; if("server".equals(method.getName())){ System.out.println("微笑"); obj = method.invoke(waiter,args); }else{ obj = method.invoke(waiter,args); } return obj; }}
运行输出:
微笑服务中………………Hello张三
PS:之间总结的关于静态代理的博文