说到动态代理就要先了解静态代理,了解静态代理就要知道什么是代理模式
通过代理对象去访问目标对象。这样可以在目标对象的基础上,增强额外的功能操作,去扩展目标对象的功能。 使用到编程中的一个思想:不要随表去修改别人已经写好的代码或者方法,如果要修改可以使用代理的方式去扩展该方法。 例如: 我们想去法国买香水,但是我们一般不会直接自己飞到法国去买香水,以为我们不熟悉当地的环境,不会语言,而且来回路费花销特特别大。这个时候我们往往去找一个代理商,这个代理商会对这个买香水的服务进行增强,代理商会问你想要什么的价位,什么味道等等,等你使用后还会给你提供一段时间的售后服务,这比你单单自己跑去法国买香水强多了。这个代理商就是我们设计的代理对象,用来对事务的增强,而又不去代表原来的法国的香水生产。
使用的时候需要定义接口或者父类,被代理的对象和代理的对象都要实现相同的接口和共同的父类。
//法国香水工厂接口,所有的香水都要售卖香水 public interface PerfumeFactory{ public void sale(); } //爱马仕的香水工程实现工程的接口 public class Hermesactory implements GoodsFactory{ @Override public void sale() { System.out.println("我在售卖爱马仕的香水"); } } //我是香水的代理商,我提供购买香水的额外服务 public class MyAgent implements PerfumeFactory{ private PerfumeFactory factory; public MyAgent(PerfumeFactory factory){ this.factory = factory; } @Override public void sale() { saleBefore(); factory.sale(); saleafter(); } private void saleBefore(){ System.out.println("我为顾客提供购买爱马仕香水的售前服务"); } private void saleafter(){ System.out.println("我为顾客提供购买爱马仕香水提供售后服务"); } } //我是消费者,我要找代理商去购买香水 public class Consumer { public static void main(String[] args) { Hermesactory hermesactory = new Hermesactory(); MyAgent myAgent = new MyAgent(hermesactory); myAgent.sale(); //下面为输出的内容 //我为顾客提供购买爱马仕香水的售前服务 //我在售卖爱马仕的香水 //我为顾客提供购买爱马仕香水提供售后服务 } }上面的例子就是静态代理的典型的例子,我们在不改动爱马仕工厂的代码下,去增强我们的销售服务
过一段时间后有人去问我这个代理商做不做法国衣服的购买,这个时候我要实现这个工程就需要改变我的代理商的代码
//衣服的接口,提供穿的方法 public interface ClothFactory { public void wear(); } //法国香奈儿的衣服的工程,实现销售香奈儿的衣服 public class ChanelFactory implements ClothFactory { @Override public void wear() { System.out.println("我在销售香奈儿的衣服"); } } //代理商新增的功能 public class MyAgent implements PerfumeFactory , ClothFactory{ private Object factory; public MyAgent(Object factory){ this.factory = factory; } @Override public void sale() { saleBefore(); PerfumeFactory perfumeFactory = (PerfumeFactory)factory; perfumeFactory.sale(); saleafter(); } @Override public void wear() { saleBefore(); ClothFactory clothFactory = (ClothFactory)factory; clothFactory.wear(); saleafter(); } private void saleBefore(){ System.out.println("我为顾客提供购买爱马仕香水的售前服务"); } private void saleafter(){ System.out.println("我为顾客提供购买爱马仕香水提供售后服务"); } } //消费者既要买香水有要买衣服 public class Consumer { public static void main(String[] args) { Hermesactory hermesactory = new Hermesactory(); MyAgent myAgent = new MyAgent(hermesactory); myAgent.sale(); ClothFactory clothFactory = new ChanelFactory(); MyAgent myAgent1 = new MyAgent(clothFactory); myAgent1.wear(); //输出的内容 //我为顾客提供购买爱马仕香水的售前服务 //我在售卖爱马仕的香水 //我为顾客提供购买爱马仕香水提供售后服务 //我为顾客提供购买爱马仕香水的售前服务 //我在销售香奈儿的衣服 //我为顾客提供购买爱马仕香水提供售后服务 } }这个新增的代理我们可以看到,我们要实现一个新的工程就要写一个接口,其实现类和代理商就要继承这个新的接口(当我们有多个需求的时候,这个代码就太过于冗余了,几个需求就要实现几个接口,这肯定是不合理的),代理商这个类就要改动代码。这个就违反了我们设计代码的时候的开放封闭原则,当我们的需求发生变化的时候我们可以添加新的模块来满足新的需求,而不是通过修改原来的代码来满足新的需求。
这个时候就需要动态代理来实现我们的功能,我们需要在需求改变的时候我们不能改表这个代理商的类,我们直接添加新的接口和其实现类就能满足我们的需求。
这就用到了使用反射生成jdk动态代理
关键步骤:
继承InvocationHandler接口调用Proxy中的newProxyInstance来创建代理类的实例对象,返回给消费者 //动态代理的代理商 public class PerfectAgent implements InvocationHandler { private Object factory; //获得需要工程的实例 public Object getProxyInstance(){ //三个参数代表使用哪一个类加载器去创建对象,这个对象实现的接口,用哪一个类增强 return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(),this); } //实现InvocationHandler接口中唯一的invoke方法,执行对应工厂的方法,并对该方法增强 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { saleBefore(); Object invoke = method.invoke(factory,args); saleafter(); return invoke ; } private void saleBefore(){ System.out.println("我是动态代理的代理商,我提供售前服务"); } private void saleafter(){ System.out.println("我是动态代理的代理商,我提供售后服务"); } public Object getFactory() { return factory; } public void setFactory(Object factory) { this.factory = factory; } } //消费者 public class Consumer { public static void main(String[] args) { PerfectAgent perfectAgent = new PerfectAgent(); //给代理对象传递,当前需要到那个工程购买 perfectAgent.setFactory(new Hermesactory()); //获取该工厂的实例对象 PerfumeFactory perfumeFactory =(PerfumeFactory)perfectAgent.getProxyInstance(); perfumeFactory.sale(); perfectAgent.setFactory(new ChanelFactory()); ClothFactory clothFactory = (ClothFactory)perfectAgent.getProxyInstance(); clothFactory.wear(); } }这样的动态代理,我们在添加新的需求的时候我们不用在去改变这个代理对象,我们直接添加新的需要的接口和其实现类就可以了