前言

代理模式是一种常见的设计模式,它使用代理对象完成用户请求,屏蔽了用户对真实对象的访问。

在软件设计中,使用代理模式的意图也很多。比如因为安全原因,屏蔽客户端直接访问真实对象。或者在远程调用中,使用代理类来屏蔽远程方法调用的技术细节。或为了提升系统性能,将真实对象封装,达到延迟加载的目的。比如hibernate就使用了cglib来实现延迟加载。
这里使用代理模式实现延迟加载,提升系统性能和速度。

不使用代理模式的直接调用

这里定义一个IUserService接口类,提供一个request方法;UserService实现IUserService接口。Main为测试类。

1
2
3
4
5
6
/**
 * Created by j.tommy on 2017/9/10.
 */
public interface IUserService {
    String request();
}

1
2
3
4
5
6
7
8
9
/**
 * Created by j.tommy on 2017/9/10.
 */
public class UserService implements IUserService {
    @Override
    public String request() {
        return "hello";
    }
}
1
2
3
4
5
6
7
8
9
10
/**
 * Created by j.tommy on 2017/9/10.
 */
public class Main {
    public static void main(String[] args) {
        IUserService ius = new UserService();
        String result = ius.request();
        System.out.println("result:" + result);
    }
}

静态代理

下面定义一个UserServiceProxy来代理UserService,对外提供服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * Created by j.tommy on 2017/9/10.
 */
public class UserServiceProxy implements IUserService {
    private UserService us = null;
    @Override
    public String request() {
        // 延迟加载us的实例,在实际使用时初始化
        if (null == us) {
            us = new UserService();
            System.out.println("Created UserService.");
        }
        return us.request();
    }
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Created by j.tommy on 2017/9/10.
 */
public class Main {
    public static void main(String[] args) {
        // 通过代理类调用
        IUserService ius = new UserServiceProxy();
        System.out.println("Created proxy.");
        String result = ius.request();
        System.out.println("result:" + result);
    }
}

输出:

可以看到,在实际调用request()方法时才初始化UserService.
静态代理很大的一个问题:所有的代理类必须实现接口,现在是一个UserService,如果还有其他的XXService,每个XXServiceProxy都需要实现XXService接口,这是很麻烦的。

JDK动态代理

上面看到了使用静态代理的一个大问题,我们可以通过JDK动态代理来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * jdk动态代理。
 * Created by j.tommy on 2017/9/10.
 */
public class JdkDynamicProxy implements InvocationHandler {
    // 真实对象
    private Object target;
    public JdkDynamicProxy(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 调用真实对象的方法
        Object result = method.invoke(target,args);
        return result;
    }
    /**
     * 获取目标对象的代理对象
     * @return
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
    }
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * Created by j.tommy on 2017/9/10.
 */
public class Main {
    public static void main(String[] args) {
        // JDK动态代理
        // 真实对象
        IUserService ius = new UserService();
        // 代理对象
        IUserService us = (IUserService) new JdkDynamicProxy(ius).getProxy();
        String result = us.request();
        System.out.println("result:" + result);
    }
}

如上代码,可以代理任何接口。但它也有个问题,要代理的类必须实现接口。。如果不想实现接口,还要能够代理,可以使用cglib.

cglib动态代理

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * Created by j.tommy on 2017/9/10.
 */
public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 通过代理类调用父类中的方法
        return methodProxy.invokeSuper(o,args);
    }
    public Object getProxy(Class clazz) {
        // 设置需要创建之类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);

        // 通过字节码结束创建之类实例
        return enhancer.create();
    }
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
/**
 * Created by j.tommy on 2017/9/10.
 */
public class Main {
    public static void main(String[] args) {
        CglibProxy cp = new CglibProxy();
        UserService ius = (UserService) cp.getProxy(UserService.class);
        String result = ius.request();
        System.out.println("result:" + result);
    }
}

更多代理模式参考:http://blog.csdn.net/yakoo5/article/details/9099133/
http://www.importnew.com/22015.html