代理模式是一种结构型设计模式。结构型模式次要总结了一些类或对象组合在一起的经典构造,这些经典的构造能够解决特定利用场景的问题。结构型模式包含:代理模式、桥接模式、装璜器模式、适配器模式、门面模式、组合模式、享元模式。

代理模式的利用场景

  • 业务零碎的非功能性需要开发。比方:监控、统计、鉴权、限流、事务、幂等、日志。咱们将这些附加性能与业务性能解耦,放到代理类中对立解决,让程序员只须要关注业务方面的开发。
  • RPC、缓存中利用。RPC 框架也能够看作一种代理模式;假如咱们要开发一个接口申请的缓存性能,对于某些接口申请,如果入参雷同,在设定的过期工夫内,间接返回缓存后果,而不必从新进行逻辑解决。

代理模式分为动态代理和动静代理。动态代理的代理对象,在程序编译时曾经写好 Java 文件了,间接 new 一个代理对象即可。动静代理产生代理对象的机会是运行时动静生成,它没有 Java 源文件,间接生成字节码文件实例化代理对象。

动态代理的实现有两种:通过接口和通过继承。

动态代理 - 通过接口方式

类图

代码实现

UserService

public interface UserService {    public Boolean login(String username, String password);}

UserServiceImpl

public class UserServiceImpl implements UserService {    @Override    public Boolean login(String username, String password) {        return "admin".equals(username) && "admin".equals(password);    }}

UserServiceProxy

public class UserServiceProxy implements UserService {    private final UserService userService;    public UserServiceProxy(UserService userService) {        this.userService = userService;    }    @Override    public Boolean login(String username, String password) {        long t1 = System.nanoTime();        System.out.println("start login");        Boolean result = userService.login(username, password);        System.out.println("end login");        long t2 = System.nanoTime();        System.out.println("time: " + (t2 - t1) + "ns");        return result;    }}

Main

public class Main {    public static void main(String[] args) {        UserService userService = new UserServiceProxy(new UserServiceImpl());        Boolean result = userService.login("admin", "admin");        System.out.println("result: " + result);    }}

动态代理 - 通过继承形式

类图

代码实现

UserService

public interface UserService {    public Boolean login(String username, String password);}

UserServiceImpl

public class UserServiceImpl implements UserService {    @Override    public Boolean login(String username, String password) {        return "admin".equals(username) && "admin".equals(password);    }}

UserServiceProxy

public class UserServiceProxy extends UserServiceImpl {    @Override    public Boolean login(String username, String password) {        long t1 = System.nanoTime();        System.out.println("start login");        Boolean result = super.login(username, password);        System.out.println("end login");        long t2 = System.nanoTime();        System.out.println("time: " + (t2 - t1) + "ns");        return result;    }}

Main

public class Main {    public static void main(String[] args) {        UserService userService = new UserServiceProxy();        Boolean result = userService.login("admin", "admin");        System.out.println("result: " + result);    }}

动静代理

下面的代码实现有两个问题:

  1. 咱们须要在代理类中,将原始类中的所有的办法,都从新实现一遍,并且为每个办法都附加类似的代码逻辑。
  2. 如果要增加的附加性能的类有不止一个,咱们须要针对每个类都创立一个代理类。

这时咱们就须要用到动静代理(Dynamic Proxy),就是咱们不当时为每个原始类编写代理类,而是在运行的时候,动静地创立原始类对应的代理类,而后在零碎中用代理类替换掉原始类。

如何实现动静代理呢?

Java 语言自身就曾经提供了动静代理的语法(实际上,动静代理底层依赖的就是 Java 的反射语法)。

类图

UserService

public interface UserService {    public Boolean login(String username, String password);}

UserServiceImpl

public class UserServiceImpl implements UserService {    @Override    public Boolean login(String username, String password) {        return "admin".equals(username) && "admin".equals(password);    }}

DynamicProxyHandler

public class DynamicProxyHandler implements InvocationHandler {    private Object target;    public DynamicProxyHandler(Object target) {        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        long t1 = System.nanoTime();        System.out.println("start " + target.getClass().getName() + ":" + method.getName());        Object result = method.invoke(target, args);        System.out.println("end " + target.getClass().getName() + ":" + method.getName());        long t2 = System.nanoTime();        System.out.println("time: " + (t2 - t1) + "ns");        return result;    }}

DynamicProxy

public class DynamicProxy {    public Object createProxy(Object target) {        ClassLoader classLoader = target.getClass().getClassLoader();        Class<?>[] interfaces = target.getClass().getInterfaces();        DynamicProxyHandler handler = new DynamicProxyHandler(target);        return Proxy.newProxyInstance(classLoader, interfaces, handler);    }}

Main

public class Main {    public static void main(String[] args) {        DynamicProxy proxy = new DynamicProxy();        UserService userService = (UserService) proxy.createProxy(new UserServiceImpl());        Boolean result = userService.login("admin", "admin");        System.out.println("result: " + result);    }}

至此,咱们曾经实现了基于JDK的动静代理,JDK动静代理要求要代理的类必须实现接口,如果类没有实现接口,那么你能够尝试 CGLIB,它不是JDK自带的,而是第三方类库,感兴趣能够具体理解。