Score
0
Watch 19 Star 33 Fork 10

wkgcass / Pure.IoCJavaMIT

Join us
Explore and code with more than 2 million developers,Free private repositories !:)
Sign up
轻量级基于类型和注解的依赖注入框架 spread retract

Clone or download
Cancel
Notice: Creating folder will generate an empty file .keep, because not support in Git
Loading...
Readme.md

click here(git@osc) to get English tutorial.

#Pure.IoC Pure.IoC是一个轻量级基于类和注解的自动依赖注入框架。

使用jdk 1.8
推荐与Spring配合使用

<dependency>
  <groupId>net.cassite</groupId>
  <artifactId>pure.ioc</artifactId>
  <version>0.3.2</version>
</dependency>

##框架思想 以已有的逻辑关系代替复杂的配置

##主要功能

  • IOC
  • AOP

##设计思路 通常写java时会使用Spring框架进行IoC管理。而Spring是基于bean的,配置起来首先需要将类映射到bean,然后描述bean的依赖关系。

事实上,很多时候依赖关系仅仅需要类型即可确定。比如说

class A{
	...
	public void setB(B b){ this.b=b; }
}

class B{
}

很显然,A依赖于B,A需要将一个B的实例通过setB注入进来。这应当是很自然的逻辑关系。

类型依赖在编码时就会设定好,所以,如果有工具能帮助完成这类“显而易见”的依赖该多好。于是我开发了Pure.IoC

#框架的框架 ##扩展性 设计Pure.IoC时经历了不少思考。考虑下面这样的“复杂”情况(其实已经算不复杂了)

@Singleton
@Wire
class Complex{
	private ......
	
	public Complex(){ ... }
	@Default public Complex(AnotherClass obj){ ... }
	
	public void setA(A a){ ... }
	public void setB(B b){ ... }	
	public void setInterface(Interf1 interf){ ... }
	public void setInterface(@Use(clazz=Impl2.class)Interf2 interf){ ... }
}

@Default(clazz=Impl1.class) interface Interf1{ ... }

上述注解描述了:

  • @ Singleton Complex是一个单例
  • @ Wire 在通过AutoWire构建时需要注入
  • @ Default 指定默认的构造器(构造函数上),指定默认的实现类(接口上)
  • @ Use 指定使用的类

注解应当可以无限的附加,也不能增加系统复杂性。
所以,最终使用这种设计:

AnnotationHandler + HandlerChain

AnnotationHandler分为三种,

  • ParamAnnotationHandler 负责根据类型获取实例
  • ConstructorFilter 负责选择构造器,考虑构造器上的注解
  • TypeAnnotationHandler 负责选取要构造的类型,考虑类型上的注解

Handler被注册到IOCController上,根据注册的顺序进行handling操作。handler的内部实现有点像AOP,一般来说会调用chain.next().handle(...) ,然后根据返回值或者异常进行一些逻辑判断。详情见各Handler接口的handle方法文档

所以,可以非常方便的进行注解的扩展。

##循环依赖 循环依赖虽然不很常见,但没准会遇到。A->B->C->A
从逻辑上,A,B,C中必须有一个是单例,否则对象的创建将无限循环下去。

另外: Spring要求构造器不能循环依赖,否则无法完成构建。

不过Pure.IoC巧妙的解决了循环依赖的问题。

  • 所有注入在构造时进行。只有注入完成,构造才会完成。
  • 对于单例,在构造实际进行前把自己的引用交给IOCController,指示单例已经存在
  • 由于只有注入完成才构造完成,所以不必担心获取到一个构造一半的对象。

所以,即使是构造器中包含循环依赖,也能顺利的进行(本质上所有依赖都是构造器依赖)。

##适用性 Pure.IoC由于设计为构造时注入,所以不需要任何额外组建即可放入框架中使用。也可配合Spring使用。甚至可以一部分setter通过本框架注入,一部分通过Spring注入。

直接与Struts2等相接也可以。由于注入过程完全在类内部,所以并不需要像Spring一样配置接管Struts2的对象工厂,而是直接就可使用(一个对象本身就是注入“工厂”)。

推荐的使用方法是

extends AutoWire

但是有些情况下必须继承别的类,那么有两种解决办法:

@Wire class A { ... }

@Wire注解标注的类在任何经过Pure.IoC的情况下都会进行注入操作。
在单独获取时可使用

AutoWire.get(A.class)

获取实例

class A {
	public A(){
		AutoWire.wire(this);
	}
}

构造时将自己的引用交给框架进行注入。

实际上所有入口最终都调用AutoWire.wire(Object)

#如何使用?

  • 首先使用上述三种方法任何一种进行框架接入。

  • 接着在程序入口直接调用

      IOCController.autoRegister();

    或者手动register各Handler,比如

      register(new DefaultConstructorFilter());

    如果是JavaEE,则可以写一个Listener完成这种操作

  • 最后使用

      IOCController.closeRegistering();

    关闭handler的注册。(这一步可选,仅仅为了保证存储handler的list不会被修改)

没有注册Handler却已开始装配,将先行调用autoRegistercloseRegistering

##默认行为 没有任何注解参与时的默认行为是:

注入setter时,获取参数类型并向IOCController请求实例,获取实例后进行setter的invoke。

在获取实例时,取得唯一一个构造器,或者取得无参数的构造器。
如果构造器有参数,则取得参数类型对应实例。
最后进行构造

##扩展注解 ###Type

  • Wire 指示该类需要注入
  • Singleton
    指示该类为单例
  • Default(clazz)
    一般用于interface或者abstract class
    在Type检查时若遇到该注解则会转而构造该注解指定的类型

###Constructor

  • Default()
    在可能产生歧义时指定构造时默认使用的构造函数

###Param

  • Use(clazz, constant, variable)
    clazz代表使用指定的类型作注入 接下来会对指定的类型进行Type检查。
    value代表在scope中注册的值
  • Force(value)
    将String类型的value转化为对应的类型。Force只支持基本类型和String
  • Extend(handler, args)
    表示从其他对象工厂获取对象
    handler ExtendingHandler,指定一个handler,描述如何从其他对象工厂获取对象
    args 用于放入handler的参数
  • Session(value)
    表示该Setter的参数值将在同一个Session中共享
    value 共享的别名
  • Ignore
    忽略该参数,仅在Setter上使用,即忽略该setter

此外,进行Param处理时还提供自动的基本类型注入。
若没有找到可用的注入,则将检查基本类型和数组类型,并初始化为默认初始值(0,false,array[length=0])

#其他 ##Session Session存在于一次从装配操作开始到完成的所有中间操作之中.几乎每个方法传递参数时都会将Session作为参数传递.
例如:
A依赖于B,B依赖于C和D.其中,A和C继承于AutoWire(隐式调用了AutoWire.wire(o)),而B和D均使用Wire注解.
那么,ABD的装配工作共享一个Session,C的装配工作属于另一个Session

##Utils 提供了一个Utils类,包含了一些常见操作,以及IOCController中protected的方法。如果不方便继承IOCController,你还可以使用Utils中提供的方法来调用那些protected的方法。

##ExtendingHandler 设计初衷是用于简化从其他对象工厂获取实例的工作。但也不限于此。
其实可以理解为扩展的简化
它用于同时完成Type,Setter和Param的Handling工作,只不过接受的参数只能是字符串数组。

###ScopeAware 实现ScopeAware接口并标记@Wire,那么将会以当前Scope为参数调用其方法.实际上,直接书写setScope(Scope s)也可以完成注入

#AOP 从版本0.1.1开始新增AOP功能

在带接口的类上设置

@AOP({Weaver.class,...})

即可获取AOP支持。

当该类被Pure.IoC注入时,或者直接使用

AOPController.weave(()->该类实例,该类.class)

即可注入/获取代理对象。

##使用 ###创建你的Weaver

class YourWeaver implements Weaver{
	@Override
	protected void doBefore(AOPPoint point) {
		...
	}

	@Override
	protected void doAfter(AOPPoint point) {
		...
	}

	@Override
	protected void doException(AOPPoint point) throws Throwable {
		...
	}
}

before, after, exception分别对应Before, AfterReturn, AfterThrowing类型。此处实际上也是Around型。

还提供了BeforeWeaver, AfterWeaver, ExceptionWeaver。
如果你只需要特定的cut point类型,你可以继承这些类。

如果需要使用Introduction型,也非常方便,只需要让你的Weaver实现需要的接口即可,无需其他任何操作

###织入 使用

@AOP({Weaver1.class, Weaver2.class, ...})

来织入
如果要使用cglib,则可以强制useCglib=true

@AOP(value={Weaver1.class, Weaver2.class, ...} useCglib=true)	

AOP过程遵循如下步骤

  • 通过AutoWire.get(Class)获取各Weaver实例
  • 设置一个变量来存储当前的Weaver数组的下标
  • 从第一个到最后一个Weaver,依次进行'before'
  • --如果设置了returnValue,直接跳到'after'步骤
  • 执行方法
  • --如果遇到了异常, 从最后一个到第一个进行'exception'
  • 从存储的下标到第一个,依次进行'after'

###AOPPoint 该类包含如下公共字段/方法

  • target 目标对象
  • method 当前方法
  • args 输入参数(可直接修改)
  • returnValue() 获取返回值
  • returnValue(Object) 设置返回值
  • exception() 获取当前异常
  • exceptionHandled() 异常已处理

###TargetAware 在Weaver中实现TargetAware接口,那么在获取该Weaver实例后将会以被代理对象为参数调用其方法.

Comments ( 0 )

Sign in for post a comment

Java
1
https://gitee.com/wkgcass/Pure.IoC.git
git@gitee.com:wkgcass/Pure.IoC.git
wkgcass
Pure.IoC
Pure.IoC
master

Help Search