Java 代理模式有如下几种实现方式:
1.静态代理。
2.JDK动态代理。
3.CGLIB动态代理。
示例,有一个打招呼的接口。分别有两个实现,说hello,和握手。代码如下。
接口:
public interface Greeting { public void doGreet(); }
实现类:
public class SayHello implements Greeting { @Override public void doGreet() { System.out.println("Greeting by say 'hello' ."); } }
public class ShakeHands implements Greeting { @Override public void doGreet() { System.out.println("Greeting by shake others's hands ."); } }
public class KissHello { public void doGreet() { System.out.println("Greeting by kiss . "); } }
在不改变代码的情况下,想在执行目标方法 前后 做一些其他操作。则可以通过代理方式来实现。
1.静态代理。需要创建代理类。代理类实现了和目标类一样的接口,代理类接收目标类对象,并在实现方法中调用目标类的实现方法前后做手脚。如下:
public class GreetStaticProxy implements Greeting { private Greeting hello;//被代理对象 public GreetStaticProxy(Greeting hello){ this.hello=hello; } @Override public void doGreet() { before();//执行其他操作 this.hello.doGreet();//调用目标方法 after();//执行其他操作 } public void before(){ System.out.println("[StaticProxy] Come to someone."); } public void after(){ System.out.println("[StaticProxy] Back to his own corner"); } }
测试调用:
public class Main { public static void main(String[] args) { Greeting hello=new SayHello(); Greeting shakeHands=new ShakeHands(); //静态代理 GreetStaticProxy staticHelloProxy=new GreetStaticProxy(hello); staticHelloProxy.doGreet(); System.out.println(); GreetStaticProxy shakeHandsProxy=new GreetStaticProxy(shakeHands); shakeHandsProxy.doGreet(); }
运行结果:
[StaticProxy] Come to someone. Greeting by say 'hello' . [StaticProxy] Back to his own corner [StaticProxy] Come to someone. Greeting by shake others's hands . [StaticProxy] Back to his own corner
这个方式有弊端,如果有N个接口的实现类需要被代理,则需要创建N个代理类。
2.JDK动态代理
创建代理类,如下:
public class JdkProxy implements InvocationHandler { private Object target; public JdkProxy(Object obj){ this.target=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; before(); result=method.invoke(target, args); after(); return result; } public void before(){ System.out.println("[JdkProxy] Come to someone."); } public void after(){ System.out.println("[JdkProxy] Back to his own corner"); } }
测试调用:
public class Main { public static void main(String[] args) { Greeting hello=new SayHello(); Greeting shakeHands=new ShakeHands(); //jdk动态代理 JdkProxy dynamicProxy=new JdkProxy(hello); Greeting target=(Greeting) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), dynamicProxy); target.doGreet(); System.out.println(); } }
这种方式和第一种方式相比,虽然不需要创建很多代理类,
但是,他依赖与“被代理的对象需要实现接口” 即:在上面给出的代码示例中,动态代理可以代理SayHello和ShakeHands,却不能代理KissHello。因为KissHello没有实现接口。
3.CGLIB动态代理。
创建代理类:
public class CglibProxy implements MethodInterceptor { public static CglibProxy proxy=new CglibProxy(); private CglibProxy(){} public static CglibProxy getInstance(){ return proxy; } public <T> T getProxy(Class<T> cls){ return (T) Enhancer.create(cls, this); } @Override public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable { Object result=null; try { before(); result= proxy.invokeSuper(obj, arg); after(); } catch (Exception e) { e.printStackTrace(); } return result; } public void before(){ System.out.println("[cglib] Come to someone."); } public void after(){ System.out.println("[cglib] Back to his own corner."); } }
调用示例:
public class Main { public static void main(String[] args) { //cglib代理 Greeting targetProxy=CglibProxy.getInstance().getProxy(SayHello.class); targetProxy.doGreet(); System.out.println(); CglibProxy.getInstance().getInstance().getProxy(KissHello.class).doGreet(); } }
综上,CGLIB动态代理最好,spring框架也用到了CGLIB包。