利用尽量少的依赖(目前依赖dom4j,cglib,aspectjweaver)实现一个支持AOP的IOC容器模仿Spring的框架,功能包括:IOC、AOP、模块化与自动配置、orm、事务、MVC支持(计划中)、web容器支持(计划中)
设计思路参考手写Spring---IOC容器(1)
、手写Spring---DI依赖注入(2)、
手写Spring---AOP面向切面编程(3)和手写Spring---AOP面向切面编程(4)
在此基础上扩展支持基于xml的bean定义和基于注解的bean定义,实现bean的自动化扫描。后续将支持AOP织入(已支持)。
注意:XML方式容器已停止开发
| 实现的功能 | 注解方式 | xml方式 |
|---|---|---|
| bean扫描 | [x] | [x] |
| 单例支持 | [x] | [x] |
| 通过名称获取实例 | [x] | [x] |
| 通过类名获取实例 | [x] | [x] |
| 自定义构造、解构函数 | [x] | [x] |
| 值注入 | [x] | [x] |
| 依赖注入 | [x] | [x] |
| 构造函数注入 | [x] | [x] |
| 计划的功能 | 实现 |
|---|---|
| AOP所需代理类生成 | 100% |
| 基于类和方法的切点定义 | 100% |
| 基于正则式的切点定义 | 30%(未完整测试) |
| 切面扫描 | 100% |
| 切面自动注册 | 100% |
| 自动配置AOP开闭 | 100% |
| 计划的功能 | 实现 |
|---|---|
| 自动配置数据库功能开闭 | [x] |
| 数据库连接池 | 部分实现 |
| 结果集映射到POJO | 基本可用 |
| 基于接口的Dao层实现 | [x] |
| SQL语句占位符 | 部分可用 |
| 事务支持(封装JDBC) | 部分可用 |
- 默认情况下,标注
@Bean或者@Config的类才能被扫描。@Bean作用在类上必须提供无参构造函数,若必须带参数,则可以在标记了@Config的类中将相应的 工厂方法标记为@Bean来定义bean,此时若@Bean注解没有提供beanName则默认使用该方法名,此种bean定义不支持通过class获取实例 - 使用
@InitMethod和@DestroyMethod标记构造和解构函数 - 使用
@Wire注入依赖,你可以在接口前使用@Wire注解,容器将尝试使用标记了@Bean的对应实现类或者兼容的工厂方法去完成依赖注入 - 使用
@Value注入值,包裹在"#{}"中的定义将会从指定的property文件读取,同时可在“#{}”后添加“:default"来指定默认值(将default替换成需要的默认值),否则按照字面值解释 - 可以通过向PropertiesApplicationContext(注解方式下默认的IOC容器)添加
PackageScanner.Filter来自定义扫描过程。 - 目前框架的自动配置器会去主动扫描的自动配置类定义在core模块的
com.aagu.ioc.context.ConfigurationCenter.java,需要修改代码才能添加额外的自动配置。
- 所有的bean都定义在标签
<container></container>中 <bean></bean>标签中是一个bean的定义name属性声明bean的名称,必须有class属性声明bean的java类,必须有scope属性声明bean的类型,可选属性,有singleton和prototype两种值<initMethod></initMethod>标签值为java class中自定义的初始化方法,可选<destroyMethod></destroyMethod>标签值为java class中自定义的销毁方法,可选<property></property>标签表示bean的注入,name属性是java class中依赖的名称。ref属性声明被注入的bean的名称(与bean的声明的名称保持一致)。type表明注入值的类型,value表明注入值的真实值,这两者配合使用,且不能和ref同时使用<constructor></constructor>标签表明构造函数,每个参数单独声明在<param></param>中,name属性表示参数名称,type属性表示参数类型,类注入统一标记为bean,value属性表示参数真实值(对于类注入,就是bean的名称)
要想使用数据库,需要在配置文件中声明enable-data=true,并提供数据库Url,Driver,User(可选),Password(可选)
数据库支持的设计思路参考Mybatis,Dao层接口用@Repository标识,提供@Select,@Insert,@Update,@Delete注解,每种注解需要声明sql语句,暂不支持占位。配合@Wire注解自动注入实现类。当然也可以获取sessionFactory实例,手动执行sql,返回结果为ResultSet。
数据库支持利用@Transactional声明事务,目前仅支持将一个方法中的数据库操作纳入一个事务管理,捕获异常自动回滚,否则提交。不支持嵌套事务、事务传播、隔离
级别定义。当@Transactional作用于方法时,该方法将纳入事务管理,当@Transactional作用于类时,该类声明的全部公开方法都将纳入事务管理。
编程式事务可以通过获取transactionManager这个bean手动控制
该项目内置的Web服务器处于非常初级的阶段,并未在开发计划中(其实就是我自己玩玩)
目前,web服务器分为web和mvc两个模块,前者提供web服务器,后者提供mvc支持。web监听http请求,并封装为HttpServlet形式,调用HttpServlet接口提供的service方法响应请求。理论上讲,任何HttpServlet接口的实现类都能用来提供HTTP响应。mvc模块提供一个类似Spring MVC的框架,根据@Controller和@RequestMapping注解进行路由扫描和注册,路由支持*通配和:subpath形式具名匹配,后者可以通过@PathVar注解注入到方法的入参中,另外框架支持@RequestParam注解向方法入参注入请求参数。如果需要web功能,可以通过继承TinyWebApplication快速开始。
程序的入口定义在TinyIocApplication中,实际使用时我们需要新建一个它的子类并实现run方法,待容器初始化完成后将从此处开始运行。对于Web应用,可以通过继承TinyWebApplication类快速开始,避免手动编码开启web服务器。
同时我们的子类必须加入@Application注解,我们可以在该注解上填写basePackage指定扫描的包(默认为我们的子类所在的包)。要想使用xml方式的容器,需要在@Application注解上填写xmlLocation注明xml文件所在路径。
另外@Application还可通过property指定property文件,从文件读取值的定义。
目前仅支持注解方式的AOP使用,标记@Aspect的类将被识别为切面定义。
目前支持前置、后置、环绕和异常四种切点定义,分别使用@Before、@After、@Around和@AfterThrow标记,并为expression参数传入AspectJ形式的匹配语法。
方法名没有限定,前置、后置和异常切点入参为JointPoint类,环绕切点入参为ProceedJointPoint。通过@Order注解添加切面顺序,数字越小优先级越高,默认为0
!!!注意:AOP默认关闭,需要在property中加入enable-aop = true手动开启