tiny-spring学习记录

最近想深入研究一下spring的内部实现原理,但是spring的源码有很多功能,如果直接看很可能会深入到各种功能逻辑无法自拔,刚刚开始看可以只关注spring的主干,其他枝节可以先不加考虑,碰巧发现了一个很好的项目,也就是tiny-spring。
之后会画出类图和sequence图,帮助理清逻辑。

1.step-1-container-register-and-get

定义BeanFactory用于注册与获取bean,
所有的bean使用BeanDefinition进行定义

step-2-abstract-beanfactory-and-do-bean-initilizing-in-it

基于step-1进一步进行改进,对BeanFactory进行分层 Interface-abstractclass-class
明确规定BeanFactory的功能,增加拓展性。
BeanDefinition扩展设置bean全类名方法,跟step1比较更加贴进BeanDefinition的作用,
Step1中直接将bean的实例传入BeanDefinition中,这样不是很好,如果我们想要在bean实例化的时候统一的做一些事情的话这样肯定不行。
而在step2中则把实例化放到了BeanFactory中去,
这样各自的分工更加明确,BeanDefinition只负责bean的定义,而注册和实例化在BeanFactory中统一进行。

step-3-inject-bean-with-property

增加属性注入功能,同样属性定义通过封装放在BeanDefinition中,
属性的实际注入工作交给BeanFactory完成。

step-4-config-beanfactory-with-xml

把bean的定义放到xml中,读取xml到BeanDefinition的map中。
主要就是xml文件的解析和数据的填充,在AbstractBeanDefinitionReader
中表现的很清楚,一个是registry即是要解析成的数据,一个是resourceLoader
数据源的加载器,具体中间怎么解析数据不需要太关心。

step-5-inject-bean-to-bean

在这一步新建了一个BeanReference用于标记引用类型并且存放ref的name,
刚开始很奇怪为什么要这个BeanReference类,直接new一个BeanDefinition给PropertyValue的value属性不就行了么?
实现bean的加载办法:懒加载和预加载两种。
问题类的循环依赖如何解决?
在AutowireCapableBeanFactory的doCreateBean中先将Bean的实例new出来,再把property set进去就不会出现所谓循环依赖的问题。

step-6-invite-application-context

把Bean的读取,向BeanFactory注册功能封装到ApplicationContext中去,只要传入配置文件位置就可以直接从ClassPathXmlApplicationContext拿到bean。

到这里应该有个总结:

前六步其实也就做了一件事情那就是制作一个最简化的IOC容器,它的功能是

  1. Bean的加载(xml)与初始化,
  2. 实现依赖注入(未实现注解支持,跟普通属性注入其实差不多),
  3. 把IOC容器封装成一个便于操作的ApplicationContext对象。

step-7-method-interceptor-by-jdk-dynamic-proxy

实现aop需要用到的包

<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>

这个包定义了一系列的aop接口规范。
切面的实现,具体见类图
tiny-spring-step7

  1. TargetSource只是对目标对象的信息进行了封装,方便使用。
  2. AdvisedSupport封装了切面和切入点,切面由MethodInterceptor定义,切入点由TargetSource定义,这里需要注意我们通常在spring里边的切入点可以精确到某个方法,这里只实现了精确到某个目标对象,即这个目标对象里的所有方法。
  3. JdkDynamicAopProxy代理封装。谈到动态代理就不得不提一个类和一个接口,即Proxy和InvocationHandler。网上有很多文章讲解动态代理,而且篇幅不短很容易把人搞晕。其实简单点可以理解为动态代理的实现都是在Proxy类里边完成的,这个类把我们要执行的方法,目标对象,方法参数这三个要素抽离出来备用。而InvocationHandler唯一的接口方法invoke正是把Proxy准备好的这三个要素当作参数传入,最终我们可以在invoke方法中使用反射的方式完成方法调用返回结果。(使用jdk动态代理需要注意:Proxy生成代理类的输入参数有三个:classLoader/interfaces/invocationHandler,值得注意的是interfaces这个参数,这个参数是被代理类所有实现的接口,也就是说jdk动态代理要求被代理对象必须实现接口,而且在代理类生成以后转型时也必须转型成接口才可以,假如你的被代理类实现了两个接口,这两个接口里分别有一个方法,在生成代理后要分别转型成对应的接口才能调用到相应的方法。jdk动态代理的不足也就是在这里,它要求被代理类必须要继承接口,而如果要直接要对类进行代理可以用cglib(下面会讲到))
  4. 还有就是为什么要用到MethodInterceptor,MethodInvocation这些接口呢?看起来很复杂的说。
    MethodInvocation用来包装方法反射所用到的所有元素,即目标对象,方法,参数。在proceed方法中进行反射得到结果。
    MethodInterceptor顾名思义方法的拦截器,就是在方法执行前后执行一些定制的代码。它的接口方法invoke()以MethodInvocation作为参数。
    MethodInvocation,MethodInterceptor等等这一系列的接口组成了aop的协议。

step-8-invite-pointcut-and-aspectj

引入aspectj包,实现根据切面表达式匹配类和方法。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.11</version>
</dependency>

这是eclipse的项目,官网地址&Getting Start

类图
step-8-invite-pointcut-and-aspectj

这一步做的事就是解析与匹配,可以看测试类AspectJExpressionPointcutTest。

step-9-auto-create-aop-proxy

这一步做的事情是在springContext初始化的时候,找一个合适的时机生成aop代理。
1. 时机:
如seq图
step-9-seq
在实例化bean后,初始化bean时把bean替换为代理类。
2. 生成代理这一步中最主要的类就是
AspectJAwareAdvisorAutoProxyCreator
类图
step-9-class
实现BeanPostProcessor,在postProcessAfterInitialization方法中完成代理。
实现BeanFactoryAware,获取BeanFactory实例,也就是相当于springContext,使用BeanFactory获取所有切面,对每个bean进行匹配,如果匹配就使用JdkDynamicAopProxy进行代理。
做个比喻,每个切面就行机场安检,有很多层,每一个bean就像是乘客。在上飞机之前乘客需要依次过层层安检,如果安检发现乘客身上有匹配项,就对乘客进行相应处理,最终上飞机的乘客可能已经和安检之前不同了(哈哈,想想就怕)。

step-10-invite-cglib-and-aopproxy-factory

引入cglib

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>2.1_3</version>
</dependency>

cglib使用

    public interface A{
        void a();
    }
    public interface B{
        void b();
    }
    public static class C implements A,B{

        @Override
        public void a() {
            System.out.println("a");
        }

        @Override
        public void b() {
            System.out.println("b");
        }
    }
    public static class MyHandler implements net.sf.cglib.proxy.InvocationHandler{
        private Object o;
        public MyHandler(Object o){
            this.o=o;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("cglib before");
            Object invoke = method.invoke(o, args);
            System.out.println("cglib after");
            return invoke;
        }
    }
    @Test
    public void test(){
        Enhancer enhancer = new Enhancer();
        //提供了针对接口和类的代理,使用一种即可
        enhancer.setSuperclass(C.class);
        enhancer.setInterfaces(C.class.getInterfaces());

        MyHandler myHandler = new MyHandler(new C());
        enhancer.setCallback(myHandler);
        C c = (C)enhancer.create();
        c.b();
        c.a();
    }

为什么要使用cglib

这是我们的代理对象决定的,aop所要代理的类通常都没有继承接口,所以就要使用能够直接对类进行代理的cglib。

ProxyFactory

ProxyFactory
ProxyFactory里边封装了所有aop相关的代理所需要的功能和原料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值