代理为什么使用代理,代理的主要作用就可以在不改动原有代码的基础上给原有对象添加新的功能,实现的方法是被代理类和代理类继承同一个类或者实现了同一个接口,java中代理分为静态代理和动态代理:
1.静态代理
静态代理中的静态主要表现在代理类是在提前写好的,也可以说所使用的代理在程序运行开始之前就知道,代理对象是通过new出来的。我们的被代理对象是一个自行车,后面对车进行了升级,可以在上面使用电动的骑行。
Machine.java
1 2 3
| public interface Machine { void drive(); }
|
Bicycle.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Bicycle implements Machine{ private String name; public Bicycle() { this.name = "人力"; } public String getName() { return name; } public void setName(String name) { this.name = name; }
@Override public void drive() { System.out.println("我正在使用"+this.name+"骑行"); } }
|
EleBicycle.java
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class EleBicycle implements Machine{ private Bicycle bicycle; public EleBicycle(Bicycle bicycle) { this.bicycle = bicycle; }
@Override public void drive() { System.out.println("现在升级了电力,可以用电力骑行"); this.bicycle.setName("电力"); this.bicycle.drive(); } }
|
People.java
1 2 3 4 5 6 7 8 9 10 11
| public class People {
public static void main(String[] args) { Bicycle bicycle = new Bicycle(); bicycle.drive();
Machine bicycleProxy = new EleBicycle(bicycle); bicycleProxy.drive(); } }
|
他们直接的关系可以看成如图所示,自行车(Bicycle)和加了电的自行车(EleBicycle)分别是被代理的对象和代理,他们都实现了Machine这个接口,然后People这个用户来消费这个产品。
通过上面的例子可以明显看出来使用代理的好处就是当我们需要对我们的类进行功能升级时不用直接在写好的类上面重新加功能代码,因为可能在有的地方是需要升级过的类,有的地方是需要未升级的类。使用代理的方式也使代码得到了复用。但使用静态代理也存在一些缺点:使用静态代理需要我们在代码运行之前就需要知道用户需要新加的功能是在那个代理类里面,但在实际开发中会存在在开发的时候,开发人员不知道用户需要的操作要使用哪个代理类,只有当用户点击页面时才知道用户所要使用的代理类,这种代理也就是我们所要学到的动态代理。
2.动态代理
动态代理的使用情景在于开发人员无法在程序运行开始前知道用户所要使用的代理是那个,这种在程序运行中创建对象的方法自然就想到了反射。在java的动态代理中最重要的是一个接口InvocationHandler,我们的代理类要实现这个接口同时重写其中的invoke()方法,和一个Proxy类中的newProxyInstance()静态方法用来动态的创建代理类。动态代理中的代理类不要我们手动写,只需要些一个实现了InvocationHadler接口的类,通过Proxy会自动根据我们的handler来创建代理类。
Hello.java
1 2 3 4 5
| public interface Hello { public String hello();
public String bye(); }
|
HelloWorld.java
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class HelloWorld implements Hello{ @Override public String bye() { System.out.println("这是被代理对象中的bye"); return "bye"; }
@Override public String hello() { System.out.println("这是被代理对象中已有的方法"); return "hello"; } }
|
WorkHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class WorkHandle implements InvocationHandler { private Object object;
public WorkHandle(Object object) { this.object = object; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理类中的新功能"); if(method.getName()=="bye"){ System.out.println("代理类中的bye"); } Object invoke = method.invoke(object,args);
return invoke; }
public static void main(String[] args) { Hello people = new HelloWorld(); InvocationHandler invocationHandler = new WorkHandle(people); Hello proxy = (Hello) Proxy.newProxyInstance(invocationHandler.getClass().getClassLoader(), people.getClass().getInterfaces(), invocationHandler); String hello = proxy.hello(); System.out.println(hello); String bye = proxy.bye(); System.out.println(bye); } }
|
上面就是一个动态代理的实现过程,我们还可以写不同的handler,运行中可以根据不同的handler来实现不同的代理。下面将Proxy和InvocationHandler展开细看。
1.Proxy类
其中的newProxyInstance()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); }
Class<?> cl = getProxyClass0(loader, intfs);
try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); }
final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
|
2.InvocationHandler
1 2 3 4
| public interface InvocationHandler{ public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }
|