`
raymond2006k
  • 浏览: 295051 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

我的开发经验分享(一)-Spring业务bean零配置

阅读更多

 注:在JavaEye注册不久,前些天这篇文章发布在了blog首页,似乎大家都在论坛活动多,因此转移到论坛这边分享

关键字: spring 动态bean管理 零配置

1. Spring业务bean配置的困扰

    利用Spring IoC 容器进行项目开发的一个重要工作就是在 applicationContext.xml 中进行bean管理。然而,业务bean(BO或Service),DAO bean的配置量随项目的功能规模增长而增长,对于大型项目而言,庞大的 bean配置文件维护起来极为痛苦。例如:

  1. <!-- 业务对象 -->        
  2. <bean id="authService" parent="baseTransactionProxy">        
  3.     <property name="target">        
  4.         <bean class="com.sr.jsfuser.service.AuthorityService">        
  5.             <property name="authDao" ref="authDao" />        
  6.         </bean>        
  7.     </property>        
  8. </bean>        
  9.         
  10. <bean id="userService" parent="baseTransactionProxy">        
  11.     <property name="target">             
  12.         <bean class="com.sr.jsfuser.service.pojo.UserService">        
  13.             <property name="userDao" ref="userDao" />        
  14.         </bean>        
  15.     </property>        
  16. </bean>        
  17. <!-- 数据访问对象 -->        
  18. <bean id="authDao" class="com.sr.jsfuser.dao.jdbc.AuthorityDao">        
  19.     <property name="dataSource" ref="dataSource" />        
  20. </bean>        
  21.         
  22. <bean id="userDao" class="com.sr.jsfuser.dao.jdbc.UserDao">        
  23.     <property name="dataSource" ref="dataSource" />        
  24. </bean>      

上例为两个功能的配置,鉴权(auth)和用户(user)。这种Service bean和DAO bean 的管理方式是按功能的管理方式,即one by one,配置量是
         F=f(n)
   

   其中 n 是项目中功能的数量。上例虽充分体现了Spring IoC容器依赖注入的优良特性,但配置量过大,维护和管理难度很大,不是一种最佳实践。


2. 零配置的动态Service Bean管理(ServiceFactory)  


     有没有一种既能发挥Spring优势,又能节省配置的模式呢?我们可以观察到,每个功能的Service bean的配置,只有 dao 注入是不同的,其他如Service类的命名,Service的事务管理器注入,Service类和DAO类的命名关系等都具有相似性或者完全相同;dao bean配置类似。

    因此,可以采用动态bean管理(Dynamic Bean Management)思想简化业务bean配置。动态bean管理使用新定义的 ServiceFactory 的createService方法来创建业务类Service实例, ServiceFactory  在创建时,自动进行dao创建,datasource注入等,不再需要进行bean的配置。原理如下图所示。



ServiceFactory原理有以下要点:
1) 利用了Spring ApplicationContext 的 registerBeanDefinition方法和动态bean注册技术;
2) 作为bean管理的一个规范:要求Service类实现 setDAO(DAO dao)方法,以便统一注入dao实例;
3) 作为bean管理的一个规范:调用 dao.setDatasource(datasource)方法进行数据源注入;
4) 作为bean管理的一个规范:内部使用className作为 service bean 和dao bean的内部id;
5) 作为bean管理的一个规范:ServiceFactory内获取bean实例时,都采用prototype scope


ServiceFactory内部实现序列图如下:



使用ServiceFactory 进行业务开发,代码如下:



UserService userService = (UserService)ServiceFactory.createService(UserService.class); User user = userService.findUser("admin");
 
这样,第一节中列出的spring配置片段中大量的业务bean配置将不再需要,使得配置工作量大大减少。

至于事务管理,即可使用向service注入transactionManager; 也可以使用 Spring 的
    org.springframework.transaction.interceptor.TransactionInterceptor ,
    org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator,
    org.springframework.aop.support.NameMatchMethodPointcutAdvisor
     三者配合,将 *Service类的 特定方法纳入事务范围。我们项目中使用的是后者,更为简便和松耦.


3. 通用的动态Bean管理(自定义BeanFactory类)  

    在上例中,注意新增了一个BeanFactory,区别于Spring 的 BeanFactory 接口。自定义 BeanFactory 通过 createBean(className) 进行动态bean注册和创建,
        

Object bean = BeanFactory.createBean(UserService.class);

    相当于替代了Object bean = new UserService();

  这相当于替代了 Java语言级的 new Object() ,并且使得类实例和Spring容器关联了起来,这样使用Spring的AOP配置就可以极为方便的对bean进行控制。(而上例中的ServiceFactory是该项目中利用BeanFactory的特定封装,其他项目的ServiceFactory实现可能不同,可参考实现)

4. JDK问题

     以上方案主要针对1.4。 但同样适用1.5及以上。有朋友说,1.5中用 annotation + <context:component-scan/>标签也能完成类似的工作,但那样需要在 Java 代码中写很多 annotation , 个人不偏好使用 annotation ,因为它相当于xml配置移到了 Java代码中,并且维护不方便。

分享到:
评论
29 楼 108439162 2014-01-02  
不得不说,可能博主自己觉得这样做很牛逼了。但是你忘了依赖注入的初衷是什么?就是将代码的各种new Instance()操作摘出来。项目过大。造成配置文件过多,完全可以通过按模块划分来解决。或者注解也是不错的方式,如果按照博主的想法,如果项目过大。做完一期之后,做二期的时候,需要修改功能。看到代码中的各种创建servce这简直是个噩梦。
28 楼 pikachu 2008-09-28  
raymond2006k 写道


还是你看明白了我的文章。




所以你的文章和老外的文章还是有差距的.再好的想法,不能清晰的表述,总是会带来这样那样的问题.


可以参考一下那些老外的行文,多看看他们的paper.毕竟技术类文章写作思路都是一致的,标准八股文写法是

1.概述或介绍.主要是背景,问题,所依赖技术以及主要功能
2.详述.
3.总结.使用方案后的效果,优势,同其他类似产品的比较
27 楼 raymond2006k 2008-09-28  
mazzystar 写道
这样配置文件就不完整了,配置文件中不能明确展现类之间的关系,看了之后肯定一头雾水,不如全部都零配置吧


对于业务bean, XXXService,XXXDAO,一般是byName来 autowire。
对于类之间的关系,按这种约定型设计,本来就是一目了然的。 userService当然要注入 userDAO,我想你不会把  orderDAO 注入给 userService吧。
业务bean的名称是稳定的, userService一旦确定,我想以后没有特殊理由,应该不会再改了。

数据库配置,事务配置,这些可变的信息才应该在applicationContext.xml 中配置,体现IoC思想。
26 楼 raymond2006k 2008-09-28  
flyingpigaa 写道
同意楼上观点,我们项目里spring 里bean 也超多,但并没有阅读困难。楼主是不是有点因噎废食


没有阅读困难就好,呵呵;每个项目,自己的方案用惯了就好; 没有说谁一定要替代谁。
如果有的话,或觉得配置麻烦的话,才需要参考我的方案。

我是在看Spring书籍的第三天,看到 service ,dao要一个个配置,我当时就有一个念头,我不想让程序员配置,一个都不想,我要减少他们的工作量 —— 零配置。
25 楼 raymond2006k 2008-09-28  
Readonly 写道
为什么不反思一下别人为啥不赞同你的帖子呢?反而跑去说别人的帖子如何如何,这不是典型的酸葡萄心理么...

另外关于你的方案,难道你不知道spring有autowire功能么?


唉,你还没看明白我的文章到底在讨论什么问题。

如果你是一个个配置,当然可以用 autowire 了;在你目前的用法下,OK的啊。
而我讨论的是如何不配置,零配置的问题。
24 楼 raymond2006k 2008-09-28  
bloodwolf_china 写道
我觉得这个这个注意不错啊,有点像grails中的思想,用约定替代配置。而且可以继承Spring BeanFactory写一个工厂类来生成service。


"用约定替代配置", 就是这个了。
XXXService,XXXDAO 的包名,类名制定了统一规则,正是按这个规则,可以自动为Service 找到对应的DAO类,并进行动态注入。
23 楼 raymond2006k 2008-09-28  
BeanFactory.createBean(UserService.class),
pikachu 写道

事实上构想不错,要是没有理解错的话,这个组件完成的是service,dao,transaction之间的依赖.并且将spring作为一个硕大的factory. 现在大家的问题是,为什么在更前端的代码要调用BeanFactory.createBean(UserService.class),难道不能进一步将service也注入么?


还是你看明白了我的文章。
Spring我还是看作IoC容器,
BeanFactory 代码我没贴出来吧,可能真的是漏了些材料:
/**
	 * 通过Spring容器创建bean
	 * 其中会检查bean的scope ,避免冲突。bean的scope取决与第一次创建时定义的scope。
	 * @param beanID
	 * @param beanClass
	 * @param isSingleton
	 * @return
	 */
	public static Object createBean(String beanID,Class beanClass,boolean isSingleton ) {
		
		if(!SpringContextManager.containsBean(beanID)) {
			
			if(log.isDebugEnabled())
				log.debug("bean dynamic register " + beanID +",class:" + beanClass +",scope(singleton?)" + isSingleton );
			SpringContextManager.registerBean(beanID, beanClass, isSingleton);
		}else {  //检查bean的scope ,避免冲突。bean的scope取决与第一次创建时定义的scope。
			BeanDefinition def = SpringContextManager.getBeanDefinition(beanID);
			if(isSingleton != def.isSingleton()) {
				throw new IllegalArgumentException("Can't register bean as " +  ( !def.isSingleton() ? "singleton" : "prototype")  + ", it's already registered as "
							+ (def.isSingleton() ? "singleton" : "prototype") +". Bean beanID '" + beanID  +"'");
			}
		}
		return getBean(beanID);	
	}




实际就是Spring context 的一个简单封装而已,加入动态注册功能,createBean(UserService.class),还是将对象注入IoC容器; 注入了容器,Spring 的AOP,事务等就能自动关联。
22 楼 fireflyc 2008-09-28  
你把配置文件分开不久可以了吗。
而且如果你真的想实现0配置的话也行,spring的注解支持;你现在的设计…………颇有黑代码的味道。
21 楼 MarkDong 2008-09-28  
如果说约定优于配置,那就用autowire,至少那个方式对代码是无侵入的,楼主的这种方式以后再想改为配置的,那就难了
20 楼 bloodwolf_china 2008-09-28  
我觉得这个这个注意不错啊,有点像grails中的思想,用约定替代配置。而且可以继承Spring BeanFactory写一个工厂类来生成service。
19 楼 MarkDong 2008-09-28  
并不觉得楼主的方法是个好方法,基于以下几点:
1、用配置文件的方式只在Spring初始化的时候进行一次注入就OK了,而楼主的方法每次均需要重新注入(至少从时序图上是这样显示的),这就带来了大量不必要的系统开销。
2、结合Spring插件,可以通过图形的方式很直观的看到各层之间的依赖关系,这也是为什么很多人都不推荐autowire的原因。而楼主这种方式连基本的bean配置都省略了,很可能引入一些很难追查源头的bug
18 楼 mazzystar 2008-09-28  
这样配置文件就不完整了,配置文件中不能明确展现类之间的关系,看了之后肯定一头雾水,不如全部都零配置吧
17 楼 flyingpigaa 2008-09-28  
同意楼上观点,我们项目里spring 里bean 也超多,但并没有阅读困难。楼主是不是有点因噎废食
16 楼 pikachu 2008-09-28  


事实上构想不错,要是没有理解错的话,这个组件完成的是service,dao,transaction之间的依赖.并且将spring作为一个硕大的factory.

现在大家的问题是,为什么在更前端的代码要调用BeanFactory.createBean(UserService.class),难道不能进一步将service也注入么?
15 楼 Readonly 2008-09-27  
为什么不反思一下别人为啥不赞同你的帖子呢?反而跑去说别人的帖子如何如何,这不是典型的酸葡萄心理么...

另外关于你的方案,难道你不知道spring有autowire功能么?
14 楼 raymond2006k 2008-09-27  
jones 写道
完全丧失IOC的核心理念,越改越不伦不类



今天刚看到另一网友发的贴:LightURL——打造零配置的Struts2开发, 介绍老外的一个插件的用法。

感慨啊感慨, 在JavaEye晃了一个来月真的感慨。
同样是 9-16号发的,他的贴很多网友赞同,精华贴;
我的贴很少人赞同,不赞同的回复一般都是不符合 ”Spring的标准适用模式“,没有体现IoC思想。

我分析了一下, 我们都提出了零配置的思想的实现,一个针对Struts的Action配置,一个针对Spring下的业务bean配置:

介绍老外的方案,赞成的人多; javaeyer 自己钻研的方案反对的人多.
介绍别人的方案,以易用性为判断标准; 介绍自己项目中成功的方案,以是否符合”标准模式“为判断标准。(其实未透彻理解IoC的核心价值和用法,坚持教条).
介绍apache上的方案,基本都是"不错,有机会要尝试一下 "; 介绍自己的方案,基本都是质疑之声,而又提不出信服的理由。

唉,这就是中国的软件界,感慨啊感慨。
哈哈,一笑了之。
13 楼 weizh 2008-09-27  
看来你是要OSGi,而非spring。
12 楼 raymond2006k 2008-09-27  
finalbone 写道
这种实现看起来挺别扭 到处都要显式调用Factory 另外遇到service循环引用怎么处理



我的方式是显示的 
BeanFactory.getBean(beanClass.getName());
BeanFactory.createBean(beanClass);

而"标准用法"是 context.getBean("userService");

你说说二者有什么本质区别没有? 即便连Action 的service引用都是通过配置注入的, 但你总有个地方 需要 指定
“userService”, 或者 ${userService}。
11 楼 raymond2006k 2008-09-27  
miaomiao0307 写道
我们不是应该将java代码拿到配置中,而不是将配置拿到java代码中吗?
这样还叫做注入吗


有时间看看Spring 的源代码吧,你会有所发现的。
10 楼 raymond2006k 2008-09-27  
zxbyhcsdn 写道
Object bean = BeanFactory.createBean(UserService.class);
这个???
拿还怎么体现IoC啦,
IoC的思想就是对象不去关心他依赖的其他对象,也不自己去做对象的获取.
他只是 面向 依赖的接口, 那个接口具体的指向什么对象,是IoC容器的事情.

业务逻辑模块并不需知道更不必调用组件框架的服务,例如不用关心和调用其factory或lookup其directory或context等。软件的组装部署和配置完全是由Ioc容器反过来主动控制业务逻辑模块来安排。Michael Mattson用所谓的好莱坞原则(Hollywood Principle)"别来找我,到时候,我会去找你"(don't call me, I will call you)形象地比喻了这一设计思想。这个比喻中的"我"指的是Ioc容器,"你"则是被其调遣配置的一个组件。


还有一点,开发中,最好针对一个用例建一个spring的配置文件,
而且子系统或者模块的话,可以建一个文件甲,然后把这模块的用例对应的配置文件放在一个文件甲里面.
这样你有时候需要去弄清楚某一个用例的类关系,看spring配置文件反倒是一件方便的事情了.

其实可以把srping配置文件看成是类图中类关系的一种表示



你可以把我的用法看作一个Spring BT用法,IoC不单指配置型注入,还有动态注入,Spring提供了 registerBean(beanDefinition) 的机制。
或者我的用法可以算 use Spring without Spring,呵呵;我的目标不是为Ioc而Ioc,作为架构师我的第一要务是减少程序员的工作量,工作的复杂度, 而不是死板和教条的墨守成规。

相关推荐

    spring配置全书(中文)

    - **作者简介**:Craig Walls是一位经验丰富的软件开发者,具有超过13年的开发经验,涉及通信、金融等多个领域。他是Spring框架的忠实支持者,曾撰写《Spring in Action》等书籍,并在多个场合分享Spring相关的技术...

    SPRING开发指南.pdf

    书中可能涵盖如何配置Spring容器、创建bean、实现AOP、处理数据访问、构建Web应用等多个主题,并结合作者的实际项目经验分享最佳实践和技巧。对于想要掌握Spring的开发者来说,这是一份宝贵的资源。

    Spring-in-Action

    10. **最佳实践**:除了技术讲解,作者还会分享Spring开发的最佳实践,帮助读者提升开发效率,编写出高质量、可维护的代码。 《Spring in Action》这本书对于希望深入理解并掌握Spring框架的开发者来说是一本不可或...

    Javaee开发 spring boot实战

    《JavaEE开发的颠覆者:Spring Boot实战》一书深入探讨了Spring Boot这一JavaEE开发领域的革新框架。Spring Boot以其简化配置、快速启动和高效运行的特性,成为了现代企业级应用开发的首选工具。本节将围绕Spring ...

    SpringCloud系列之API Gateway开发手册(Hoxton版本).pdf

    - **SpringCloud Gateway优质参考博客**:社区博客通常包含实践案例和经验分享,可以帮助开发者解决实际问题。 SpringCloud Gateway通过其强大的路由和过滤器机制,为微服务架构提供了一种高效的API管理解决方案。...

    ssh完整例子ssh完整例子

    SSH是Java开发中常见的三大框架——Struts2、Spring和Hibernate的缩写,它们分别用于MVC模式的展现层、业务层管理和数据持久层操作。这个压缩包包含了一个完整的SSH集成项目的配置文件和源代码,适合初学者进行学习...

    spring-zh-CN.zip

    《Spring框架中文文档详解》 Spring框架是Java开发领域中不可或缺的重要组成部分,它...在学习过程中,不断查阅源码、参与社区讨论,以及参考其他开发者的经验分享,将有助于你更好地掌握Spring,提升自己的开发技能。

    spring MVC中文教程

    #### 六、实战经验分享 - 本书还包含了许多作者在实际项目中的经验和心得,这些实践经验对于读者理解和应用Spring MVC非常有帮助。 总之,《Spring MVC中文教程》是一本非常适合初学者的指南,它不仅详细介绍了...

    一个struts2+hibernate+spring整合的例子

    Spring框架在此中的作用主要体现在两方面:一是管理Bean,通过XML或注解方式定义Bean及其依赖关系,实现Bean的自动装配;二是提供事务管理,确保数据操作的一致性。在与Hibernate集成时,Spring可以管理Hibernate的...

    Spring in action 3rd (第三版)

    - **Spring 框架概述**:Spring 是一个开源框架,它为 Java 应用程序提供了一种轻量级的方式来管理和组织业务对象。Spring 通过依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, ...

    Spring_MVC_教程_快速入门_深入分析 高清文字版PDF

    Spring MVC是一个流行的Java框架,用于开发Web应用程序,遵循MVC(Model-View-Controller)设计模式。...这显示了Spring MVC社区的活跃度和开发者之间的互助精神,有助于开发者快速解决问题并分享经验。

    Spring与JBoss JBPM工作流集成开发指南

    - 社区论坛: 用户可以在这里提问和分享经验。 - 示例代码: 包含了Spring与JBPM集成的完整示例。 #### 六、总结 通过Spring与JBoss JBPM的集成,可以构建出灵活、可靠的工作流管理系统。这不仅能够提高业务流程的...

    spring杂谈 作者zhang KaiTao

    BeanPostProcessor接口是Spring中实现开闭原则的一个重要工具,允许开发者在Spring容器初始化Bean前后进行自定义操作,增强了框架的可扩展性。作者探讨了如何利用BeanPostProcessor实现特定的业务逻辑,以及在两个...

    JAVA程序开发大全---上半部分

    本书内容主要来自作者多年的软件开发和教学、培训经验,通过实例由浅入深地介绍MyEclipse的基本应用,是一本强调实践技能的实用性指导图书。 本书内容丰富、技术全面、案例实用,而且所有的实例都以MyEclipse工程的...

    springinaction示例代码

    1. **Spring框架基础**:Spring是Java企业级应用程序开发中的一个关键框架,它提供了依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)的核心特性,有助于简化项目结构,...

    spring培训课件PPT格式

    Spring框架是Java开发中的核心组件,它为应用程序提供了一个全面的基础设施,支持bean的依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)以及数据访问等众多功能。本套"Spring培训课件PPT格式"旨在帮助学习...

Global site tag (gtag.js) - Google Analytics