征求IOC/AOP微形开源项目jBeanBox合作者
方永贞
2023-12-01
这是一个微形开源项目,目标是使用尽可能少的Java类实现全功能的IOC和AOP功能,有兴趣参加的朋友可以跟贴,贡献者将列入作者名单,谢谢!
项目的目的是取消XML配置文件而用纯Java类代替,Spring本身越来越臃肿,替我们自做主张集成了自以为最好的一条龙服务,这本身没什么,可以自取所需。 但是它最大问题是采用XML静态配置,导致需要动态修改配置功能时灵活性不够,注解的引入没有根本性变化。 jBeanBox项目只实现最基本的IOC和AOP功能以满足功能单一原则。用尽可能少的源码实现,基本思路可参见我的另一贴"JSP页面布局工具jWebBox升级到2.0版" http://www.iteye.com/topic/1143195, 利用Java类本身作为配置文件,来获得免学习、高灵活性、高可定制性、支持UML图、类可继承、类名检查、类名重构、代码提示等优点,且得益于对象化和微型化设计(尽可能不要超过10个Java类),本IOC/AOP工具有支持动态更改配置、启动快速、适合移植到移动开发等特点。 项目采用BSD协议,项目地址为https://sourceforge.net/projects/jbeanbox/
(补充一下,这两天研究Spring才发现Spring3.0已经有了用JAVA类代替XML配置的做法,实现了编译器类名检查,但是仔细一看,晕倒,它使用了一种特殊的JAVA类,又引入了四个新的注解,注解加JAVA,不伦不类。配置类不能继承重用、而且最大问题是把语句写死在Java配置类里,如果运行期要动态生成、修改配置类怎么办? 看来三种配置方式还不够,将来Spring还会增加第四种配置方式。 于2016年2月13日)
(这两天没人跟贴就在原贴基础上再更新一遍,第一版jBeanBox已上传到项目目录https://sourceforge.net/projects/jbeanbox/下,有兴趣的可以当下来看一看源码,目前源码220行,已实现了设值注入、构造器注入、静态工厂注入、实例工厂注入四种IOC,因时间关系还只是一个框架,但用例部分已经全部跑通,感觉比XML配置方便多了,调试时经常要变动类名,利用重构功能Eclipse自动全部更新,不用担心类名拼写出错了,但是方法名拼错就没办法了,JDK1.8以下没有方法变量支持。 目前实现了IOC所有注入方式,只不过都是多例的,还要改成默认单例的,要和不擅长的多线程和单例注册表打交道了,AOP功能也不太了解,有时间再加上去。个人感觉用纯Java代理Box类代替XML作为配置文件可以成为一种设计模式,对简化编程非常有成效,要知道Spring IOC和AOP内核一共有700多个类3.6M,要压缩成只有一个类(估计项目最终完成后不超过1000行)是个什么概念! 源码写的很烂,没加注释,但好在目前只有两百行,读起来还是很容易的。 于2016年2月15日)
以下是对此项目的描述,用例部分已调试通过(目前是多例的),AOP功能如何还待添加。
jBeanBox is a micro-scale but full functional IOC & AOP tool, it has no XML files(Use "BeanBox" classes to replace), no annotations. 1 Java class do all the jobs Spring IOC/AOP core did. jBeanBox is an open source software follows BSD license.
Why jBeanBox?
Current IOC/AOP frameworks problem:
1) Spring, HiveMind and other IOC/AOP tools use XML as configuration file: XML is hard to write and maintenance, hard to present complicated features like extends, map, sets injection, and not flexible to create/change configuration in run-time.
(I just notice from Spring3.0, Spring imported a kind of special JAVA class to replace XML, but that's a wired way, Java mixed up with annotations, it's not OO designed, and can not create/modify configuration at run time. )
2) Guice and other IOC/AOP tools depend on annotation: write annotation in bean class is an invasion; IOC/AOP tool should no need to change anything in bean classes.
3) PicoContainer, no AOP function, Bean configurations cannot be re-used.
jBeanBox is lightest IOC/AOP tool, which function only focus on IOC/AOP. It's small size but full functional, source code are short and easy to understand. It’s ideal to mobile device developing, and of cause, can use anywhere where an IOC/AOP tool needed.
Key features of jBeanBox:
1) Simple, function only focuses on IOC and AOP. No XML files, no any annotations, use pure Java classes to replace XML, these Java classes be called "BeanBox" (similar like "Box" concept in another open source project "jWebBox", it looks like if XML configurations become complicated, use a "Box" to replace it often make things simple and flexible.)
2) As using Java class to store configurations, IDE can help to find class name spelling mistake, UML tool can used to draw bean relationship graph, Bean Boxes can organized in packages according its function.
3) No conflict with other bean containers, it can be used as foundation of whole project or only to manage few Beans in application.
4) Friend to test, as configurations are stored in Java BeanBox tree, only Beans included in this tree will be created and injected, so it starts quick. It’s also friend to team work, user A and user B can have their own BeanBoxes/Beans and test it separately, after tested just copy these beans together.
5) Bean configurations (BeanBox classes) are created dynamically, it's easy to modify or create configurations at run-time. For example, change bean create method from singleton to prototype, inject different bean instance, add or remove AOP pointcuts at run-time.
6) Small size, only 1 java file (and 2 .jar libs) needed, ideal for mobile device applications.
7) jBeanBox tool only implements IOC and AOP function, no intend to add more functions like Transactions, Hibernate, MVC support. User should assembly these functions in project by themselves or to find a one-site solution project at other places.
How to use it:
This project be packaged as .war file, you can import it into Eclipse as a web project to see the source code, and run MainTest.java to see the test result, why packed in .war format is because there are 2 lib files "asm-3.x.x.jar" and "cglib-2.x.jar" are necessary, it's convenient to import to Eclipse. And you can also download new version of asm-3.x.x.jar and cglib-2.x.jar from their project homepages.
Typically a project using jBeanBox, need prepare below files:
1. Your bean or interface classes, for example, below 3 bean classes and 1 factory class:
public class Company {
private String name;
//getter & setter......
}
public class OrderItem {
private String itemName;
private Double price;
//getter & setter......
public OrderItem(String itemName, Double price) {
this.itemName = itemName;
this.price = price;
}
public void printItemInfo() {
System.out.println(itemName + " $" + price);
}
}
public class Order {
private String orderNO;
private OrderItem orderItem1, orderItem2, orderItem3;
private Company company;
//getter & setter......
public void printALlItems() {
System.out.println("OrderNO:" + orderNO);
System.out.println("Company:" + company.getName());
orderItem1.printItemInfo();
orderItem2.printItemInfo();
orderItem3.printItemInfo();
}
}
public class OrderItemFactory {
private Boolean hidePrice;
public OrderItemFactory(Boolean hidePrice) {
this.hidePrice = hidePrice;
}
public static OrderItem createOrderItem(String itemName, Double price) {
return new OrderItem(itemName, price);
}
public OrderItem createOrderItem2(String itemName, Double price) {
if (hidePrice)return new OrderItem(itemName, 0.0);
else return new OrderItem(itemName, price);
}
}
2. Configuration classes (to replace XML):
class OrderTemplate extends BeanBox {
{ this.setBeanClass(Order.class);
this.setProperty("orderNO", "PO#20160214");// setter inject value
this.setProperty("company", new BeanBox(Company.class).setProperty("name", "Dog Shop"));// setter inject bean
this.setProperty("orderItem1", new BeanBox(OrderItem.class, new Object[] { "Dog1", 77.99 }));// setter & constructor inject
this.setStaticFactory("orderItem2", OrderItemFactory.class, "createOrderItem", new Object[] { "Dog2", 88.99 });// static factory inject
BeanBox factory = new BeanBox(OrderItemFactory.class, new Object[] { true });// constructor inject
this.setInstanceFactory("orderItem3", factory, "createOrderItem2", new Object[] { "Dog3", 99.99 });// instance factory inject
}
}
public class OrderBox extends OrderTemplate {
{ this.setProperty("company", ((BeanBox) getProperty("company")).setProperty("name", "Dog Store"));// modify property
}
}
3. At last, get bean instance by call getBean method:
public static void main(String[] args) {
Order order = (Order) new OrderBox().getBean();
order.printALlItems();
}
For this example, below is output result:
OrderNO:PO#20160214
Company:Dog Store
Dog1 $77.99
Dog2 $88.99
Dog3 $0.0