原文链接:https://www.leahy.club/archives/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%BB%A3%E7%90%86%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F
什么是代理?
代理就是为其他对象提供一些代理服务以控制的访问或者扩展功能。
Java中常见的代理模式主要有两种:一种是静态代理,一种是动态代理。
静态代理:
静态代理就是代理类和被代理类都实现了相同的接口,在使用时将被代理类作为参数传给代理类,在代理类中调用被代理类的方法,并且在这些方法调用时可以加入一些方法,比如权限控制等,从而实现某些特定的功能。但是静态代理的缺点在于必须有一个代理类实现了被代理类的接口,这样会导致两个局限:①如果同时代理多各类,会导致代理类的无限扩展②如果被代理类中有多个方法,同样的逻辑需要反复实现。
动态代理:
为了解决静态代理的不足,提出了动态代理。动态代理在代码中并不会针对每个被代理类实现其接口,而是根据被代理类动态的生成代理类。例如在Java中主要是使用反射包下的Proxy类和InvocationHandler接口来实现动态代理。Proxy用来生成代理对象;InvocationHandler主要用于自定义代理逻辑处理;为了完成被代理对象的方法拦截,需要在InvocationHandler对象中传入被代理对象的实例。这样做的好处在于只要你在newProxyInstance方法中指定代理需要实现的接口(需要用到反射),指定用于自定义处理的InvocationHandler对象,整个代理的逻辑处理都在你自定义的InvocationHandler实现类中进行处理。至此,而我们终于可以从不断地写代理类用于实现自定义逻辑的重复工作中解放出来了,从此需要做什么,交给InvocationHandler。
动态代理的作用?
动态代理可以在我们不改变源码的情况下,直接在方法中插入自定义的逻辑,这种编程方式叫做AOP,即面向切面编程。基于这样一种动态代理,可以做很多事情,比如:事物的提交或回退、权限管理(拦截器的设计)等。
静态代理举例:
interface ClothFactory{ void produceCloth(); } //代理类 class ProxyClothFactory implements ClothFactory{ private ClothFactory factory;//用被代理类对象进行实例化 public ProxyClothFactory(ClothFactory factory){ this.factory = factory; } @Override public void produceCloth() { System.out.println("代理工厂做一些准备工作"); factory.produceCloth(); System.out.println("代理工厂做一些后续的收尾工作"); } } //被代理类 class NikeClothFactory implements ClothFactory{ @Override public void produceCloth() { System.out.println("Nike工厂生产一批运动服"); } } public class StaticProxyTest { public static void main(String[] args) { //创建被代理类的对象 ClothFactory nike = new NikeClothFactory(); //创建代理类的对象 ClothFactory proxyClothFactory = new ProxyClothFactory(nike); proxyClothFactory.produceCloth(); } }
动态代理举例:
interface Human { String getBelief(); void eat(String food); } //被代理类 class SuperMan implements Human { @Override public String getBelief() { return "I believe I can fly."; } @Override public void eat(String food) { System.out.println("我喜欢吃" + food); } } class HumanUtil{ public void method1(){ System.out.println("====================通用方法一===================="); } public void method2(){ System.out.println("====================通用方法二===================="); } } /* 要想实现动态代理,需要解决的问题? 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。 */ class ProxyFactory{ //调用此方法,返回一个代理类的对象。解决问题一 public static Object getProxyInstance(Object obj){//obj:被代理类的对象 MyInvocationHandler handler = new MyInvocationHandler(); handler.bind(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler); } } class MyInvocationHandler implements InvocationHandler{ private Object obj;//需要使用被代理类的对象进行赋值 public void bind(Object obj){ this.obj = obj; } //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke() //将被代理类要执行的方法a的功能就声明在invoke()中 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { HumanUtil util = new HumanUtil(); util.method1(); //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法 //obj:被代理类的对象 Object returnValue = method.invoke(obj,args); util.method2(); //上述方法的返回值就作为当前类中的invoke()的返回值。 return returnValue; } } public class ProxyTest { public static void main(String[] args) { SuperMan superMan = new SuperMan(); //proxyInstance:代理类的对象 Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法 String belief = proxyInstance.getBelief(); System.out.println(belief); proxyInstance.eat("四川麻辣烫"); System.out.println("*****************************"); NikeClothFactory nikeClothFactory = new NikeClothFactory(); ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory); proxyClothFactory.produceCloth(); } }