为seed容器添加自动注入和AOP功能

img

前言

  大概在半年前写了一个简陋的ioc容器,并设想实现不少功能,不过以后由于各类缘由(主要是懒( ̄▽ ̄)")闲置了。最近又从新将这个项目拾起,经过半个多月上班摸鱼时间更新了两个版本0.0.2(实现自动注入)和0.0.3(实现AOP),这篇博客就简单讲讲实现的一些过程,分享给你们。源码地址java

自动注入

大体流程图:
git

img

  自动注入实现思路比较简单,在bean建立完成后查看有哪些须要注入的属性,利用beanPostProcessor来对bean进行处理,注入须要的属性。目前seed容器支持 @Autowired注入当前bean中的类,以及 @Value注入默认值和 seed.yml/ seed.properties(当前seed容器环境变量environment)中的属性(当前还不可以和spring同样支持复杂的方法等表达式)。主要功能其实就只有两块:

  1. 解析yml文件。
  2. 判断某个类是否符合注入须要(须要考虑到泛型)。

  解析yml比较简单,因为yml文件颇有特色。实现了YmlProperties用于读取yml文件(参考了Properties类)。实现HashTable来存储读取的属性值键值对。经过逐行读取文件,利用yml文件明显的特色:空格来表示所属分级,来判断出当前所属节点以及上级节点,将全部属性读取成spring.aop(每一级用·分隔)格式的key,再利用的分隔符来获取value。在seed容器初始化的时候将属性加入到容器中。github

  判断某个类的是否符合注入需求作起来仍是走了一些弯路。其实实现起来也不难,首先须要注入的类必定同级类或者父类。只要找到容器中每一个bean的实现或继承类所对应的泛型关系就能够了,经过二者对应的泛型关系来比较是否为相同的类。web

AOP

  AOP功能的实现也是依赖的BeanPostProcessor。主要功能点在建立jdk以及cglib代理类和切入点的读取处理。实现仍是参考的spring,在建立代理类的时候利用拦截器链来在方法执行先后进行处理。不论是建立jdk的代理类仍是建立cglib的代理类都会给处理器设置一个拦截器链,里面放置着匹配该类的拦截器,以后执行代理类方法的时候会匹配拦截器并逐一执行拦截器。
AOP抽象层的建模:
spring

img

  首先讲下建立代理类遇到的一些问题吧,JDK的代理类建立比较简单直接调用java的api就行。cglib就有些问题了,因为是直接建立的新类,因此若是原先的类若是没有无参的构造函数就须要调用有参构造函数,那么就要在建立代理对象时注入构造函数参数。我这边的处理方式是获取第一个构造函数传入的null参数。(其实和spring相似,因为spring本身实现了cglib,因此它在建立代理对象的时候不须要调用构造函数。)这边使用空参数并会有带来什么影响,由于最终调用原始方法的仍是容器建立的对象,而不是代理对象。(这是在实现cglib的MethodInterceptor时处理的)。可是若是建立对象的构造函数对参数进行了判断而且抛异常,那建立代理对象就会出错,暂时尚未什么好的方案修复这一点,这也许就是spring使用本身的方式来实现cglib代理对象建立的缘由吧。数据库

  在完成建立一个带有拦截器链的代理类以后遇到的问题就是如何匹配切点表达式。原先是想本身实现的,然而本身光是写匹配包名的表达式就花了好几个小时,因而果断放弃了(lll¬ω¬)。而后看了下spring是如何处理的,结果发现spring是使用了aspectjweaver这个jar包来处理的。以后便在aop模块导入了该jar包,参考了spring的使用方式,完成了对切面表达式的匹配。(因此@Aspect,@Before等注解都是使用的该jar包的)。api

  在完成编码以后赶忙测试了一下AOP的功能,发现彻底OK,说实话仍是有点小激动的,就目前使用来看和Spring的几乎没有什么差异,能够说彻底契合麻雀虽小,五脏俱全这句话了。不过仔细想一想在实现AOP的时候也没有太多难点,主要仍是在思路上。我虽然实现方式有差异,可是大体思路仍是模仿Spring,仍是得感叹下Spring设计师超前的思路。框架

总结

  完成了自动注入和AOP以后能够说seed做为一个bean容器来讲已经比较完善了。以后应该会为该项目添加更多功能,例如数据库交互,web交互等等。该项目仍是可以帮助我更好的理解框架内部的一些原理的。最后我但愿本身的项目能够帮助到你们。(若是有志同道合的小伙伴咱们能够一块儿写一些比较好玩的项目O(∩_∩)O)函数

相关文章
相关标签/搜索