设计模式学习之代理模式

什么是代理模式

代理模式(Proxy Pattern) :给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。

代理模式包含如下角色:
Subject: 抽象主题角色
Proxy: 代理主题角色
RealSubject: 真实主题角色


image.png

MyBatis中实现的代理模式

代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写Mapper.java接口,不需要实现,由Mybatis后台帮我们完成具体SQL的执行。
这里有两个步骤,第一个是提前创建一个Proxy,第二个是使用的时候会自动请求Proxy,然后由Proxy来执行具体事务;
当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理:

public class MapperProxyFactory {

    private final Class mapperInterface;
    private final Map methodCache = new ConcurrentHashMap();

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

    public Class getMapperInterface() {
        return mapperInterface;
    }

    public Map getMethodCache() {
        return methodCache;
    }

    @SuppressWarnings("unchecked")
    protected T newInstance(MapperProxy mapperProxy) {
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface },
                mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
    }

}

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

而查看MapperProxy的代码,可以看到如下内容:

public class MapperProxy 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);
    }

非常典型的,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。

通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口的时候,就会转发给MapperProxy.invoke方法,而该方法则会调用后续的sqlSession.cud>executor.execute>prepareStatement等一系列方法,完成SQL的执行和返回。

JDK实现的动态代理

java 运行环境JDK,jdk中也给我们提供了动态代理,jdk中的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler它是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy利用InvocationHandler动态创建一个符合某一接口的实例,用来生成目标类的代理对象。
对于异常处理,日志功能,权限的检查,事务等都是贯穿到各个模块之中,因此进行AOP。代理技术有面向接口和生成子类,面向接口的实现如下:

public Object getProxy(final Object targetObj) { 
    Obejct obj = Proxy.newProxyInstance( 
    targetObj.getClass().getClassLoader(),       //被代理类的类加载器
    targetObj.getClass().getInterfaces(),          //被代理类接口的字节码
    new InvocationHandler() {                  //类似于一个回调函数 代理功能就在里面实现
        @Override 
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
            try{ 
                  beforeAdvice();   //前置通知
                  method.invoke(targetObj, args);  //拦截的点
                  afterAdvice();    //后置通知
           }catch (Exception e) { 
                  exceptionAdvice();   //异常通知
           }finally{ 
                        finalAdvice();   //必须执行通知
                    } 
                   return obj; 
         } 
     }); 
 }

Spring中的动态代理

Spring 的 AOP 代理是完全由 Spring 的 IoC 容器负责生成、管理的,其依赖关系也由 IoC 容器负责管理。因此,AOP 代理可以直接使用容器中的其他 Bean 实例作为目标,这种关系可由 IoC 容器的依赖注入提供。
Spring是默认采取的动态代理机制实现AOP的,当然,在当动态代理不可用时候(代理类无接口)它就会使用CGlib的机制了。
Spring提供了两种方式来生成代理对象: 一个是JDK的Proxy,另一个就是Cglib了,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。Spring会自动选择使用那种方式,我们不用担心,此处做个了解。

CGLib实现的动态代理

CGLib动态代理的全称为 Code Generation Library,它是一个强大的高性能的,高质量的代码生成类库,就可以在运行期扩展Java类与实现Java接口,CGLib它封装了asm,可以再运行期动态生成新的class。CGLIB和JDK动态代理相比较的话:JDK创建的代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则就可以通过CGLib来创建动态代理了。
小结:JDK 对接口创建代理实例,CGLIB 可以对类创建代理实例。
参考资料:https://mp.weixin.qq.com/s/-nMUwRPp_XYg-YZF9P0bTg

你可能感兴趣的:(设计模式学习之代理模式)