Spring单测中的@Autowired和@Qualifier

@Autowired 
注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出BeanCreationException 
 
@Autowired(required = false) 
这等于告诉 Spring:在找不到匹配 Bean 时也不报错。
 
和找不到一个类型匹配 Bean 相反的一个错误是:如果 Spring 容器中拥有多个候选 Bean,Spring 容器在启动时也会抛出BeanCreationException 
 
此时该如何处理呢?答案是是使用@Qualifier。
@Autowired与@Qualifier配合使用时将会以byName方式进行依赖注入。以byName方式进行依赖注入正是为了避免相同类型的不同POJOs在注入时发生冲突。@Qualifier作用于类的成员变量、类的setter方法中的参数或类的构造函数中的参数。
 
@Autowired
public void setOffice(@Qualifier("office")Office office) { 
this.office = office;
 
下面给出一个常见的Spring测试用例做参考:
 
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import junit.framework.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
 
/**
 * 
 * &ldquo;搜客&rdquo;和&ldquo;投放网络&rdquo;列表筛选后不能删除问题回归测试用例 <p>
 * 
 * Hibernate3.3.2GA在使用hql删除时,如果where id in(XXX)里面的XXX太多了,会导致StackOverFlowError。使用hibernate3-fix.jar后该问题修复。<br>
 * 详参考https://hibernate.onjira.com/browse/HHH-2166?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=35008#action_35008。<p>
 * 
 * 复现场景:<br>
 * 1. 使用Hibernate3.3.2GA版本hibernate3.jar部署web程序。<br>
 * 2. 登陆http://beidoulocal.baidu.com:8080/shifenLogin.action。<br>
 * 3. 推广组 -> 搜客,新建1万个搜索关键词。<br>
 * 4. 停止web应用程序,执行测试用例,应抛出如下错误<br>
 * <code>
 * java.lang.StackOverflowError
 *	at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:64)
 *	at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66) 
 * </code>
 * <p>
 *	
 * 5. 使用使用Hibernate3.3.2GA-fixByZhangxu版本hibernate3-fix.jar部署web应用程序<br>
 * 6. 登陆http://beidoulocal.baidu.com:8080/shifenLogin.action。<br>
 * 7. 推广组 -> 搜客,新建1万个搜索关键词。<br>
 * 8. 停止web应用程序,执行测试用例,执行通过,可以观察打印出所有QT关键词信息。<br>
 * 
 * @author zhangxu
 * @since 20110826
 *
 */
@ContextConfiguration(locations = { "/applicationContext.xml" })
public class CproQTKeywordMgrTest extends AbstractTransactionalJUnit4SpringContextTests {
 
	////////////////////////////////////////////////////////////////
 
	// 修改userid和groupid进行测试
	private final int userid = 480787;
	private final int groupid = 905276;
 
	////////////////////////////////////////////////////////////////
 
	private static final Log log = LogFactory.getLog(CproQTKeywordMgrTest.class);
 
	@Autowired
	private CproQTKeywordMgr cproQTKeywordMgr;
 
	private JdbcTemplate jdbcTemplate;
 
	@Autowired
	public void setDataSource(@Qualifier("dataSource") DataSource dataSource){
		super.setDataSource(dataSource);
	}
 
	@Autowired
	public void setJdbcTemplate(@Qualifier("dynamicJdbcTemplate") JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
 
	private PartitionStrategy strategy = null;
	private final int mod = 64;
	private String range = "2000000";
	private final String tablename = "cproqtkeyword";
	private final String poname = "com.baidu.beidou.cprogroup.bo.CproQtKeyword";
 
	/**
	 * 	构造一个分页策略
		<bean id="keywordPartitionStrategy"
		class="com.baidu.beidou.util.partition.strategy.impl.HashPartitionStrategy">
			<constructor-arg index="0" value="cproqtkeyword" />
			<constructor-arg index="1" value="com.baidu.beidou.cprogroup.bo.CproQtKeyword" />
			<constructor-arg index="2" value="64"></constructor-arg>
			<constructor-arg index="3" value="2000000"></constructor-arg>
		</bean>
	 */
	public void setUp(){ 
		try {
			log.info("初始化分页策略");
			strategy = new HashPartitionStrategy(tablename, poname, mod, range);
		}catch(Exception e){
			log.error(e.getMessage(),e);
		}
 
	}
 
	@Test
	public void testSelectHugeNumberQTKeywords(){
		setUp();
		log.info("Begin=======================");
 
		//1. 用sql查询所有keywordIds
		log.info("Start to get all keywordIds from userid=" + userid + ",groupid=" + groupid);
		log.info("(The method used here is not hql but pure jdbc sql)");
		MockCproQTKeywordDaoImpl mockCproQTKeywordDaoImpl = new MockCproQTKeywordDaoImpl();
		List<Integer> keywordIds = mockCproQTKeywordDaoImpl.findKeywordIdsByUserid(userid, groupid);
		log.info("Get " + keywordIds.size() + " keywordIds from userid=" + userid + ",groupid=" + groupid + ", there ids are " + keywordIds);
		log.info("Start to get all keywordIds from userid=" + userid + ",groupid=" + groupid);
		log.info("(The method used here is cproQTKeywordMgr.findByIds(keywordIds, userid) and it used hql)");
 
 
		//2. 用service层提供到方法查询所有CproQTKeyword;如果用旧到hibernate,此处应该会抛出StackOverFlowError。
		List<CproQTKeyword> result = cproQTKeywordMgr.findByIds(keywordIds, userid);
		Assert.assertNotNull(result);
		log.info("Get " + result.size() + " CproQTKeyword object back");
		log.info("Print all of returned CproQTKeyword");
		for(CproQTKeyword cproQTKeyword: result){
			logger.info(cproQTKeyword.getKeywordid() +  "|" +
					cproQTKeyword.getKeyword() + "|" + 
					cproQTKeyword.getWordid() + "|" + 
					cproQTKeyword.getPlanid() + "|" + 
					cproQTKeyword.getGroupid() + "|" + 
					cproQTKeyword.getUserid() + "|" + 
					cproQTKeyword.getAdduser() + "|" + 
					cproQTKeyword.getAddtime());
		}
 
		log.info("End=======================");
	}
 
	/**
	 * 
	 * 自行构造到使用sql查询到DAO
	 * 
	 * @author zhangxu
	 *
	 */
	public class MockCproQTKeywordDaoImpl extends GenericDaoImpl<Object, Integer>{
 
		/**
		 * 不用hql查询,用JDBC写SQL
		 */
		public List<Integer> findKeywordIdsByUserid(Integer userid, Integer groupid) {
			PartID part = strategy.getPartitions(new PartKeyBDidImpl(userid));
			String sql = "select keywordid from " + part.getTablename() + " where userid = " + userid + " and groupid = " + groupid;
			log.info("sql : " + sql);
			// 不调用父类到findBySql方法
			return findBySql(new GenericRowMapping<Integer>() {
 
				public Integer mapRow(ResultSet rs, int rowNum)
						throws SQLException {
					return rs.getInt(1);
				}
 
			}, sql, new Object[] {}, new int[] {});
		}
 
		/**
		 * 用了测试用例手工注入到jdbcTemplate
		 */
		protected <E> List<E> findBySql(GenericRowMapping<E> mappper, String sql,
				Object[] parameters, int[] argTypes) {
			if(sql == null){
				return null;
			}
			return jdbcTemplate.query(sql, parameters, argTypes, mappper);
		}
 
	}
 
}
 
 

 

Leave a Comment.