代理(Proxy),通俗的讲就是找个人帮你去处理事务。它又分为静态代理和动态代理。下面将举例进行说明,存在一个Hello接口
public interface Hello { void say(String name); }
和其实现类
public class HelloImpl implements Hello { @Override public void say(String name) { System.out.println("Hello," + name + "!"); } }
现在我们需要在say方法的前后分别处理一些逻辑,这时我们考虑用到代理模式。如果不使用代理模式,则会将前后逻辑写死在代码中,不利于日后代码的维护和修改,就会如下所示
public class HelloImpl implements Hello { @Override public void say(String name) { before(); System.out.pringln("Hello," + name + "!"); after(); } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
静态代理的做法:
写一个代理类,并通过它去调用HelloImpl的say方法,同时在其前后完成逻辑处理,具体代码如下
public class HelloProxy implements Hello { private Hello hello; public HelloProxy() { hello = new HelloImpl; } @Override public void say(String name) { before(); hello.say(name); after(); } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
对应的main方法为
public static void main() { Hello helloProxy = new HelloProxy(); helloProxy.say("Tom"); }
这样做也会存在问题,问题在于随着日后代码的增多,类似XxxProxy的代理类就会越来越多...
基于JDK动态代理的做法:
public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } @SupperssWarnings("unchecked") public <T> T getProxy() { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this ); } @Override public Object invoke(Object Proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target, args); after(); return result; } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
在这是定义了一个target变量,通过它来实现被代理的目标对象,下面是对应的main方法
public static void main(String[] args) { DynamicProxy dynamicProxy = new DynamicProxy(new HelloImpl()); Hello helloProxy = dynamicProxy.getProxy(); helloProxy.say("Jerry"); }
从上可以看到main方法通过DynamicProxy类去包装HelloImpl实例,并利用自身的getProxy方法动态的创建一个Hello接口,最后调用这个代理类的say方法。单基于JDK动态代理的做法也是存在问题的,即它只能代理接口,而不能代理没有接口的类。
基于CGlib动态代理的做法:
public class CGLibProxy implements MethodInterceptor { private static CGLibProxy instance = new CGLibProxy(); private CGLibProxy() { } public static CGLibProxy getInstance() { return instance; } public <T> T getProxy(Class<T> cls) { return (T) Enhancer.create(cls, this); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { before(); Object result = proxy.invokeSuper(obj, args); after(); return result; } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
对应的main方法可以描述为
public static void main(String[] args) { Hello helloProxy = cgLibProxy.getInstance().getProxy(HelloImpl.class); helloProxy.say("Jack"); }
从而我们可以看到基于CGLib动态代理既可以有接口的代理,又可以实现没有接口的代理,这样也就弥补了JDK的不足。