Java 的动态代理模式
代理模式(Proxy)
其实JAVA 的每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。
例码:
public interface Sourceable { public void method(); } public class Source implements Sourceable { @Override public void method() { System.out.println("the original method!"); } } public class Proxy implements Sourceable { private Source source; public Proxy(){ super(); this.source = new Source(); } @Override public void method() { before(); source.method(); atfer(); } private void atfer() { System.out.println("after proxy!"); } private void before() { System.out.println("before proxy!"); } }
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
代理模式JAVA&Spring AOP 中的应用
代理的实现分动态代理和静态代理,静态代理的实现是对已经生成了的JAVA类进行封装。
动态代理则是在运行时生成了相关代理累,在JAVA中生成动态代理一般有两种方式。
一、JAVA 自带的代理实现:
JDK实现代理生成,是用类 java.lang.reflect.Proxy, 实现方式如下
public class JDKProxy { public static Object getPoxyObject(final Object c) { return Proxy.newProxyInstance(c.getClass().getClassLoader(), c.getClass().getInterfaces(),// JDK实现动态代理,但JDK实现必须需要接口 new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object reObj = null; System.out.print("you say: "); reObj = method.invoke(c, args); System.out.println(" [" + Calendar.getInstance().get(Calendar.HOUR) + ":" + Calendar.getInstance().get(Calendar.MINUTE) + " " + Calendar.getInstance().get(Calendar.SECOND) + "]"); return reObj; } }); } }
1, Proxy实现代理的目标类必须有实现接口
2, 生成出来的代理类为接口实现类,和目标类不能进行转换,只能转为接口实现类进行调用
明显特点:通过此方法生成出来的类名叫做 $Proxy0
二、用 CGLIB 实现
public class CGLIBProxy { public static Object getPoxyObject(Object c) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(c.getClass()); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable { System.out.print("you say: "); proxy.invokeSuper(arg0, arg2); System.out.println(" [" + Calendar.getInstance().get(Calendar.HOUR) + ":" + Calendar.getInstance().get(Calendar.MINUTE) + " " + Calendar.getInstance().get(Calendar.SECOND) + "]"); return null; } }); return enhancer.create(); } }
1, CGLIB实现方式是对代理的目标类进行继承
2, 生成出了的代理类可以没方法,生成出来的类可以直接转换成目标类或目标类实现接口的实现类,因JAVA向上转换
明显特点:通过输出看出,看出生成出的代理类的parent类为代理的目标类
Spring AOP中,当拦截对象实现了接口时,生成方式是用JDK的Proxy类。当没有实现任何接口时用的是GCLIB开源项目生成的拦截类的子类.