jBeanBoxIOC/AOP工具
jBeanBox
License: Apache 2.0
jBeanBox是一個(gè)微形但功能較齊全的IOC/AOP工具,除了引入的第三方庫(kù)之外,它的核心只有十多個(gè)類,源碼只有1500行左右。它運(yùn)用了“Box”編程模式,利用純粹的Java類作為配置。jBeanBox運(yùn)行于JDK1.6或以上。
jBeanBox的開發(fā)目的是要克服其它IOC/AOP工具的一些問題:
- Spring: 源碼臃腫,Java方式的配置不靈活,在動(dòng)態(tài)配置、配置的繼承上有問題、啟動(dòng)慢、非單例模式時(shí)性能極差。
- Guice: 源碼略臃腫(200個(gè)類),使用不太方便,對(duì)Bean的生命周期支持不好。
- Feather:源碼極簡(jiǎn)(幾百行),但功能不全,只是一個(gè)DI工具,不支持AOP。
- Dagger: 源碼略臃腫(300個(gè)類),編譯期靜態(tài)注入,使用略不便,不支持AOP。
- Genie: 這是ActFramework的內(nèi)核,只是DI工具,不支持AOP。
如何在項(xiàng)目中使用jBeanBox?
手工下載jbeanbox-2.4.8.jar放到項(xiàng)目的類目錄,或在pom.xml中加入以下配置:
com.github.drinkjava2
jbeanbox
2.4.8
jBeanBox不依賴于任何第三方庫(kù),為避免包沖突,它將用到的CGLIB等第三方庫(kù)以源碼內(nèi)嵌方式包含在項(xiàng)目中。jBeanBox的jar包尺寸較大,約為750K,如果用不到AOP功能,可以只使用它的DI內(nèi)核,稱為"jBeanBoxDI", 只有49k大小,將上面artifactId中的jbeanbox改成jbeanboxdi即可。jBeanBoxDI項(xiàng)目詳見jbeanboxdi子目 錄。
第一個(gè)jBeanBox演示:
以下演示了9種不同的注入方式:
public class HelloWorld {
public static class User {
String name;
public User() { }
@VALUE("User1")
public User(String name) { this.name = name; }
void setName(String name) { this.name = name; }
void init() {this.name = "User6";}
@PreDestroy
void end() {this.name= "User9";}
}
public static class UserBox extends BeanBox {
Object create() {return new User("User2");}
}
public static class H7 extends UserBox {{setAsValue("User7");}}
public static void main(String[] args) {
User u1 = JBEANBOX.getInstance(User.class);
User u2 = JBEANBOX.getBean(UserBox.class);
User u3 = JBEANBOX.getBean(new BeanBox().injectConstruct(User.class, String.class, value("User3")));
User u4 = JBEANBOX.getBean(new BeanBox(User.class).injectValue("name", "User4" ));
User u5 = JBEANBOX
.getBean(new BeanBox(User.class).injectMethod("setName", String.class, value("User5")));
User u6 = JBEANBOX.getBean(new BeanBox().setBeanClass(User.class).setPostConstruct("init"));
BeanBoxContext ctx = new BeanBoxContext();
Interceptor aop=new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0]="User8";
return invocation.proceed();
}
};
User u7 = ctx.bind(String.class, "7").bind("7", H7.class)
.getBean(ctx.getBeanBox(User.class).addMethodAop(aop, "setName",String.class).injectField("name", autowired()));
System.out.println(u1.name); //Result: User1
System.out.println(u2.name); //Result: User2
System.out.println(u3.name); //Result: User3
System.out.println(u4.name); //Result: User4
System.out.println(u5.name); //Result: User5
System.out.println(u6.name); //Result: User6
System.out.println(u7.name); //Result: User7
u7.setName("");
System.out.println(u7.name); //Result: User8
ctx.close();
System.out.println(u7.name); //Result: User9
}
}
這個(gè)例子的輸出結(jié)果是依次打印出“User1” 、“User2”...到“User9”。下面遂一解釋:
- 利用了@VALUE("User1")注解,進(jìn)行了構(gòu)造器注入
- UserBox是一個(gè)jBeanBox的純Java配置類,這個(gè)Java類是一個(gè)純粹的Java類(不象Spring中的Java配置類是一個(gè)非 常特殊的類,它在運(yùn)行期會(huì)產(chǎn)生一個(gè)代理類),可以運(yùn)用類的繼承、方法重寫等常見設(shè)計(jì)模式。 在這個(gè)示例里它的create方法手工生成了一個(gè)User("User2")對(duì)象。
- 第三個(gè)是動(dòng)態(tài)生成一個(gè)BeanBox配置,動(dòng)態(tài)配置它的構(gòu)造器注入,注入值為"User3"。
- 第四個(gè)也是動(dòng)態(tài)配置,演示了字段注入,注入值為常量"User4".
- 第五個(gè)是方法注入的演示,注入?yún)?shù)依次為:方法名、參數(shù)類型們、實(shí)際參數(shù)們。
- 第六個(gè)是setPostConstruct注入,等效于@PostConstruct注解,即Bean生成后立即執(zhí)行的方法為init()方法。
- 第七個(gè)比較復(fù)雜,ctx是一個(gè)新的上下文實(shí)例,它先獲取User.class的固定配置,然后給它的setName方法添加一個(gè)AOP切面,然后 注入"name"字段為autowired類型,也就是說String類型,不過在此之前String類被綁定到字符串"7",字符串"7"又綁定到 H2.class,H7又繼承于UserBox,UserBox又返回"User2",然而都是浮云,因?yàn)镠7本身被配置成一個(gè)值類型"User7",于 是最后輸出結(jié)果是“User7”。
- 第八個(gè)比較簡(jiǎn)單,因?yàn)閟etName方法被添加了一個(gè)AOP攔截器,參數(shù)被改成了"User8"。
- 第九個(gè)是因?yàn)閏tx這個(gè)上下文結(jié)束,所有單例被@PreDestroy標(biāo)注的方法會(huì)執(zhí)行,這是一個(gè)標(biāo)準(zhǔn)JSR330注解。
上例除了一頭一尾外,主要演示了jBeanBox的Java方法配置,Java方法即可以動(dòng)態(tài)執(zhí)行,也可以在定義好的BeanBox類中作為固定配 置執(zhí)行,固定的配置可以打下配置的基調(diào),當(dāng)固定配置需要變動(dòng)時(shí)可以用同樣的Java方法來進(jìn)行調(diào)整(因?yàn)楸緛砭褪峭粋€(gè)BeanBox對(duì)象)甚至臨時(shí)創(chuàng)建 出新的配置,所以jBeanBox同時(shí)具有了固定配置和動(dòng)態(tài)配置的優(yōu)點(diǎn)。另外當(dāng)沒有源碼時(shí),例如配置第三方庫(kù)的實(shí)例,這時(shí)所有的注解方式配置都用不上,唯 一能用的只有Java配置方式。
上例中的value()方法是從JBEANBOX類中靜態(tài)引入的全局方法,這個(gè)示例的源碼位于單元測(cè)試目錄下的HelloWorld.java。
jBeanBox注解方式配置
jBeanBox不光支持Java方式配置,還支持注解方式配置,它支持以下注解:
@INJECT 類似于JSR中的@Inject注解,但允許添加目標(biāo)類作為參數(shù)
@POSTCONSTRUCT 等同于JSR中的@PostConstruct注解
@PREDESTROY 等同于JSR中的@PreDestroy注解
@VALUE 類似于Spring中的@Value注解
@PROTOTYPE 等同于Spring中的@Prototype注解
@AOP 用于自定義AOP注解,詳見AOP一節(jié)
jBeanBox還能自動(dòng)識(shí)別并支持以下JSR及Spring的注解:
JSR的注解:@PostConstruct, @PreDestroy, @Inject, @Singleton, @scope(“prototype”), @scope(“singleton”)
Spring的注解:@Autowired @Prototype
因?yàn)樽⒔夥绞脚渲么蠹叶挤浅J煜ぃ@里就不作詳細(xì)介紹了,在jBeanBox\test目錄下能找到一 個(gè)"AnnotationInjectTest.java"文件,演示了各種注解方式配置的使用。另外還可以調(diào)用 ctx.setAllowSpringJsrAnnotation(false)去禁用JSR、Spring注解,也可以調(diào)用 ctx.setAllowAnnotation(false)去禁用所有注解(也就是說只能用Java方式配置了)。
關(guān)于注解方式配置,jBeanBox與其它IOC工具不同點(diǎn)在于:它不支持@Qualifer、@Name、@Provider這三個(gè)JSR330注解,這是因?yàn)楣P者認(rèn)為這3個(gè)注解在jBeanBox中可以用已有注解實(shí)現(xiàn),如:
@Inject @Named("JDBC-URL") private String url;
在jBeanBox中可以用以下方式替代:
@INJECT(JDBC_URL.class) private String url; //其中JDBC_URL.class是一個(gè)BeanBox類
或
@VALUE("$JDBC-URL") private String url; //$JDBC-URL值可以通過配置BeanBoxContext中的ValueTranslator來解釋。
又如:
@Named("p") public class Person {}
在jBeanBox中看來,Person類已經(jīng)有了唯一的ID: Person.class, 無需再定義一個(gè)多余的“P”作為ID,所有靜態(tài)定義的類,它的類本身就是唯一的ID。jBeanBox對(duì)于靜態(tài)定義的類,默認(rèn)均為單例類,所以每次ctx.getBean(Person.class)都會(huì)獲得同一個(gè)單例對(duì)象。
@Named的問題是它是字符串類型的,無法利用IDE快速定位到配置文件,當(dāng)項(xiàng)目配置很多時(shí),不利于維護(hù)。
jBeanBox是一個(gè)無需定義Bean ID的IOC工具,注意:如果是手工動(dòng)態(tài)創(chuàng)建的BeanBox配置,默認(rèn)均為非單例類。如果用setSingleton(true)方法硬改成單例,那問 題來了,它的ID是什么? 很簡(jiǎn)單,它的唯一ID就是這個(gè)動(dòng)態(tài)創(chuàng)建的配置實(shí)例本身。BeanBox box1=new BeanBox(A.class).setSingeton(true), 則每次ctx.getBeanBox(box1)就會(huì)獲得同一個(gè)A類型的單例對(duì)象。當(dāng)然,也可以用ctx.bind("id1",box1),則相當(dāng)于手 工給它綁定了一個(gè)ID值"id1",可以用getBean("id1")來獲取它。jBeanBox沒有自動(dòng)掃描、預(yù)創(chuàng)建單例之類的功能,所以它的啟動(dòng)非 ??焖?。如果有人有自動(dòng)掃描、預(yù)創(chuàng)建單例、預(yù)綁定ID名之類的需求,必須手工編寫一個(gè)工具類來實(shí)現(xiàn)這個(gè)目的(jBeanBox暫不提供),例如在程序運(yùn)行 開始時(shí)調(diào)用一下ctx.getBean(A.class)就會(huì)在上下文中暫存一個(gè)A的單例類,下次訪問時(shí)會(huì)直接從緩存中取。
jBeanBox的Java方式配置
示例一只是籠統(tǒng)演示了一下jBeanBox的Java方式配置,現(xiàn)在再回過頭來詳細(xì)介紹一下它的Java方式配置:
- setAsValue(Object) 將當(dāng)前BeanBox配置成一個(gè)常量值,等同于setTarget(Obj)+setPureVale(true)
- setPrototype(boolean) 如參數(shù)為true時(shí)表示它是一個(gè)非單例,與setSingleton方法作用相反
- injectConstruct(Class, Object...) 設(shè)定構(gòu)造器注入,參數(shù)分別是類、構(gòu)造器參數(shù)類型們、參數(shù)們
- injectMethod(String, Object...) 設(shè)定某個(gè)方法注入,參數(shù)分別是方法名、參數(shù)類型們、參數(shù)們
- addAopToMethod(Object, Method) 對(duì)某個(gè)方法添加AOP,參數(shù)分別是AOP類或?qū)嵗⒎椒?/li>
- addMethodAop(Object, String, Class...) 對(duì)某個(gè)方法添加AOP,參數(shù)分別是AOP類或?qū)嵗⒎椒?、參?shù)類型們
- addBeanAop(Object, String) 對(duì)整個(gè)Bean添加AOP,參數(shù)分別是AOP類或?qū)嵗⒎椒ㄒ?guī)則(如"setUser*"),
- setPostConstruct(String) 設(shè)定一個(gè)PostConstruct方法名,效果等同與@PostConstruct注解
- setPreDestroy(String) 設(shè)定一個(gè)PreDestroy方法名,效果等同與@PreDestroy注解
- injectField(String, BeanBox) 注入一個(gè)字段,參數(shù)是字段名、BeanBox實(shí)例,它的等效注解是@INJECT
- setProperty(String, Object) 等同于injectValue方法
- injectValue(String, Object) 注入一個(gè)字段,參數(shù)是字段名、對(duì)象實(shí)例,可與它類比的注解是@VALUE
- setTarget(Object) 注定當(dāng)前Bean的目標(biāo),另外當(dāng)bind("7",User.class)時(shí),setTarget("7")就等同于setTarget(User.class)
- setPureValue(boolean) 表示target不再是目標(biāo)了,而是作為純值返回,上行的"7"就會(huì)返回字符串"7"
- setBeanClass(Class) 設(shè)定當(dāng)前BeanBox的最終目標(biāo)類,所有的配置都是基于這個(gè)類展開
- setSingleton(Boolean) 與setPrototype作用相反
- setConstructor(Constructor) 設(shè)定一個(gè)構(gòu)造器
- setConstructorParams(BeanBox[]) 設(shè)定構(gòu)造器的參數(shù),與上行聯(lián)用
- setPostConstruct(Method) 設(shè)定一個(gè)PostConstruct方法,效果等同與@PostConstruct注解
- setPreDestroy(Method) 設(shè)定一個(gè)PreDestroy方法名,效果等同與@PreDestroy注解
Java方式配置,對(duì)于BeanBox來說,還有兩個(gè)特殊的方法create和config,如下示例:
public static class DemoBox extends BeanBox {
public Object create(Caller caller) {
A a = new A();
a.field1 = caller.getBean(B.class);
return a;
}
public void config(Object o, Caller caller) {
((A) o).field2 = caller.getBean(C.class);
}
}
上例表示DemoBox中創(chuàng)建的Bean是由create方法來生成,由config方法來修改。create和config方法中的Caller參數(shù)可以省略,如果不需要利用這個(gè)Caller參數(shù)進(jìn)行加載其它Bean的話。
jBeanBox的AOP(面向切面編程)
jBeanBox功能大都可以用Java配置或注解配置兩種方式來實(shí)現(xiàn),同樣地,它對(duì)AOP的支持也有兩種方式:
Java方式AOP配置
- someBeanBox.addMethodAop(Object, String, Class...) 對(duì)某個(gè)方法添加AOP,參數(shù)分別是AOP類或?qū)嵗?、方法名、參?shù)類型們
- someBeanBox.addBeanAop(Object, String) 對(duì)整個(gè)Bean添加AOP,參數(shù)分別是AOP類或?qū)嵗?、方法?guī)則(如"setUser*")
- someBeanBoxContext.addGlobalAop(Object, Object, String);對(duì)整個(gè)上下文添加AOP規(guī)則,參數(shù)分別是AOP類或?qū)嵗?、類或類名?guī)則、方法名規(guī)則。
以上三個(gè)方法分別對(duì)應(yīng)三種不同級(jí)別的AOP規(guī)則,第一個(gè)方法只針對(duì)方法,第二個(gè)方法針對(duì)整個(gè)類,第三個(gè)方法針對(duì)整個(gè)上下文。以下是一個(gè)AOP的Java配置示例:
public static class AopDemo1 {
String name;
String address;
String email;
//getter & setters...
}
public static class MethodAOP implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "1";
return invocation.proceed();
}
}
public static class BeanAOP implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "2";
return invocation.proceed();
}
}
public static class GlobalAOP implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "3";
return invocation.proceed();
}
}
public static class AopDemo1Box extends BeanBox {
{
this.injectConstruct(AopDemo1.class, String.class, value("0"));
this.addMethodAop(MethodAOP.class, "setName", String.class);
this.addBeanAop(BeanAOP.class, "setAddr*");
}
}
@Test
public void aopTest1() {
JBEANBOX.bctx().bind("3", GlobalAOP.class);
JBEANBOX.bctx().addGlobalAop("3", AopDemo1.class, "setEm*");
AopDemo1 demo = JBEANBOX.getBean(AopDemo1Box.class);
demo.setName("--");
Assert.assertEquals("1", demo.name);
demo.setAddress("--");
Assert.assertEquals("2", demo.address);
demo.setEmail("--");
Assert.assertEquals("3", demo.email);
}
上面的命名規(guī)則采用“*”做為模糊匹配字符,代表任意長(zhǎng)度、任意字符。
注解方式AOP配置
注解方式AOP只有兩種類型,針對(duì)方法的和針對(duì)類的,沒有針對(duì)上下文的。 注解方式需要用到一個(gè)特殊的注解@AOP,它是用來自定義自已的AOP注解用的,使用示例如下:
public static class Interceptor1 implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "1";
return invocation.proceed();
}
}
public static class Interceptor2 implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "2";
return invocation.proceed();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@AOP
public static @interface MyAop1 {
public Class value() default Interceptor1.class;
public String method() default "setNa*";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@AOP
public static @interface MyAop2 {
public Class value() default Interceptor2.class;
}
@MyAop1
public static class AopDemo1 {
String name;
String address;
public void setName(String name) {
this.name = name;
}
@MyAop2
public void setAddress(String address) {
this.address = address;
}
}
@Test
public void aopTest1() {
AopDemo1 demo = JBEANBOX.getBean(AopDemo1.class);
demo.setName("--");
Assert.assertEquals("1", demo.name);
demo.setAddress("--");
Assert.assertEquals("2", demo.address);
}
本文所說的AOP是針對(duì)Aop alliance聯(lián)盟標(biāo)準(zhǔn)的接口來說的,它已經(jīng)被包含在jBeanBox中,無需再單獨(dú)引入(當(dāng)然重復(fù)引入也不會(huì)有問題)。Aop alliance聯(lián)盟標(biāo)準(zhǔn)是比較有用的一個(gè)接口,實(shí)現(xiàn)了各種AOP實(shí)現(xiàn)之間的互換性,基于它,jBeanBox可以替換掉Spring的內(nèi)核而使用它的聲 明式事務(wù),這種互換性能夠?qū)崿F(xiàn)的前提就是因?yàn)镾pring的聲明式事務(wù)實(shí)現(xiàn)(如TransactionInterceptor)也實(shí)現(xiàn)了Aop alliance聯(lián)盟標(biāo)準(zhǔn)接口MethodInterceptor。
jBeanBox從2.4.8版本起,AOP功能大副削減,去掉了不常用的前置、后置、異常切面功能,只保留了支持AOP alliance聯(lián)盟標(biāo)準(zhǔn)接口MethodInterceptor的功能(注意在CGLIB也有一個(gè)同名的接口,不要混淆)。實(shí)現(xiàn)了 MethodInterceptor接口的類,通常稱為Interceptor,但在jBeanBox中圖省事,也把它稱為AOP,畢竟寫成 addBeanAop要比寫成addBeanInterceptor簡(jiǎn)潔一些。
關(guān)于循環(huán)依賴
jBeanBox具備循環(huán)依賴檢測(cè)功能,如果發(fā)現(xiàn)循環(huán)依賴注入(如A構(gòu)造器中注入B,B的構(gòu)造器中又需要注入A),將會(huì)拋出BeanBoxException運(yùn)行時(shí)異常。 但是,以下這種字段或方法中出現(xiàn)的循環(huán)依賴注入在jBeanBox中是允許的:
public static class A {
@Inject
public B b;
}
public static class B {
@Inject
public A a;
}
A a = JBEANBOX.getBean(A.class);
Assert.assertTrue(a == a.b.a);//true
jBeanBox支持多上下文和Bean生命周期
jBeanBox支持多個(gè)上下文實(shí)例(BeanBoxContext),每個(gè)上下文實(shí)例都是互不干攏的。例如一個(gè)User.class可以在3個(gè)上 下文中各自用不同的配置方式(注解、Java)生成3個(gè)單例,這3個(gè)“單例”都是相對(duì)于當(dāng)前上下文唯一的,它們的屬性與各自的配置有關(guān)。
JBEANBOX.getBean()方法是利用了一個(gè)缺省的全局上下文,可以用JBEANBOX.bctx()方法來獲取,所以如果一個(gè)項(xiàng)目中不 需要用到多個(gè)上下文,可以直接使用JBEANBOX.getBean()方法來獲取實(shí)例,這樣可以節(jié)省一行創(chuàng)建一個(gè)新上下文的代碼。
BeanBoxContext的每個(gè)實(shí)例都在內(nèi)部維護(hù)著配置信息、單例緩存等,在BeanBoxContext實(shí)例的close方法被調(diào)用后,它的 配置信息和單例被清空,當(dāng)然,在清空之前,所有單例類的PreDestroy方法(如果有的話)被調(diào)用運(yùn)行。所以對(duì)于需要回調(diào)PreDestroy方法的 上下文來說,在關(guān)閉時(shí)不要忘了調(diào)用close方法。對(duì)于缺省的全局上下文來說就是JBEANBOX.close()方法。
BeanBoxContext的常用方法詳解:
- reset() 這個(gè)靜態(tài)方法重置所有靜態(tài)全局配置,并調(diào)用缺省上下文實(shí)例的close方法。
- close() 先調(diào)用當(dāng)前上下文緩存中單例實(shí)例的PreDestroy方法(如果有的話),然后清空當(dāng)前上下文的緩存。
- getBean(Object) 根據(jù)目標(biāo)對(duì)象(可以是任意對(duì)象類型),返回一個(gè)Bean,如果找不到則拋出異常
- getInstance(Class) 根據(jù)目標(biāo)類T,返回一個(gè)T類型的實(shí)例, 如果找不到則拋出異常
- getBean(Object, boolean) 根據(jù)目標(biāo)對(duì)象,返回一個(gè)Bean, 第二個(gè)參數(shù)為false時(shí)如果找不到則返回Empty.class
- getInstance(Class, boolean) 根據(jù)目標(biāo)類T,返回一個(gè)T類型的實(shí)例, 第二個(gè)參數(shù)為false時(shí)如果找不到則返回Empty.class
- bind(Object, Object) 給目標(biāo)類綁定一個(gè)ID,例如:ctx.bind("A","B").bind("B".C.class),則以后可以用getBean("A")獲取C的實(shí)例
- addGlobalAop(Object, String, String) 在當(dāng)前上下文環(huán)境添加一個(gè)AOP(詳見AOP一節(jié)),第二個(gè)參數(shù)為類名模糊匹配規(guī)則,如"com.tom.*"或"*.tom"等,*號(hào)只允許出現(xiàn)在頭尾 (可以同時(shí)出現(xiàn),也可以一個(gè)不出現(xiàn)), 第三個(gè)參數(shù)為方法名模糊匹配規(guī)則,如"setUser*"或"*user"等。
- addGlobalAop(Object, Class, String) 在當(dāng)前上下文環(huán)境添加一個(gè)AOP,第二個(gè)參數(shù)為根類,第三個(gè)參數(shù)為方法名模糊匹配規(guī)則
- getBeanBox(Class) 獲取一個(gè)類的BeanBox實(shí)例,例如一個(gè)注解標(biāo)注的類,可以用這個(gè)方法獲取BeanBox實(shí)例,然后再添加、修改它的配置,這就是固定配置和動(dòng)態(tài)配置的結(jié)合運(yùn)用。
- setAllowAnnotation(boolean) 設(shè)定是否允許讀取類中的注解,如果設(shè)為flase的話,則jBeanBox只允行使用純Java配置方式。默認(rèn)true。
- setAllowSpringJsrAnnotation(boolean) 設(shè)定是否允先讀取類中JSR330/JSR350和Spring的部分注解,以實(shí)現(xiàn)兼容性。默認(rèn)true。
- setValueTranslator(ValueTranslator) 設(shè)定對(duì)于@VALUE注解中的內(nèi)容,如何解析它,例如@VALUE("#user"),系統(tǒng)默認(rèn)返回"#user"字符串,如果需要不同的解析,例如讀取 property文本中的值,則需要自已設(shè)定一個(gè)實(shí)現(xiàn)了ValueTranslator接口的實(shí)例。
jBeanBox的性能
以下為jBeanBox的性能與其它IOC工具的對(duì)比(只對(duì)比DI注入功能,搭建一個(gè)由6個(gè)對(duì)象組成的實(shí)例樹),可見jBeanBox創(chuàng)建非單例的 速度大約為Guice的一半,但依然要比Spring快得多,是Spring的45倍左右。測(cè)試程序詳見:[di-benchmark](https://github.com/drinkjava2/di-benchmark)
Runtime benchmark, fetch new bean for 500000 times:
---------------------------------------------------------
Vanilla| 31ms
Guice| 1154ms
Feather| 624ms
Dagger| 312ms
Genie| 609ms
Pico| 4555ms
jBeanBoxNormal| 2075ms
jBeanBoxTypeSafe| 2371ms
jBeanBoxAnnotation| 2059ms
SpringJavaConfiguration| 92149ms
SpringAnnotationScanned| 95504ms
Split Starting up DI containers & instantiating a dependency graph 4999 times:
-------------------------------------------------------------------------------
Vanilla| start: 0ms fetch: 0ms
Guice| start: 1046ms fetch: 1560ms
Feather| start: 0ms fetch: 109ms
Dagger| start: 46ms fetch: 173ms
Pico| start: 376ms fetch: 217ms
Genie| start: 766ms fetch: 247ms
jBeanBoxNormal| start: 79ms fetch: 982ms
jBeanBoxTypeSafe| start: 0ms fetch: 998ms
jBeanBoxAnnotation| start: 0ms fetch: 468ms
SpringJavaConfiguration| start: 51831ms fetch: 1834ms
SpringAnnotationScanned| start: 70712ms fetch: 4155ms
Runtime benchmark, fetch singleton bean for 5000000 times:
---------------------------------------------------------
Vanilla| 47ms
Guice| 1950ms
Feather| 624ms
Dagger| 2746ms
Genie| 327ms
Pico| 3385ms
jBeanBoxNormal| 188ms
jBeanBoxTypeSafe| 187ms
jBeanBoxAnnotation| 171ms
SpringJavaConfiguration| 1061ms
SpringAnnotationScanned| 1045ms
雖然IOC工具大多應(yīng)用在單例場(chǎng)合,性能大家都差不多(因?yàn)閺木彺嬷腥?,但是如果遇到必須生成非單例的場(chǎng)合,例如每次訪問生成一個(gè)新的頁(yè)面實(shí)例,這時(shí)候Spring就不夠看了, 至于啟動(dòng)速度,則更是慢到離譜了。
以上就是對(duì)jBeanBox的介紹,沒有別的文檔了,因?yàn)楫吘顾暮诵脑创a也只有1千多行(第三方工具如CGLIB、JSR接口等不算在內(nèi)),有問題去看看它的源碼可能更簡(jiǎn)單一些。
更多關(guān)于jBeanBox的用法還可以在jSqlBox項(xiàng)目中看到它的運(yùn)用(數(shù)據(jù)源的配置、聲明式事務(wù)示例等)。
