文档章节

动态代理

wuyiyi
 wuyiyi
发布于 10/16 15:07
字数 686
阅读 5
收藏 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
粉丝 1
博文 40
码字总数 16552
作品 0
浦东
程序员
私信 提问
JDK动态代理和CGLiB动态代理

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

kakayang2011
2016/03/13
80
0
代理模式

代理模式一般分为两种,即静态代理和动态代理,静态代理限制比较严格,代理类和委托类必须实现相同的接口;而动态代理则更加灵活,除了jdk的动态代理,其他的代理方式,如cglib和javassist则...

high_m
2017/11/15
0
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,在这个方法...

王子城
08/01
0
0
动态代理jdk和cglib的区别

动态代理的描述在前两篇文章已经做了一部分描述动态代理的详细解读和动态代理的简单描述,JDK的动态代理只能针对实现了接口的类生成代理。而cglib的动态代理是针对类实现代理,这两种代理我们...

激情的狼王丶21
2017/12/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot中filter的用法

一、在spring的应用中我们存在两种过滤的用法,一种是拦截器、另外一种当然是过滤器。我们这里介绍过滤器在springboot的用法,在springmvc中的用法基本上一样,只是配置上面有点区别。 二、f...

xiaomin0322
29分钟前
5
0
java项目修改了更换了jdk版本报错进行修改

java项目原来用的是1.8版本的,改成1.7版本后,项目会报错,要进行的修改是 然后是clean一下项目,然后是选中项目的buildpath,然后是configurebuildpath,然后是看jdk是否进行修改...

myAll_myAll
40分钟前
4
0
Gartner 2018 数据库系列报告发布 巨杉数据库连续两年入选

近期,Gartner陆续发布了2018年的数据库系列报告,包括《数据库魔力象限》《数据库核心能力》以及《数据库推荐报告》。其中,SequoiaDB巨杉数据库作为业界领先的金融级分布式交易型数据库产品...

巨杉数据库
43分钟前
2
0
Navicat闲置一段时间卡死问题的解决

先关闭连接,再右键点击所需要设置的链接,进入编辑连接,进入高级项,勾选保持连续间隔(秒):时间设置短一些,比如30秒,完成!!

joyStalker
43分钟前
3
0
理解Java中的弱引用(Weak Reference)

1. What——什么是弱引用? Java中的弱引用具体指的是java.lang.ref.WeakReference<T>类,我们首先来看一下官方文档对它做的说明: 弱引用对象的存在不会阻止它所指向的对象变被垃圾回收器回...

绝地逢生
44分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部