jBeanBox是一个微形(只有单个Java文件约1000行源码)但功能较齐全的IOC/AOP工具,利用了Java的初始化块实现的Java配置代替XML,比目前Spring或Guice的Java配置更简单更实用。jBeanBox遵循BSD-3开源协议,目前的版本是jBeanBox2.2。
1)Spring,HiveMind的和其他IOC/AOP工具使用XML作为配置文件:XML不支持类名称拼写检查和IDE重构,很难在运行时更改
配置。(从Spring3.0开始使用基于一种Java配置来取代XML,但Java配置与与注解混用,复杂且不支持配置的继承重用,如果
使用方法名作为Bean的ID则不支持类名的IDE重构。), 我的看法是,作为一个IOC/AOP工具来说它太大太复杂了。
2)Guice和其他依赖于注解的IOC/AOP项目:注解是一种拉式注入,入侵性强,不支持第三方库,IOC/AOP工具不应该完全依赖于更改Java源码。
1)简单,仅一个Java文件做所有的IOC/AOP工作,没有XML,只有1个注释。易于学习、使用和修改源代码。
2)使用Java来代替XML,其实现比Spring或Guice的Java配置更简单更自然,支持配置的继承重用。
3)jBeanBox是一个麻雀虽小、功能俱全的IOC/AOP工具,旨在小项目中取代Spring IoC/AOP内核,它具有的主要功能有:
*以Box封装为基础的Java配置类(称为“BeanBox”)来代替XML,配置可以在运行期创建和修改。
*Bean实例延迟初始化(如Guice类似)
*单例/多例支持,默认情况下所有实例为单例(与Spring类似)
*单例缓存
*内置AOP和AspectJ支持
*多种注射机制:
推式注入:值注入,实例注入,构造方法注入,静态工厂注入,实例工厂注入 (与Spring传统XML注入类似)
拉式注入:利用@InjectBox注解 (与Guice和Spring的注解注入类似)
*多上下文的支持(除了默认的全局范围上下文外,它支持多个上下文,类似于Spring中创建多个ApplicationContext实例)
*支持Bean生命周期管理(postConstruction和preDestory方法支持)
从jBeanBox项目网站下载jbeanbox-x.x.jar或jbeanbox-x.x-src.jar,并把以下4个包放入lib目录:
http://central.maven.org/maven2/aopalliance/aopalliance/1.0/aopalliance-1.0.jar
http://central.maven.org/maven2/asm/asm/3.3.1/asm-3.3.1.jar
http://central.maven.org/maven2/org/aspectj/aspectjrt/1.8.9/aspectjrt-1.8.9.jar
http://central.maven.org/maven2/cglib/cglib/2.2.2/cglib-2.2.2.jar
(项目尚待按Meven目录格式整理,但目前可从项目页下载打包好的的Demo_jBeanBoxx.x.war查看示例)
基本用法: 示例1 - 基本用法(各种注入):
public class OrderBox extends BeanBox {//这是用于取代XML的JAVA配置类 { //setClassOrValue(Order.class); //目标类或数值的设定,如使用getBean()调用可省略 setProperty("orderNO", "PO#20160214");//值注入 setProperty("company", CompanyBox.class);// Inject a bean setProperty("orderItem1", new BeanBox(OrderItem.class,"Dog1",77.99));//构造器注入 setStaticFactory("orderItem2", OrderItemFactory.class, "createOrderItem", "Dog2", 88.99);//静态工厂注入 BeanBox factory = new BeanBox(OrderItemFactory.class, new CompanyBox(), false); setBeanFactory("orderItem3", factory, "createOrderItem2", new CompanyBox(), "Dog3", 99.99);//实例工厂注入 } public static class CompanyBox1 extends BeanBox { { setClassOrValue(Company.class); setProperty("name", "Company1"); } } public static class CompanyBox extends CompanyBox1 {//配置的继承 { setProperty("name", "Company2");//属性覆盖 } } } public class Tester { public static void main(String[] args) { Order order = BeanBox.getBean(Order.class); order.printALlItems(); System.out.println("Order bean is a SingleTon? " + (order == new OrderBox().getBean()));//true } }
以上"Company", "Order", "OrderItem", "OrderItemFactory"为普通Java类,源码见"Demo_jBeanBox2.1.war"示例。
示例2: AOP & Aspectj 演示
public class Tester { private Iitem item; public void setItem(Iitem item) { this.item = item; } public void doPrintItem() { item.doPrint(); } public static void main(String[] args) { BeanBox advice = new BeanBox(AOPLogAdvice.class).setProperty("name", "AOP Logger"); BeanBox.defaultContext.setAOPAround("examples.example2_aop.//w*", "doPrint//w*", advice, "doAround"); BeanBox advice2 = new BeanBox(AspectjLogAdvice.class).setProperty("name", "AspectJ Logger"); BeanBox.defaultContext.setAspectjAfterReturning("examples.example2_aop.//w*", "doPrint//w*", advice2, "doAfterReturning"); Tester t = new BeanBox(Tester.class) { { this.setProperty("item", ItemImpl.class); } }.getBean(); t.doPrintItem(); } }
BeanBox.defaultContext是个单例类全局变量,对于无需创建多个上下文实例的小型项目可以直接使用这个全局实例变量以简化编码。
示例3: @injectBox注解和上下文演示
此项目有且仅有一个注解@injectBox,注入1到7为注解注入,属于拉式注入,注入8和9为传统无侵入的推式注入。
可以看出,注解的引入可极大简化源码,提高开发效率,但代价是难以理解和维护,且不支持无源码的第三方库。
public class Tester { @InjectBox(A.StrBox.class) String s1;// Use StrBox.class @InjectBox(A.class) String s2;// Use A.StringBox.class (or A.StringBox2.class, 2 to 8 depends context setting) @InjectBox(B.class) String s3;// Use B$S3Box.class @InjectBox C c4;// Use CBox.class @InjectBox String s5;// Use TesterBox$StringBox.class @InjectBox(required = false) D d6;// Use Config$DBox.class (or Config2$DBox2) @InjectBox(required = false) E e7;// Use Config$E7Box.class (or Config2$E7Box2) private String s8; // injected by field, not suitable for Proxy bean private String s9; // injected by setter method public void setS9(String s9) { this.s9 = s9; } public void print() { System.out.println(s1); System.out.println(s2); System.out.println(s3); System.out.println((c4 == null) ? null : c4.value); System.out.println(s5); System.out.println((d6 == null) ? null : d6.value); System.out.println((e7 == null) ? null : e7.value); System.out.println(s8); System.out.println(s9); System.out.println(this); } public static void main(String[] args) { Tester t = BeanBox.getBean(Tester.class); t.print(); BeanBoxContext ctx = new BeanBoxContext(Config2.class).setBoxIdentity("Box2"); Tester t3 = ctx.getBean(Tester.class); t3.print(); } }