文档章节

动态代理

wuyiyi
 wuyiyi
发布于 2018/10/16 15:07
字数 686
阅读 6
收藏 0

具体场景

为了使代理类与被代理类对第三方有相同的函数,代理类与被代理类一般实现一个公共的interface,定义如下

public interface Subject {

    void rent();

    void hello(String s);
}

被代理类定义如下

public class RealSubject implements Subject {
    @Override
    public void rent() {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String s) {
        System.out.println("hello :"+s);
    }
}

代理需求:在接口subject的每个方法前后分别输出before invoke和after invoke

静态代理解决方案

public class StaticSubjectProxy implements Subject {
    private RealSubject realSubject;
    @Override
    public void rent() {
        System.out.println("before invoke");
        realSubject.rent();
        System.out.println("after invoke");
    }

    @Override
    public void hello(String s) {
        System.out.println("before invoke");
        realSubject.hello(s);
        System.out.println("after invoke");
    }
}

但是这种处理存在弊端,如果subject接口的方法不止两个,还有很多其他的方法,那么静态代理的实现就不太适合

动态代理解决方案

public class SubjectInvocationHandler implements InvocationHandler {
    private Subject subject; //被代理类

    public SubjectInvocationHandler(Subject interfaceClass) {
        this.subject = interfaceClass;
    }

    /**
     *
     * @param proxy  动态代理类的引用,通常情况下不需要它。但可以使用getClass()方法,
     *               得到proxy的Class类从而取得实例的类信息,如方法列表,annotation等。
     * @param method 方法对象的引用,代表被动态代理类调用的方法。从中可得到方法名,参数类型,返回类型等等
     * @param args args对象数组,代表被调用方法的参数。注意基本类型(int,long)会被装箱成对象类型(Interger, Long)
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (!isDefaultMethod(method)){
            System.out.println("before invoke");
            System.out.println("Method: " + method);
            //执行被代理类方法
            method.invoke(subject,args);
            System.out.println("after invoke");
        }
        return null;
    }

    private boolean isDefaultMethod(Method method) {
        return (method.getModifiers()
                & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
                && method.getDeclaringClass().isInterface();
    }

生成代理类方法

public class SubjectProxy {
    private Subject subject;

    public SubjectProxy(Subject subject) {
        this.subject = subject;
    }

    public Subject create(){
        final Class<?>[] interfaces = new Class[]{Subject.class};
        final SubjectInvocationHandler handler = new SubjectInvocationHandler(subject);
        return (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),interfaces,handler);
    }
}
@Test
    public void test(){
        Subject subject = new RealSubject();
        SubjectProxy proxy = new SubjectProxy(subject);

        Subject proxySubject = proxy.create();
        proxySubject.rent();
        proxySubject.hello("world");
    }

上述动态代理无论subject包含多少方法,动态代理只需实现一次。 mybatis获取mapper,使用到动态代理

UserMapper mapper = sqlSession.getMapper(UserMapper.class);
public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
    }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
  protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

参考:

© 著作权归作者所有

共有 人打赏支持
wuyiyi
粉丝 2
博文 51
码字总数 23208
作品 0
浦东
程序员
私信 提问
JDK动态代理和CGLiB动态代理

JDK动态代理 JDK动态代理要求类必须实现某一接口,代理类是同一接口的实现类。 JDK动态代理主要涉及两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,可以通过实现该接口定义...

kakayang2011
2016/03/13
80
0
java动态代理

java动态代理用到了java.lang.reflect包的Proxy类和InvocationHandler接口。它们在动态代理中起到的作用如下: Proxy类:提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所...

SeaRise
2017/11/20
0
0
Spring中JDK动态代理和Cglib代理的区别

Spring的AOP基于代理模式,并且它即使用到了JDK动态代理也使用了Cglib代理。 如下代码是springAOP中默认的代理实现类DefaultAopProxyFactory,其中创建代理的方法createAopProxy,在这个方法...

王子城
2018/08/01
0
0
静态代理与静态代理

1 代理模式及概念 代理模式是给某个对象提供一个代理对象,并由代理对象控制对原始对象的引用。如下图: 代理类和委托类有共同的父类,这样在任何使用原始对象(委托对象)的地方都可用代理对...

林中漫步
2016/05/15
80
0
JDK动态代理与Cglib动态代理(转载)

spring容器通过动态代理再结合java反射思想可以使得方法调用更加简洁 一、动态代理概述: 与静态代理对照(关于静态代理的介绍 可以阅读上一篇:JAVA设计模式之 代理模式【Proxy Pattern】(...

思悟修
2015/08/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

node调用dll

先安装python2.7 安装node-gyp cnpm install node-gyp -g 新建一个Electron-vue项目(案例用Electron-vue) vue init simulatedgreg/electron-vue my-project 安装electron-rebuild cnpm ins......

Chason-洪
今天
3
0
eclipse中项目svn转gitLab全过程

在工作中,我们可能会遇到项目从svn迁移到gitLab;此过程我们需要变化版本管理工具,上传代码。本篇博客记录了使用spring tool suit(sts/eclipse)进行项目迁移的全过程。 步骤: (1)端口之...

em_aaron
今天
3
0
scala学习(一)

学习Spark之前需要学习Scala。 参考学习的书籍:快学Scala

柠檬果过
今天
1
0
通俗易懂解释网络工程中的技术,如STP,HSRP等

导读 在面试时,比如被问到HSRP的主备切换时间时多久,STP几个状态的停留时间,自己知道有这些东西,但在工作中不会经常用到,就老是记不住,觉得可能还是自己基础不够牢固,知识掌握不够全面...

问题终结者
昨天
4
0
看了一下Maven的内容

了解了Maven其实是一个跨IDE的标准构建工具,能推广的原因估计是借了仓库的便利。 另一个作用是可以通过Maven的功能在社区版的IDEA去创建Web项目,下次实践看看

max佩恩
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部