今でもあなたは私の光丶

MyBatis设计模式

Builder构建者模式

概念

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数能包含的范围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用更加复杂的对象的构建,甚至只会构建产品的一个部分,直白来说,就是使用多个简单的对象一步一步构建成一个复杂的对象

例子

构建步骤

  • 将需要构建的目标类分成多个部件(电脑可以分为主机、显示器、键盘、音响等部件)
  • 创建构建类
  • 依次创建部件
  • 将部件组装成目标对象

MyBatis中的体现

工厂模式

概念

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,属于创建类模式
在简单工厂模式中,可以根据参数的不同返回不同类的实例,简单工厂模式专门定义了一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类

例子:生产电脑

创建抽象产品类

Computer.java
public abstract class Computer {
 /**
 * 产品的抽象方法,由具体产品类去实现
 */
 public abstract void start();
}

创建具体产品类

public class HpComputer extends Computer {
    @Override
    public void start() {
        System.out.println("惠普电脑启动");
    }
}
public class LenovoComputer extends Computer {
    @Override
    public void start() {
        System.out.println("联想电脑启动");
    }
}

创建工厂类

public class ComputerFactory {

    public static Computer createComputer(String type){
        Computer computer =null;
        switch (type){
            case "lenovo":
                computer = new LenovoComputer();
            case "hp":
                computer = new HpComputer();
        }

        return  computer;
    }

}

代理模式

概念

代理模式(Proxy Pattern):给某一个对象提供一个代理,并由代理对象控制对原对象的的引用,代理模式的英文叫做Proxy,是一种对象结构类模式,代理模式分为静态代理和动态代理

例子

新建一个接口

/**
*抽象类人
*/
public interface Person {
 void doSomething();
}

实现类,使其实现抽象方法

/**
 *创建一个名为Bob的人的实现类
*/
public class Bob implements Person {
 public void doSomething() {
 System.out.println("Bob doing something!");
 }
}

创建JDK动态代理类,使其实现InvocationHandler接口

public class JDKDynamicProxy implements InvocationHandler {

    // 声明被代理的对象
    private Person person;

    //构造函数
    public JDKDynamicProxy(Person person) {
        this.person = person;
    }

    //获取代理对象
    public Object getTarget(){
        Object proxyInstance = Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);

        return proxyInstance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("对原方法进行了前置增强");
        //原方法执行
        Object invoke = method.invoke(person, args);
        System.out.println("对原方法进行了后置增强");
        return invoke;
    }
}

MyBatis体现

代理模式可以认为是MyBatis的核心使用模式,正式由于这个模式,我们只需要编写Mapper.java接口,不需要实现,由MyBatis后台帮我们完成具体SQL的执行。
当我们使用Configuration的getMapper方法时,会调用mapperRegisry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理。

/**
 * Mapper Proxy 工厂类
 *
 * @author Lasse Voss
 */
public class MapperProxyFactory<T> {

    /**
     * Mapper 接口
     */
    private final Class<T> mapperInterface;
    /**
     * 方法与 MapperMethod 的映射
     */
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return mapperInterface;
    }

    public Map<Method, MapperMethod> getMethodCache() {
        return methodCache;
    }

    @SuppressWarnings("unchecked")
    protected T newInstance(MapperProxy<T> mapperProxy) {

        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
    }

   //MapperProxyFactory类中的newInstance方法
    public T newInstance(SqlSession sqlSession) {
        // 创建了JDK动态代理的invocationHandler接口的实现类mapperProxy
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        // 调用了重载方法
        return newInstance(mapperProxy);
    }

}

在这里,先通过T newInstance(SqlSession sqlSession)方法会得到一个MapperProxy对象,然后调用T newInstance(MapperProxy mapperProxy)生成代理对象然后返回。

public class MapperProxy<T> implements InvocationHandler, Serializable {
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
 try {
 if (Object.class.equals(method.getDeclaringClass())) {
 return method.invoke(this, args);
 } else if (isDefaultMethod(method)) {
 return invokeDefaultMethod(proxy, method, args);
 }
 } catch (Throwable t) {
 throw ExceptionUtil.unwrapThrowable(t);
 }
 final MapperMethod mapperMethod = cachedMapperMethod(method);
 return mapperMethod.execute(sqlSession, args);

非常典型的,gaiMapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法,通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口时,就会转发给MapperProxy.invoke方法,而该方法则会调用后续的sqlSession.curd>executor.execute>prepareStatement等一系列方法,完成SQL的执行和返回