代理的含义在于 代替原对象做更多的事情,而不破坏原代码的代码结构。
代理也分静态代理 和 动态代理,我们先以简单的静态代理为例子。
##静态代理:
定义一个接口
package designmode.代理模式;
public interface Sourceable {
public void method();
}
被代理的对象,它实现了 Sourceable 接口
/**
* 被代理对象
* @author panqian
*
*/
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
然后 假设method方法已经不能满足我们的要求,我们需要在这个方法里输出更多的语句,但是我不需要直接修改Source 这个类,我们可以设计一个代理类:
这个代理类Proxy同样实现了Sourceable 接口,但是多了一个Source 成员变量,我们可以通过构造器接收我们原来的对象,然后在代理类的method()方法中,增强我们原有代码的功能(拓展Source对象method的功能 )。
/**
* Proxy 是一个代理类 静态代理
*
* @author panqian
*/
public class Proxy implements Sourceable {
public Source source;
public Proxy(Source source) {
super();
this.source = source;
}
@Override
public void method() {
System.out.println("before proxy!");
source.method();
System.out.println("after proxy!");
}
}
最后写一个测试用例并看输出的结果:
public class ProxyTest {
public static void main(String[] args) {
Source source = new Source();
Sourceable sourceable = new Proxy(source);
sourceable.method();
}
}
结果:
可以看到,我们达到了我们的目的,不改变原有代码而增强了代码的功能
before proxy!
the original method!
after proxy!
##动态代理
在写代理模式时,我们做的其实是面向接口编程,代理类和被代理类都实现了一个接口,这也是代理的规范写法。在静态代理中,我们自己要编写代理类,虽然没有破坏原有代码,但是也有几个问题
####1.如果我们要做不同接口的代理,而且我们需要增强的功能没有区别的话,重复的编写代理类是 就造成了代码重复。
####2.如果源对象的接口新增了方法,实现类不用多说,就连代理类也需要重新实现新的方法,代码维护难度上升了。
上面问题全出在需要委托代理的类需要跟 代理类一一对应上,jdk给我们的解决方案便是 动态代理。在动态代理中,我们不需要委托类跟代理类一一对应,上面的两个问题 动态代理 来帮我们解决~!
为了展示动态代理的好处,我们在原有接口上新增一个方法:
public interface Sourceable {
public void method();
public void method1();
}
Source 类也需要多实现method1()方法:
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
@Override
public void method1() {
System.out.println("the original method1!");
}
}
关键来了,我们请来了动态代理的核心接口 InvocationHandler,
InvocationHandler 接口只需要实现invoke方法,三个参数依次为 代理对象(基本没什么用),代理对象调用的方法,调用的方法中的参数。通过
method.invoke方法,我们传入需要代理的对象(被代理对象作为DynamicProxy 的成员对象,通过构造器传入),和这个方法的参数,便可以调用被代理对象的原方法。然后其它跟静态代理没什么区别。
还有一点,method.getName()可以知道被代理对象调用了什么方法,根据不同方法可以自由编写增强现有代码的功能。
/**
* 动态代理,不用自己实现 被代理类
* Created by panqian on 2017/7/1.
*/
public class DynamicProxy implements InvocationHandler {
Object object;
DynamicProxy(Object object) {
super();
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("method1".equals(method.getName())) {
System.out.println("before dynamicProxy!");
method.invoke(object, args);
System.out.println("before dynamicProxy!");
} else if ("method".equals(method.getName())) {
System.out.println("before dynamicProxy1!");
method.invoke(object, args);
System.out.println("before dynamicProxy1!");
}
return null;
}
}
最后编写测试类
Proxy.newProxyInstance方法传入 被代理对象的classloader,接口和被代理对象本身。它会在代码运行时 自动创建代理对象(免去了自己写代理类的问题),然后通过返回的代理对象调用代理方法。
public static void main(String[] args) {
Sourceable source = new Source();
DynamicProxy dynamicProxy = new DynamicProxy(source);
Sourceable sourceable = (Sourceable) Proxy.newProxyInstance(Source.class.getClassLoader(), Source.class.getInterfaces(), dynamicProxy);
sourceable.method();
System.out.println("=========");
sourceable.method1();
}
动态代理 相比较 静态代理 相同点在于都是面向接口编程,都不破坏原有代码而增强功能,不同点在于 动态代理不需要编写大量的代理类,也就免去了很多因为自己写代理类而带来的问题。
在spring大名鼎鼎的aop特性中,Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,默认的策略是如果目标类是接口,则使用JDKProxy,JDKProxy便是我们所说的动态代理,否则使用Cglib来生成代理。所以说代理模式不是空中楼阁,对于减少代码重复量,减少代码冗余有很多实际的用处。