Fork me on GitHub

MyBatis源码解析【4】反射和动态代理

通过之前的介绍,我们了解了几个组件的生命周期。

它也是我们重要装备之一。

今天我们需要搞一件更加强的装备,叫做反射和动态代理。

如果没有这件装备的话,显然后面的源码boss是打不动的。

顺便说一下,下面可能会提到一些名词简写,都在之前出现过,所以如果看不明白可以看一下之前的咯。

废话少说,╭(′▽`)╯

 

什么是代理

首先我们要明白代理是什么样一个概念。

不要想这个概念有多复杂,其实很简单的。代理从中文角度很好理解嘛。它是一个动词吧,举个实际的例子,你代理我,帮我抄作业。

我--->你--->作业

你代理我,相当于我让你做,或者你帮我做。

最终抄作业这个事情呢是由你来完成的。嘻嘻。

注意这个例子的两个关键:

1、我没有直接操作真实的最终的对象。(我没有抄作业)

2、你可以提供额外的服务,比如告诉我作业抄好了,或者明天有什么作业。

那么认真的讲:

通过代理模式,访问者没有办法操作真实的对象,只能通过代理对象去操作真实的对象。代理对象可以提供额外的服务,比操作真实对象更多的服务。

 

什么是反射

是不是很多人当提到这个概念有下面几个感觉:1、反射学过没用过。2、反射很难,但是没啥用。3、反射很危险,没事情不要乱用。

如果你有这么几个概念的话,证明你已经对反射有一些学习和感觉了(滑稽脸)。

如果没有的话,我建议呢,还是去好好找个大神的博客或者视频学习一下反射。因为不简单,听我一两句可能不一定明白。

那我们这里用到反射,需要知道这几个点。

1、在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。

2、对于任意一个对象,都能够调用它的任意方法和属性;生成动态代理。

3、通过一些特殊的方法得到对象,calss.forname等

知道这些就可以了。

如果你愿意呢,可以看一下我以前写的关于反射的几个小例子,希望能帮到你:http://www.cnblogs.com/linkstar/p/5744444.html

 

什么是动态代理

动态代理其实上面在说代理的时候以及提到了。其实就是动态的代理嘛。

动态代理这里介绍两种:一种使用JDK的反射机制提供的代理,另一种是CGLIB代理。

我们一种种来讲。

JDK的动态代理。

如何实现呢?很简单,完成两个类就可以了。

1、服务类,也就是真正提供服务的人。

2、代理类,代理做事情的人。

对于JDK的动态代理的服务类来说需要额外一个接口开放给代理类哦。

下面是代码

接口

public interface DemoService {
    public void demo();
}

实现类

public class DemoServiceImpl implements DemoService {
    public void demo() {
        System.out.println("Test------------");
    }
}

代理类

public class DemoServiceProxy implements InvocationHandler {

    private Object target;

    public Object bind(Object target){
        this.target = target;
        //利用反射将这个类DemoServiceProxy作为传入的目标类的代理类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    //代理方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method : " + method.getName());
        return method.invoke(target, args);
    }
}

测试类

public class DemoServiceTest {
    public static void main(String[] args) {
        DemoServiceProxy demoServiceHanler = new DemoServiceProxy();
        DemoService proxy = (DemoService) demoServiceHanler.bind(new DemoServiceImpl());
        proxy.demo();
    }
}

最后打印结果

method : demo
Test------------

这里的这几个类的作用和功能要好好理解哦,因为后面读源码的时候需要用到。

然后是CGLIB代理

相对来说就没有那么复杂了,只需要一个类就可以了,不需要接口。

public class DemoServiceCglib implements MethodInterceptor {

    private Object target;

    public Object getInstance(Object target){
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("method : " + method.getName());
        return proxy.invokeSuper(obj, args);
    }
}

测试类修改

public class DemoServiceTest {
    public static void main(String[] args) {
        /*DemoServiceProxy demoServiceHanler = new DemoServiceProxy();
        DemoService proxy = (DemoService) demoServiceHanler.bind(new DemoServiceImpl());
        proxy.demo();*/
        DemoServiceCglib demoServiceCglib = new DemoServiceCglib();
        DemoService proxy = (DemoService) demoServiceCglib.getInstance(new DemoServiceImpl());
        proxy.demo();
    }
}

测试结果相同。

这里就不深究两种动态代理的各种参数啊,方法啊。

我们需要知道的是,在被动态代理之后,当我们调用原来的方法时候一定调用一个叫做invoke的方法。

也就是在调用的前后我们能做很多事情了。

上述在mybatis的源码中会出现,很重要,望理解。

 

至此,装备都有了,之后就要开始进入难点了。

posted @ 2017-07-04 22:15  LinkinStar  阅读(827)  评论(0编辑  收藏  举报