代理模式


代理模式

定义

在不改变原始类代码情况下,通过引入代理类来给原始类附加功能

角色

  • Subject:定义 RealSubject 和 Proxy 角色都应该实现的接口
  • Real Subject:原始类,真正完成业务服务功能
  • Proxy:代理类,将自身的请求用Real Subject对应的功能来实现,代理类对象并不真正的去实现其业务功能

应用场景

  • 业务系统的非功能性需求开发,比如监控、统计、鉴权、限流、事务、幂等、日志……
  • RPC
  • 缓存

静态代理

缺点

  • 必须实现接口
  • 每个原始类都要创建一个对应的代理类,类数量爆炸。且每个代理类中的代码有点像模板式代码,增加了维护成本和开发成本
  • 接口一旦增加新方法,原始类和代理类都得修改,不符合开闭原则

动态代理

原理

动态代理是在运行时动态生成类字节码,并加载到 JVM中,生成Class对象

优点

  • 动态代理更加灵活,不需要必须实现接口。既可代理接口也可直接代理原始类
  • 不用每个原始类都创建一个对应的代理类,减少了开发和维护成本
  • 接口新增方法,代理类不用修改,符合开闭原则

字节码生成框架

  • ASM
  • CGLIB
  • Javassist

JDK动态代理

角色

  • Subject
  • Real Subject
  • InvocationHandler:创建一个处理类并实现 InvocationHandler 接口,将原始类注入处理类,重写其 invoke 方法,在 invoke 方法中利用反射机制调用原始类的方法,并自定义一些处理逻辑
  • Proxy

缺点

只能代理接口的实现类,且只能代理接口中的方法,原始类的其它方法不能代理

CGLIB动态代理

角色

  • Subject
  • Real Subject
  • MethodInterceptor:创建一个方法拦截器实现MethodInterceptor接口,并重写 intercept 方法,intercept用于拦截并增强原始类的方法
  • Proxy

栗子

场景

一个UserMapper接口是提供对用户数据的增删查改功能,现在要统计增删查改的执行次数,典型的代理模式使用场景

共用代码

package io.zjh.entity;

public class User {
    private String id;
    private String name;
    private int age;

    public User(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package io.zjh.metric;

import java.util.concurrent.atomic.AtomicInteger;

public class CrudMetric {

    private final static AtomicInteger insertCount = new AtomicInteger(0);
    private final static AtomicInteger updateCount = new AtomicInteger(0);
    private final static AtomicInteger deleteCount = new AtomicInteger(0);
    private final static AtomicInteger selectCount = new AtomicInteger(0);

    public static void increaseInsert() {
        insertCount.incrementAndGet();
    }

    public static void increaseUpdate() {
        updateCount.incrementAndGet();
    }

    public static void increaseDelete() {
        deleteCount.incrementAndGet();
    }

    public static void increaseSelect() {
        selectCount.incrementAndGet();
    }

    public static void metric() {
        System.out.println("----------------metric-------------------");
        System.out.println("insert count : " + insertCount.get());
        System.out.println("update count : " + updateCount.get());
        System.out.println("delete count : " + deleteCount.get());
        System.out.println("select count : " + selectCount.get());
        System.out.println("----------------metric-------------------");
    }

    public static void clear() {
        insertCount.set(0);
        updateCount.set(0);
        deleteCount.set(0);
        selectCount.set(0);
    }

}

静态代理方式实现

Subject

package io.zjh;

import io.zjh.entity.User;

import java.util.List;

public interface IUserMapper {

    void insert(User user);

    void update(User user);

    void deleteById(String id);

    User selectById(String id);

    List<User> selectAll();

}

Real Subject

package io.zjh;

import io.zjh.entity.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class UserMapper implements IUserMapper {

    private final Map<String, User> maps = new ConcurrentHashMap<>();

    @Override
    public void insert(User user) {
        maps.put(user.getId(), user);
        System.out.println("insert : " + user);
    }

    @Override
    public void update(User user) {
        maps.put(user.getId(), user);
        System.out.println("update : " + user);
    }

    @Override
    public void deleteById(String id) {
        maps.remove(id);
        System.out.println("delete id : " + id);
    }

    @Override
    public User selectById(String id) {
        System.out.println("select id : " + id);
        return maps.get(id);
    }

    @Override
    public List<User> selectAll() {
        System.out.println("select all");
        return new ArrayList<>(maps.values());
    }
}

Proxy

package io.zjh.staticproxy;

import io.zjh.IUserMapper;
import io.zjh.UserMapper;
import io.zjh.entity.User;
import io.zjh.metric.CrudMetric;

import java.util.List;

public class UserMapperProxy implements IUserMapper {

    private final UserMapper userMapper;

    public UserMapperProxy(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public void insert(User user) {
        CrudMetric.increaseInsert();
        userMapper.insert(user);
    }

    @Override
    public void update(User user) {
        CrudMetric.increaseUpdate();
        userMapper.update(user);
    }

    @Override
    public void deleteById(String id) {
        CrudMetric.increaseDelete();
        userMapper.deleteById(id);
    }

    @Override
    public User selectById(String id) {
        CrudMetric.increaseSelect();
        return userMapper.selectById(id);
    }

    @Override
    public List<User> selectAll() {
        CrudMetric.increaseSelect();
        return userMapper.selectAll();
    }

}

test

package io.zjh.staticproxy;

import io.zjh.UserMapper;
import io.zjh.entity.User;
import io.zjh.metric.CrudMetric;

public class Main {
    public static void main(String[] args) {
        UserMapper userMapper = new UserMapper();
        UserMapperProxy userMapperProxy = new UserMapperProxy(userMapper);
        User user = new User("1", "sky", 18);
        userMapperProxy.insert(user);
        user.setName("人皇sky");
        userMapperProxy.update(user);
        userMapperProxy.selectById(user.getId());
        userMapperProxy.selectAll();
        userMapperProxy.deleteById(user.getId());
        CrudMetric.metric();
    }
}

执行结果

insert : User{name='sky', age=18}
update : User{name='人皇sky', age=18}
select id : 1
select all
delete id : 1
----------------metric-------------------
insert count : 1
update count : 1
delete count : 1
select count : 2
----------------metric-------------------

JDK动态代理实现方式

InvocationHandler

package io.zjh.dynamicproxy.jdk;

import io.zjh.metric.CrudMetric;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MapperInvocationHandler<T> implements InvocationHandler {
    private final T target;

    public MapperInvocationHandler(T target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        if (name.startsWith("insert")) {
            CrudMetric.increaseInsert();
        } else if (name.startsWith("update")) {
            CrudMetric.increaseUpdate();
        } else if (name.startsWith("delete")) {
            CrudMetric.increaseDelete();
        } else if (name.startsWith("select")) {
            CrudMetric.increaseSelect();
        }
        return method.invoke(target, args);
    }

}

创建工厂

package io.zjh.dynamicproxy.jdk;

import java.lang.reflect.Proxy;

@SuppressWarnings("all")
public class JdkMapperProxyFactory {

    public static <T> T newInstance(T target) {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new MapperInvocationHandler(target));
    }

}

test

package io.zjh.dynamicproxy.jdk;

import io.zjh.IUserMapper;
import io.zjh.entity.User;
import io.zjh.metric.CrudMetric;
import io.zjh.UserMapper;

public class JDKMain {
    public static void main(String[] args) {
        IUserMapper userMapper = JdkMapperProxyFactory.newInstance(new UserMapper());
        User user = new User("1", "sky", 18);
        userMapper.insert(user);
        user.setName("人皇sky");
        userMapper.update(user);
        userMapper.selectById(user.getId());
        userMapper.selectAll();
        userMapper.deleteById(user.getId());
        CrudMetric.metric();
    }
}

执行结果

insert : User{name='sky', age=18}
update : User{name='人皇sky', age=18}
select id : 1
select all
delete id : 1
----------------metric-------------------
insert count : 1
update count : 1
delete count : 1
select count : 2
----------------metric-------------------

CGLIB动态代理实现方式

MethodInterceptor

package io.zjh.dynamicproxy.cglib;

import io.zjh.metric.CrudMetric;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MapperInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String name = method.getName();
        if (name.startsWith("insert")) {
            CrudMetric.increaseInsert();
        } else if (name.startsWith("update")) {
            CrudMetric.increaseUpdate();
        } else if (name.startsWith("delete")) {
            CrudMetric.increaseDelete();
        } else if (name.startsWith("select")) {
            CrudMetric.increaseSelect();
        }
        return methodProxy.invokeSuper(o, objects);
    }

}

创建工厂

package io.zjh.dynamicproxy.cglib;

import net.sf.cglib.proxy.Enhancer;

@SuppressWarnings("all")
public class CGLIBMapperProxyFactory {

    public static <T> T newInstance(Class<T> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(clazz.getClassLoader());
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new MapperInterceptor());
        return (T) enhancer.create();
    }

}

test

package io.zjh.dynamicproxy.cglib;

import io.zjh.InnerUserMapper;
import io.zjh.UserMapper;
import io.zjh.entity.User;
import io.zjh.metric.CrudMetric;

public class CGLIBMain {
    public static void main(String[] args) {
        InnerUserMapper innerUserMapper = CGLIBMapperProxyFactory.newInstance(InnerUserMapper.class);
        User user = new User("1", "sky", 18);
        innerUserMapper.insert(user);
        user.setName("人皇sky");
        innerUserMapper.update(user);
        innerUserMapper.selectById(user.getId());
        innerUserMapper.selectAll();
        innerUserMapper.deleteById(user.getId());
        CrudMetric.metric();

        CrudMetric.clear();
        System.out.println("*****************************************");

        UserMapper userMapper = CGLIBMapperProxyFactory.newInstance(UserMapper.class);
        userMapper.insert(user);
        user.setName("sky");
        userMapper.update(user);
        userMapper.selectById(user.getId());
        userMapper.selectAll();
        userMapper.deleteById(user.getId());
        CrudMetric.metric();
    }
}

执行结果

insert : User{name='sky', age=18}
update : User{name='人皇sky', age=18}
select id : 1
select all
delete id : 1
----------------metric-------------------
insert count : 1
update count : 1
delete count : 1
select count : 2
----------------metric-------------------
*****************************************
insert : User{name='人皇sky', age=18}
update : User{name='sky', age=18}
select id : 1
select all
delete id : 1
----------------metric-------------------
insert count : 1
update count : 1
delete count : 1
select count : 2
----------------metric-------------------

小结


文章作者: maybe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 maybe !