精华内容
下载资源
问答
  • 1.什么会有这样的想法去生成接口实现类 在学习mybatis的过程中,其存在一种机制,接口式编程。利用接口对我们sql的查询进行约束 我们只是写了接口,mybatis能给我们返回一个该接口的实例,这个实例是怎么来的...

    1.为什么会有这样的想法去生成接口的实现类

    在学习mybatis的过程中,其存在一种机制,接口式编程。利用接口对我们sql的查询进行约束

    我们只是写了接口,mybatis能给我们返回一个该接口的实例,这个实例是怎么来的?

    思考:由于我们没有写该接口的实现类,mybatis返回的对象肯定不是简单的动态代理

    但是我们打印其返回对象的class发现

    class com.sun.proxy.$Proxy0

    可以看出其就是jdk的动态代理对象。

    2.实现动态的为接口生成实现类

    我们利用jdk的动态代理,来对接口进行实现。

    传统的使用动态代理的方式,需要传入一个被代理类来进行动态代理

    我们这里由于没有接口实现类所以我们在写InvocationHandler的实现类的时候,不为其内部添加实现类。

    代码如下:

    要生成实现类的接口

    public interface Person {
    	public void showName();
    	public void saying();
    }
    

    InvocationHandler的实现类,内部没有上面接口的实现类,也就是没有被代理类

    public class InvokeHandler implements InvocationHandler {
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		// object的公用方法直接调用当前invoke对象的。
                if (Object.class.equals(method.getDeclaringClass())) {
    			return method.invoke(this, args);
                // 针对接口的不同方法书写我们具体的实现
    		} else if ("showName".equals(method.getName())) {
    			System.out.println("张三");
    		} else if ("saying".equals(method.getName())) {
    			System.out.println("我叫张三");
    		}
    		return null;
    	}
    }

     测试:

    	public static void main(String[] args) {
    		Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class}, new InvokeHandler());
    		person.showName();
    		person.saying();
    		System.out.println(person);
    		System.out.println(person.getClass());
    	}
    张三
    我叫张三
    toString
    D.InvokeHandler@6bc7c054
    class com.sun.proxy.$Proxy0

    这样我们就动态的简单的生成了一个接口的实现类。其原理还是动态代理,只是抛弃掉了被代理类

    3.总结

    mybaties内部动态的生成接口的实现类,其基本原理就是是如上面的代码所展示

    可以去看其MapperProxy的源码:

    public class MapperProxy<T> implements InvocationHandler, Serializable {
      // 可以看出内部字段是没有被代理类的
      private static final long serialVersionUID = -6424540398559729838L;
      private final SqlSession sqlSession;
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache;
    
      public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
      }
    
      @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);
      }
    
      private MapperMethod cachedMapperMethod(Method method) {
        return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
      }
    
      private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
          throws Throwable {
        final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
            .getDeclaredConstructor(Class.class, int.class);
        if (!constructor.isAccessible()) {
          constructor.setAccessible(true);
        }
        final Class<?> declaringClass = method.getDeclaringClass();
        return constructor
            .newInstance(declaringClass,
                MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                    | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
            .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
      }
    
      /**
       * Backport of java.lang.reflect.Method#isDefault()
       */
      private boolean isDefaultMethod(Method method) {
        return (method.getModifiers()
            & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
            && method.getDeclaringClass().isInterface();
      }
    }

     

     

     

     

    展开全文
  • JDK代理代理的是接口,那么笔者想一想,既然代理的是接口,那如果没有实现类怎么办,能不能代理。答案是可以的,Mybatis就是这样的。 Mybatis使用JDK动态代理来实现Mapper接口,事先保存好Mapper接口,和接口声明...

    JDK代理,代理的是接口,那么笔者想一想,既然代理的是接口,那如果没有实现类怎么办,能不能代理。答案是可以的,Mybatis就是这样的。

    Mybatis使用JDK动态代理来实现Mapper接口,事先保存好Mapper接口,和接口声明的方法,返回值,参数类型,然后代理类的方法调用的时候使用MapperMethod这个事先放入方法缓存里的对象来真实调用功能。

    笔者极度简化了一下代码:

    被代理的接口:

    public interface Subject2 {
    
        String selectById();
    }
    

    这个接口可以看成是Mapper接口

    代理对象:

    public class SubjectProxy2<T> implements InvocationHandler {
    
        private Class<T> proxyInterface;
        //这里可以维护一个缓存,存这个接口的方法抽象的对象
    
        
    
        SubjectProxy2(Class<T> proxyInterface){
            this.proxyInterface = proxyInterface;
        }
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("selectById")){
                //String result = (String) method.invoke(proxyInterface,args);
                //这里可以得到方法抽象对象来调用真的的查询方法
                System.out.println("selectById调用成功");
            }
            return null;
        }
    
        public T getProxy(){
            return (T) Proxy.newProxyInstance(proxyInterface.getClassLoader(),new Class[]{proxyInterface},this);
        }
    }
    

    这个代理类使用了泛型,说明这个代理类可以代理所有的mapper接口。

    那么接下来测试一下:

    public class ProxyTest2 {
    
        public static void main(String[] args) {
            SubjectProxy2<Subject2> subjectProxy2 = new SubjectProxy2(Subject2.class);
            Subject2 subject2 = subjectProxy2.getProxy();
            subject2.selectById();
        }
    }

    结果不言而喻。肯定会有相应的输出

    没有看mybatis源码的时候,我以为动态代理一定要要有实现类才能代理,但是看了优秀的顶级大牛的源码之后,我才发现,原来还可以这样。

     

    展开全文
  • 但我们用过的Mybatis中Dao接口,或者Spring Data JPA接口,其实我们没有手动他们编写实现类,那什么仍然能正常调用呢?这里就涉及到了动态代理。下面我演示一下,如何利用JDK一个接口创建动态实现。 代码目录...

    我们大家都知道,一般情况下,如果一个接口没有实现类的话,我们直接调用该接口的方法会报错。但我们用过的Mybatis中Dao接口,或者Spring Data JPA接口,其实我们没有手动为他们编写实现类,那为什么仍然能正常调用呢?这里就涉及到了动态代理。下面我演示一下,如何利用JDK为一个接口创建动态实现。

    代码目录大致如下,在com.company.proxy包下有三个类文件

    一、SaleService 这个是一个接口声明,后面我们将为该接口创建一个动态实现。其源码如下:

    package com.company.proxy;
    
    /**
     *
     * @author LICHUANG
     */
    public interface SaleService {
    
        /**
         * 出售
         * @param goodsName 商品名称
         * @param price 价格
         * @return
         */
        String sale(String goodsName,Integer price);
    }

    二、SaleInvocation 该类实现了InvocationHandler接口,并重写其invoke方法。其源码如下:

    package com.company.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     *
     * @author LICHUANG
     */
    public class SaleInvocation implements InvocationHandler {
    
        private Class<?> clazz;
    
        public SaleInvocation(Class<?> o) {
            this.clazz = o;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //一般DEBUG时,我们查看变量时,会调用其toString()方法,由于该方法也会被代理,所以出现递归调用,
            //这里为了避免DEBUG时,重复调用方法,所以作特殊处理
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this,args);
            }
            System.out.println("调用前");
            //这里是为接口的方法构造实现逻辑,
            // 由于我们已经获取到了方法名称和参数值,所以可以根据实际需要去创建实现逻辑。
            Object result = "方法名称:" + method.getName() + ",参数值:" + Arrays.toString(args) + ",clazz:" + clazz;
            System.out.println("调用后result:" + result);
            return result;
        }
    }

    三、ProxyTest 这个类主要是包含main方法,用来测试的。其源码如下:

    package com.company.proxy;
    
    import java.lang.reflect.Proxy;
    
    /**
     * 
     *
     * @author LICHUANG
     */
    public class ProxyTest {
    
        public static void main(String[] args) {
            Class<?> clazz = SaleService.class;
            SaleInvocation invocation = new SaleInvocation(clazz);
            SaleService proxyObject = (SaleService) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[] {clazz},invocation);
            String result = proxyObject.sale("商品名称",5);
            System.out.println("得到返回结果:" + result);
        }
    }

    可以注意到,以上SaleService接口,我并没有手动编写任何实现类,但我仍然能正常调用其String sale(String goodsName,Integer price)方法。

    最后main方法运行结果如下:

    调用前
    调用后result:方法名称:sale,参数值:[商品名称, 5],clazz:interface com.company.proxy.SaleService
    得到返回结果:方法名称:sale,参数值:[商品名称, 5],clazz:interface com.company.proxy.SaleService
    
    Process finished with exit code 0

     

    展开全文
  • 我们知道MyBatis通过动态代理的方式,实现了只通过Mapper接口而无接口实现类的方式操作数据库。 熟悉源码的同学应该知道如下代码(MapperProxy.invoke()): ``` @Override public Object invoke...
  • java动态代理--代理接口实现类

    千次阅读 2017-04-03 13:15:32
    使用通过接口定义,或解析接口注解等完成相关功能,如mybatis的SqlSession.getMapper的实现 接口定义 package cn.proxy; public interface IHello { String say(String aa); } 代理实现 package cn.proxy; ...

    使用通过接口定义,或解析接口注解等完成相关功能,如mybatis的SqlSession.getMapper的实现

    1. 接口定义
    package cn.proxy;  
    
    public interface IHello {  
        String say(String aa);  
    }  
    1. 代理实现
    package cn.proxy;  
    import java.lang.reflect.InvocationHandler;  
    import java.lang.reflect.Method;  
    import java.lang.reflect.Proxy;  
    /** 
      JDK动态代理代理类  
     */  
    @SuppressWarnings("unchecked")  
    public class FacadeProxy implements InvocationHandler {    
        @Override    
        public Object invoke(Object proxy, Method method, Object[] args)    
                throws Throwable {    
            System.out.println("接口方法调用开始");    
            //执行方法    
            System.out.println("method toGenericString:"+method.toGenericString());  
            System.out.println("method name:"+method.getName());  
            System.out.println("method args:"+(String)args[0]);  
            System.out.println("接口方法调用结束");    
            return "调用返回值";    
        }    
        public static <T> T newMapperProxy(Class<T> mapperInterface) {  
            ClassLoader classLoader = mapperInterface.getClassLoader();  
            Class<?>[] interfaces = new Class[]{mapperInterface};  
            FacadeProxy proxy = new FacadeProxy();  
            return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);  
          }  
    }  
    1. 运行
    package cn.proxy;  
    
    public class Test {  
        public static void main(String[] args) {  
            IHello hello = FacadeProxy.newMapperProxy(IHello.class);  
            System.out.println(hello.say("hello world"));  
        }  
    }  
    1. 运行结果
    接口方法调用开始  
    method toGenericString:public abstract java.lang.String cn.proxy.IHello.say(java.lang.String)  
    method name:say  
    method args:hello world  
    接口方法调用结束  
    调用返回值 

    转载于http://blog.csdn.net/zhu_tianwei/article/details/40076391

    展开全文
  • 因为jdk动态代理生成的class文件已经继承了Proxy,而java是单继承的,所以是基于jdk动态代理是基于接口的。 请看代码使用jdk动态代理生成class文件 public static void main(String[] args) { Class<?>[] ...
  • 使用mybaitis的mapper接口执行sql语句时,我们拿到其实是接口实现类代理,这个代理类是由mybatis使用动态代理生成接口实现类。 mybatis通过配置 MapperFactoryBean来生成Mapper接口代理。如: <pr
  • java动态代理实现接口调用

    千次阅读 2019-10-14 11:17:33
    动态代理是基于接口实现的代理,...首先,创建一个最基本接口实现类: interface UserManager { void addUser(); } class UserManagerImpl implements UserManager{ @Override public void addUser() { Sy...
  • jdk动态代理为什么必须实现接口

    千次阅读 2020-04-03 18:49:28
    通过jdk实现动态代理会使用Proxy的newProxyInstance方法: 写一个类实现InvocationHandler,内部要注入对应原代理类实现; 测试代码: TestServiceImpl testService = new TestServiceImpl(); TestServiceIm...
  • 对Mybatis不熟悉的可以查看我的这篇文章:Mybatis原理,在使用中,我们往往会很惊讶,啥我只定义了一个接口,就可以进行依赖注入,而且还能对数据库进行操作,这其实是基于代理模式来实现的,对动态代理不了解的...
  • 1、动态代理的原理 ...Java提供2中动态代理的方式,一种是基于接口实现(JDK动态代理),一种是基于继承实现(Cglib)。 2、基于接口动态代理模式 JDK代理模式中,有两个重要的点;一个(Proxy)和一个...
  • 前言 如果你学习过spring,那么你一定接触和使用过Aop。...java原生的动态代理代理的对象必须要实现一个顶级接口,而cglib的动态代理则不需要这样的接口。在很长一段时间里很迷惑什么java的动态代...
  • java动态代理:JDK接口实现方式

    千次阅读 2018-06-11 11:26:21
    (1)什么是代理?大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户----&gt;消防部门119...
  • 引言 mybatis版本:3.5.1 mybatis-spring:2.0.1 ...Mybatis是如何mapper接口生成代理对象的? Mybatis又是如何将mapper对象交给Spring管理? 我们在整合mybatis与spring时,都会使用MyBatis-Spring 将 MyBatis
  • 有借口Test,但是没有实现类,现在需要动态代理这个接口,怎么实现,接口都是jar更新的
  • 我也编写一个接口,代码未给出实现,通过动态代理进行接口的默认实现,通过FactoryBean方式注入到容器中(当然,我们也可以通过在一个用@Configuration声明的配置中,通过@Bean注解,手动编写该实例的生成过程)。...
  • 前边我们讲过了如何SqlSession的作用和使用方法,即SqlSession是操作数据库的接口其中含有一系列操作数据库的方法。但是他是线程不安全的,所以在使用它的时候就必须放在方法内部使用,即定义也要在方法内部。今天...
  • 动态代理是许多框架底层实现的基础,比如Spirng的AOP等,其实弄清楚了动态代理实现原理,它就没那么神奇了,下面就来通过案例和分析JDK底层源码来揭秘她的神秘面纱,让她一丝不挂地呈现在我们面前,邪恶了。...
  • 首先解释下,标题的意思,一般在java动态代理中,委托类一般都是实现某接口的具体类,但最近在看mybatis源码的时候,发现mybatis中的mapper接口(XML接口用java接口来描述)并没有实现类 :  sqlsession.getMapper...
  •  如果使用mapper接口的方式,问题来了,这个是个接口,通过sqlSession对象get出来的一定是个实现类,问题是,我们并没有手工去写 实现类,那么谁去干了这件事情呢?  答案是mybatis通过JDK的动态代理方式,在启动...
  • JDK中的动态代理是通过反射Proxy以及InvocationHandler回调接口实现的,...使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用...
  • Mybatis只有接口没有实现类的原理

    千次阅读 2019-08-19 23:49:17
    问题背景 mybaits相对于Ibatis的一大区别就是,不用自己写接口实现类。Ibatis的实现类十几年来做着...mybatis使用了动态代理技术生成实现类动态代理的具体手段有两种:jdk自带和cglib。 对比 jdk自带 cglib ...
  • jdk动态代理(底层动态生成代理类和编译过程)

    千次阅读 多人点赞 2018-09-29 21:23:43
    Java动态代理,顾名思义,动态生成代理对象。其实难点就在这里—动态。到底怎么动态生成代理解决的问题就是增强。其实,实现代理的方式很多种,比如继承,子类对一个增强,我们可以认为子类就是一个代理类,...
  • mybatis使用mapper接口生成实现类

    千次阅读 2016-06-25 00:08:14
    mybatis在java开发中已经成为主流,它有很多优点,例如 1. 易于上手和掌握。 2. sql写在xml里,便于统一管理和优化。 3. 解除sql与程序代码的耦合。...如图:我们在使用mybatis的时候,经常会这样写接口服务。
  • Java 动态代理为啥需要接口???

    千次阅读 2019-03-08 17:16:32
    我们通过查看源码newProxyInstance方法的实现: public static Object newProxyInstance(ClassLoader loader, Class&amp;amp;lt;?&amp;amp;gt;[] interfaces, ...
  • 接口的CGLIB动态代理实现

    千次阅读 2017-03-31 17:05:00
    接口的CGLIB动态代理实现定义接口package com.hk.service; /** * 定义一个接口(一人要做的事情) * @author 浪丶荡 * */ public interface ISomeService { //打官司 public String Litigate(); //吃饭 ...
  • Java中如何动态创建接口实现

    千次阅读 2017-04-21 21:13:33
    1、mybatis / jpa 等orm框架,可以在接口上加注解进行开发,不需要编写实现类,运行时动态产生实现。 2、dubbo等分布式服务框架,消费者只需要引入接口就可以调用远程的实现,分析源代码,其实在消费端产生了接口...
  • 代理设计模式:通过代理完成目标对象的工作,同时代理还可以做自己的事情。...A:如果目标已经实现了某个接口,则代理类和目标类实现相同的接口并在代理类中持有目标的引用, JDK动态代理使用...
  • jdk的动态代理什么需要接口

    万次阅读 2018-05-14 16:34:46
    一直不待明白的是什么,jdk的动态代理需要接口才能实现,这也是其短板和令人诟病的地方。很多的博文说的很复杂,代码一大堆,没有太明白。手打了一下,参考了一些优秀的博文,在这里给自己做个总结。首先,动态代理...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 216,216
精华内容 86,486
关键字:

动态代理为接口生成实现类