异常信息:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.springapp.test.SqlTests': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.shyy.web.service.TreeMapper com.springapp.test.SqlTests.treeMapper; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.shyy.web.service.TreeMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:384)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:326)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.shyy.web.service.TreeMapper com.springapp.test.SqlTests.treeMapper; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.shyy.web.service.TreeMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
... 29 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.shyy.web.service.TreeMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1100)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 31 more
出现以上异常的环境:
这是面向mybatis文件的接口(注意:没有实现类)
package com.shyy.web.service; import com.shyy.web.entity.Tree; import java.util.List; public interface TreeMapper { int deleteByPrimaryKey(String id); int insert(Tree record); int insertSelective(Tree record); Tree selectByPrimaryKey(String id); List<Tree> getFather(); List<Tree> getChildren(String id); int updateByPrimaryKeySelective(Tree record); int updateByPrimaryKey(Tree record); }
这是pojo的映射文件(注意其namespace是面向指定接口的)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.shyy.web.service.TreeMapper" > <resultMap id="BaseResultMap" type="com.shyy.web.entity.Tree" > <id column="id" property="id" jdbcType="VARCHAR" /> <result column="text" property="text" jdbcType="VARCHAR" /> <result column="iconCls" property="iconCls" jdbcType="VARCHAR" /> <result column="leaf" property="leaf" jdbcType="TINYINT" javaType="Boolean" /> <result column="fatherId" property="fatherId" jdbcType="VARCHAR" /> </resultMap> <sql id="Base_Column_List" > id, text, iconCls, leaf, fatherId </sql> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" > select <include refid="Base_Column_List" /> from t_tree where id = #{id,jdbcType=VARCHAR} </select> <select id="getFather"> SELECT <include refid="Base_Column_List" /> FROM t_tree WHERE fatherId IS NULL </select> <select id="getChildren" parameterType="java.lang.String"> SELECT <include refid="Base_Column_List" /> FROM t_tree WHERE fatherId = #{fatherId} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.String" > delete from t_tree where id = #{id,jdbcType=VARCHAR} </delete> <insert id="insert" parameterType="com.shyy.web.entity.Tree" > insert into t_tree (id, text, iconCls, leaf, fatherId) values (#{id,jdbcType=VARCHAR}, #{text,jdbcType=VARCHAR}, #{iconCls,jdbcType=VARCHAR}, #{leaf,jdbcType=TINYINT}, #{fatherId,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.shyy.web.entity.Tree" > insert into t_tree <trim prefix="(" suffix=")" suffixOverrides="," > <if test="id != null" > id, </if> <if test="text != null" > text, </if> <if test="iconCls != null" > iconCls, </if> <if test="leaf != null" > leaf, </if> <if test="fatherId != null" > fatherId, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="id != null" > #{id,jdbcType=VARCHAR}, </if> <if test="text != null" > #{text,jdbcType=VARCHAR}, </if> <if test="iconCls != null" > #{iconCls,jdbcType=VARCHAR}, </if> <if test="leaf != null" > #{leaf,jdbcType=TINYINT}, </if> <if test="fatherId != null" > #{fatherId,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.shyy.web.entity.Tree" > update t_tree <set > <if test="text != null" > text = #{text,jdbcType=VARCHAR}, </if> <if test="iconCls != null" > iconCls = #{iconCls,jdbcType=VARCHAR}, </if> <if test="leaf != null" > leaf = #{leaf,jdbcType=TINYINT}, </if> <if test="fatherId != null" > fatherId = #{fatherId,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=VARCHAR} </update> <update id="updateByPrimaryKey" parameterType="com.shyy.web.entity.Tree" > update t_tree set text = #{text,jdbcType=VARCHAR}, iconCls = #{iconCls,jdbcType=VARCHAR}, leaf = #{leaf,jdbcType=TINYINT}, fatherId = #{fatherId,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} </update> </mapper>
这是spring-mybatis的xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.shyy.web.service"/> <context:component-scan base-package="com.mybatis.mapper"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${mySQLdriver}"/> <property name="url" value="${url}"/> <property name="username" value="${user}"/> <property name="password" value="${pwd}"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:sqlMap/*.xml"/> <property name="typeAliasesPackage" value="com.shyy.web.entity"/> </bean> <bean class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
分析:这是在spring-mybatis的xml文件缺少MapperScannerConfigurer的配置造成的,因为这里是直接调用接口中的方法执行相应映射文件中的sql,而在该接口缺少了必要的依赖bean——sqlSessionFactory,解决方法如下:配置MapperScannerConfigurer
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.shyy.web"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${mySQLdriver}"/> <property name="url" value="${url}"/> <property name="username" value="${user}"/> <property name="password" value="${pwd}"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:sqlMap/*.xml"/> <property name="typeAliasesPackage" value="com.shyy.web.entity"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.shyy.web.service"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
通过配置MapperScannerConfigurer,mabatis就会扫描指定的包,然后将sqlSessionFactory注入到该包中的类中。
附:另一种设计模式示例
dao层
AccountDao.java 接口
public interface AccountDao { public abstract List<Account> list(); public abstract Pager list2(Pager p); public abstract Pager search(Account account,int currId,Pager p); public abstract Account findByName(String username); public abstract Account findById(int aid); public abstract Account checkAccount(Account account); public abstract void saveOrUpdate(Account account); public abstract void update(Account account); public abstract void delete(Account account); }
实现类
@Repository("accountImpl") public class AccountImpl extends BaseDaoImp<Account> implements AccountDao{ @Resource private HibernateTemplate hibernateTemplate; String hql = "from Account a order by a.aid"; @Override public List<Account> list() { return this.listObject(hql); } @Override public Pager list2(Pager p) { return this.listObject(hql,p); } @Override public Pager search(Account account,int currId, Pager p) { StringBuffer sbhql=new StringBuffer(); sbhql.append("from Account a where a.aid!="+currId+""); if(account!=null){ if(account.getUsername()!=null&&!"".equals(account.getUsername().trim())){ sbhql.append(" and a.username like '%"+account.getUsername()+"%'"); } if(account.getInactive()!=0){ sbhql.append(" and a.inactive="+account.getInactive()+""); } } sbhql.append(" order by a.aid "); return listObject(sbhql.toString(), p); } @Override public Account findById(int aid) { String hql="from Account a where a.aid="+aid; return this.getObject(hql); } @Override public Account findByName(String username) { String hql="from Account a where a.username='"+username+"'"; return this.getObject(hql); } @Override public Account checkAccount(Account account) { String hql="from Account a where a.username='"+account.getUsername()+"'"; return this.getObject(hql); } @Override public void saveOrUpdate(Account account) { hibernateTemplate.saveOrUpdate(account); } @Override public void update(Account account) { hibernateTemplate.merge(account); } @Override public void delete(Account account) { hibernateTemplate.delete(account); } }
然后在需要的地方注入就可以:
@Autowired
private AccountDao accountImpl;