jBeanBox是一个微形(只有单个Java文件约1000行源码)但功能较齐全的IOC/AOP工具,利用了Java的初始化块实现的Java配
置代替XML,比目前Spring或Guice的Java配置更简单更实用。jBeanBox遵循BSD-3开源协议,目前的版本是jBeanBox2.2。
其他一些IOC / AOP框架问题:
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源码。
jBeanBox的特点:
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方法支持)
基本用法: 示例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();
}
}
示例4: Bean的生命周期管理(PostConstructor和PreDestory方法回调)
public class Tester {
private String name;
public void init() {
name = "Sam";
}
public void destory() {
System.out.println("Bye " + name);
}
public static class TesterBox extends BeanBox {
{
setPostConstructor("init");
setPreDestory("destory");
}
}
public static void main(String[] args) {
BeanBox.getBean(Tester.class);
BeanBox.defaultContext.close();// print Bye Sam
}
}
示例5: 利用jBeanBox取代Spring内核实现无XML的声明式事务
声明式事务是AOP的典型运用场合,基本原理是利用线程局部变量来管理连接,AOP的特点就是服务和内核是插拔式设计,内核和
服务可以单独使用。Spring中提供的一些业务支持理论上都可以抽取出来在其它IOC/AOP工具上使用,如果抽取不出来,说明它
绑死在Spring内核上了,这与它的设计理念是不符的。本着不重新发明轮子的原则,此示例将Spring中的声明式事务服务抽取出
来,与jBeanBox整合,也就是说这一次的整合只利用了Spring的事务服务,而不使用它的IOC/AOP内核 ,很诡异的组合,但目
的很明确:取消XML配置。以下是jBeanBox整合了c3p0数据池+JDBCTemplate+Spring声明式事务的一个例子,实测通过:
public class TesterBox extends BeanBox {//用于取代XML的JAVA配置类
static {//在默认全局单例上下文上设置AOP事务切面
BeanBox.defaultContext.setAOPAround("examples.example5_transaction.Test\\w*", "insert\\w*", new TxInterceptorBox(), "invoke");
}
static class DSPoolBeanBox extends BeanBox {//C3P0数据池配置,为单例,下同
{
setClassOrValue(ComboPooledDataSource.class);
setProperty("jdbcUrl", "jdbc:mysql://127.0.0.1:3306/test?user=root&password=yourPWD&useUnicode=true&characterEncoding=UTF-8");
setProperty("driverClass", "com.mysql.jdbc.Driver");// your jdbc driver name
setProperty("maxPoolSize", 10);
}
}
static class TxManagerBox extends BeanBox {//事务管理器配置,从Spring中抽取的
{
setClassOrValue(DataSourceTransactionManager.class);
setProperty("dataSource", new DSPoolBeanBox());
}
}
static class TxInterceptorBox extends BeanBox {//AOP事务切面处理类,从Spring中抽取的
{
Properties props = new Properties();
props.put("insert*", "PROPAGATION_REQUIRED");
setConstructor(TransactionInterceptor.class, new TxManagerBox(), props);
}
}
public static class JdbcTemplateBox extends BeanBox {//JDBC模板配置,可换成dbUtils等
{
setConstructor(JdbcTemplate.class, new DSPoolBeanBox());
}
}
}
public class Tester {//测试类
@InjectBox
private JdbcTemplate dao;//注入JdbcTemplateBox配置类生成的实例
public void insertUser() {
dao.execute("insert into users values ('User1')");
int i = 1 / 0; //抛出运行期错误,导致事务回滚
dao.execute("insert into users values ('User2')");
}
public static void main(String[] args) {
Tester tester = BeanBox.getBean(Tester.class);//从默认上下文获取类实例
tester.insertUser();
}
}
示例5中需要额外用到如下第三方包:
c3p0-0.9.1.2.jar
commons-logging-api-1.0.4.jar
mysql-connector-java-5.1.5.jar
spring-aop-3.2.16.RELEASE.jar
spring-beans-3.2.16.RELEASE.jar
spring-core-3.2.16.RELEASE.jar
spring-jdbc-3.2.16.RELEASE.jar
spring-tx-3.2.16.RELEASE.jar
可从Maven网站按包名搜索下载,或从jBeanBox项目中下载示例项目Demo_jBeanBox2.2.war,其中已包含了以上所有第三方包。