Java代理设计模式是非常常用的设计模式,像spring中就使用了很多的代理模式
使用代理我们可以对一个类进行增强或者缩减功能;代理可以分为静态代理和动态代理
静态代理:代理对象在编译期,就已经被编译成class,在运行之前就已经存在了
动态代理:代理对象是在运行期间通过反射生成的
一、静态代理
静态代理使用起来比较简单,但是由于它是写死的,所以很不灵活,耦合度比较高
1.1、我们需要创建一个接口模板
public interface Animal { public void call(); }
1.2、创建被代理类Dog实现Animal接口,并实现其call方法
public class Dog implements Animal { @Override public void call() { System.out.println("我会跑"); } }
1.3、创建代理类,这个类也需要实现Animal接口,我们通过构造器获取被代理类对象,并对其进行增强操作
public class AnimalStaticProxy implements Animal { Animal animal; public AnimalStaticProxy(Animal animal) { this.animal = animal; } @Override public void call() { animal.call(); System.out.println("我还会游泳”); } }
1.4、测试
public class Test { public static void main(String[] args) { Animal dog=new Dog(); AnimalStaticProxy staticProxy=new AnimalStaticProxy(cat); staticProxy.call(); } }
从运行结果可以看到我们对Dog进行了增强,它不但拥有原本的跑步功能,还拥有了游泳的技能;
二、动态代理
虽然我们可以很简单的使用静态代理对一个类进行增强,但是大家应该都发现了,我们在new代理类的时候传入的对象必须是实现Animal这个接口的实现类;所以,这个就很不灵活了,假设有一个Plant接口的实现类,由于它没有实现Animal这个接口,所以没有办法对它进行增强,只能再写一个PlantStaticProxy代理类,如果我们增强的代码都是相同的,又有很多实现类需要进行增强,我们就需要写大量的代理类,这样是非常蛋疼的,而且维护起来也特别麻烦;所以动态代理出现了;
2.1、我们创建动态代理类时,需要实现InvocationHandler接口,并实现其invoke方法,这个方法在代理对象调用其方法函数时,会被触发;
public class AnimalDynamicProxy implements InvocationHandler { Object object; //生成并返回代理对象 public Object getProxy(Object object) { this.object = object; return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doBefore(); Object result = method.invoke(object, args); doAfter(); return result; } private void doBefore() { System.out.println("[Proxy]一些前置处理"); } private void doAfter() { System.out.println("[Proxy]一些后置处理"); } }
2.2、测试
public static void main(String[] args) { Animal dog=new Dog(); AnimalDynamicProxy dynamicProxy=new AnimalDynamicProxy(); Animal animal = (Animal)dynamicProxy.getProxy(cat); animal.call(); }
我们可以看到运行结果,代理类的invoke方法被执行了,并对被代理类进行了增强
3.3、我们再创建一个Plant接口及PlantImpl实现类
接口类
public interface Plant { public void call(); }
实现类
public class PlantImpl implements Plant { @Override public void call() { System.out.println("我是蒲公英"); } }
3.4、测试
我们可以看到,两个不同接口的实现类都使用了同一个代理类进行增强了,这就是动态代理的好处