Spring3注释装配的最佳实践
长久以来国内的众多应用都在使用Spring框架,它为我们带来的好处不言而喻。但问题是Spring2.0以下版本尚未支持注释装配,而企业应用大多分作MVC三层结构,每层Bean的配置渐渐膨胀,直到打开了XML文件,IDE不堪重负崩溃为止,情形实为惊人。后有了Convention over Configuration的软件设计范式,即“约定优于配置”,也作“约定编程”。Ruby and Rails和EJB3也都按此实现,Spring注释也基于此。
首先,在解答为什么要使用注释装配之前,先看看没有它时配置文件臃肿的样子,如:持久层DAO的Spring配置文件
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<beans ‘略去声明’>
<bean id="xxDAO" class="com.data.switching.db.dao.impl.XxDAOImpl"
parent="sqlMapClientDAO" />
略去同样999个配置 ... ...
使用后的情况:
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:annotation-config />
<context:component-scan base-package="com.longtop.data.switching.db.dao"
name-generator="com.seraph.bi.suite.support.core.generator.IBatisDaoBeanNameGenerator" />
</beans>
现在大家想必都了解到为什么使用注释配置,两者之间后者很优雅,而这全在于约定优于配置。
解决方案:
改造过程是,首先在DAO的实现类中加入@Repository标签,说明这是持久层的服务。另外两层的标签@Service, @Controller,实现类如下:
Java代码
import org.springframework.stereotype.Repository;
...
@Repository
public class XxDAOImpl extends SqlMapClientDaoSupport implements XxDAO {
...
在配置文件中加入:
Xml代码
<context:annotation-config />
<context:component-scan base-package="com.db.dao"
name-generator="com.seraph.bi.suite.support.core.generator.IBatisDaoBeanNameGenerator" />
因接口名为XxDAO,而实现类名为 XxDAOImpl,引用类中的域名是接口的首字母小写名XxDAO,而容器生成的默认类名是 XxDAOImpl,所以不行,但spring预留了
接口BeanNameGenerator,只要实现它我们就可以自己指定生成bean的名字,这里的实现类如下:
Java代码
/**
* 类说明: 生成iBatis的DAO的Spring注册名,规则是首字母小写,并去掉后缀名<br>
* 创建时间: 2011-1-26 下午12:44:20<br>
*/
public class IBatisDaoBeanNameGenerator implements BeanNameGenerator {
private static final Logger logger = Logger
.getLogger(IBatisDaoBeanNameGenerator.class);
private static final String DAO_IMPLEMENTS_SUFFIX = "Impl";
public String generateBeanName(BeanDefinition paramBeanDefinition,
BeanDefinitionRegistry paramBeanDefinitionRegistry) {
String[] strs = paramBeanDefinition.getBeanClassName().split("\.");
String shortName = strs[strs.length - 1];
shortName = StringUtils.uncapitalize(shortName);
shortName = shortName.replace(DAO_IMPLEMENTS_SUFFIX, "");
logger.debug("Generated a ibatis DAO bean's name: [" + shortName + "]");
return shortName;
}
}
到这里我们可以自由的指定注释类的bean名称,但对于为DAO提供dataSource和sqlMapClient的Inner Class,即parent="sqlMapClientDAO"要如何处理呢?
Xml代码
<bean id="scRoleDAO" class="com.dao.impl.XxDAOImpl"
parent="sqlMapClientDAO" />
Xml代码
<bean id="sqlMapClientDAO"
class="org.springframework.orm.ibatis.support.SqlMapClientDaoSupport"
abstract="true">
<property name="dataSource" ref="${jdbc.dataSource}" />
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
<bean id="sqlMapClient" class="com.seraph.bi.suite.support.core.IncludesSqlMapClientFactoryBean">
<property name="configLocation" value="classpath:ibatis/platform/orcl/sqlmap.xml" />
</bean>
为了解决此问题,我们实现了一个后置注入的类:SqlMapClientDaoInjector用来在DAO加载到context中后注入其依赖。类代码如下:
Java代码
/**
* 类说明: 向iBatis的DAO中注入依赖<br>
* 创建时间: 2011-1-26 上午10:51:28<br>
*/
public class SqlMapClientDaoInjector implements ApplicationContextAware, InitializingBean {
private static final Logger logger = Logger.getLogger(SqlMapClientDaoInjector.class);
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContext.setApplicationContext(applicationContext);
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(dataSource, "Property 'dataSource' is required.");
Assert.notNull(sqlMapClient, "Property 'sqlMapClient' is required.");
injectDependence();
}
private void injectDependence() {
// 获取Context上下文
ApplicationContext ctx = SpringContext.getApplicationContext();
// 按类型获取上下文中的对象
Map<String, SqlMapClientDaoSupport> map = ctx.getBeansOfType(org.springframework.orm.ibatis.support.SqlMapClientDaoSupport.class, true, true);
for (Iterator<String> i = map.keySet().iterator(); i.hasNext();) {
try {
String supportName = (String) i.next();
SqlMapClientDaoSupport support = map.get(supportName);
// 后注入依赖
support.setSqlMapClient(sqlMapClient);
support.setDataSource(dataSource);
} catch (RuntimeException e) {
logger.error("SqlMapClientDaoInjector.injectDependence()", e);
}
}
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void setSqlMapClient(SqlMapClient sqlMapClient) {
this.sqlMapClient = sqlMapClient;
}
private DataSource dataSource;
private SqlMapClient sqlMapClient;
}
然后加入此类的配置即可,
Xml代码
<bean id="sqlMapClientDaoInjector"
class="com.seraph.bi.suite.support.dao.assembly.SqlMapClientDaoInjector">
<property name="dataSource" ref="${jdbc.dataSource}" />
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
至此我们完成了Spring注释配置的改造。
总结下实现思路,首先是在需要自动加载的类上加入@Repository注释标签,对于需要改变默认类名生成规则的约定,编写实现BeanNameGenerator接口的类,然后对于需要抽象的内置类的配置,自实现后依赖注入的实现。针对此例我们要体会实现的思路,即了解Spring容器的工作原理和设计思想,而后我们可以对其实现有益且有必要的改进工作,但最终都是旨在简化配置,减少没有必要的工作量。
分享到:
相关推荐
数据来源:中国电力统计NJ-2021版
数据来源:中国电力统计NJ-2021版
词根单词 2.2.4 修改版.apk
毕业论文-基于JSP的个人通讯录管理系统设计与实现.docx
数据来源:中国电力统计NJ-2021版
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
数据来源:中国电力统计NJ-2021版
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
数据来源:中国人口与就业统计NJ-2023版
图书借阅管理系统设计与实现及论大学生写作能力.docx
Smart继电器编程器操作手册
毕业设计论文-基于C的人事管理系统设计与实现.docx
数据来源:中国劳动统计NJ-2023版
OPCEV096IPHT手册
数据来源:中国电力统计NJ-2021版
数据来源:中国人口与就业统计NJ-2023版
数据来源:中国人口与就业统计NJ-2023版
基于matlab实现应用遗传算法针对物流配送车辆路径规划问题进行求解.rar
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
数据来源:中国人口与就业统计NJ-2023版