Service实现类中不能自动注入Dao对象

J2EE 码拜 8年前 (2016-05-18) 2035次浏览
0、出错在:org.seckill.servce.SeckillServiceImpl类中两个@autowired处
报错:Could not autowire. No beans of “SeckillDao” type found.

         // 在spring容器中获取Dao实例,注入到Service依赖:
	@Autowired   // 自动注入
	private SeckillDao seckillDao;

	@Autowired
	private SuccessKilledDao successKilledDao;

1、Dao接口

package org.seckill.dao;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.seckill.entity.Seckill;
import org.springframework.web.bind.annotation.ResponseBody;
/*
 * 这个DAO接口负责实体Seckill中属性的增删改查的设计
 */
@ResponseBody
public interface SeckillDao {
	/**
	 * 减库存(更新库存):要减库存id,执行减库存的时间
	 * @param seckillId
	 * @param killTime 秒杀时间
	 * @return 更新语句影响的行数:假如 >=1,表示这条更新语句没有成功
	 */
	int reduceNumber(@Param("seckillId") long seckillId, @Param("killTime") Date killTime);

	/**
	 * 根据id查询秒杀对象
	 * @param seckillId
	 * @return
	 */
	Seckill queryById(long seckillId);

	/**
	 * 根据偏移量查询秒杀商品列表
	 * @param offset 偏移量
	 * @param limit 在偏移量之后,查询多少条记录
	 * @return
	 */
	List<Seckill> queryAll(@Param("offset") int offset, @Param("limit") int limit);

}

2、Service实现类

package org.seckill.service.impl;
import java.util.Date;
import java.util.List;
import org.seckill.dao.SeckillDao;
import org.seckill.dao.SuccessKilledDao;
import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExecution;
import org.seckill.entity.Seckill;
import org.seckill.entity.SuccessKilled;
import org.seckill.enums.SeckillStateEnum;
import org.seckill.exception.RepeatKillException;
import org.seckill.exception.SeckillCloseException;
import org.seckill.exception.SeckillException;
import org.seckill.service.SeckillService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
// spring提供的注解:@component 代表全部的组件、@Service、@Dao、@Controller
@Service
public class SeckillServiceImpl implements SeckillService {

	// 日志 slf4j接口
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	// 在spring容器中获取Dao实例,注入到Service依赖:
	@Autowired   // 自动注入
	private SeckillDao seckillDao;

	@Autowired
	private SuccessKilledDao successKilledDao;

	// md5盐值字符串,用户混淆md5: 乱敲的,越复杂越好。
	private final String slat = "sfdhasfosadihf23oihikefGFUUI5778^&*^%^*sdjkfakj"; 



	public List<Seckill> getSeckillList() {
		return seckillDao.queryAll(0, 4);
	}
	public Seckill getById(long seckillId) {
		return seckillDao.queryById(seckillId);
	}
	public Exposer exportSeckillUrl(long seckillId) {
		// 优化点:缓存优化
		/**
		 * get from catch
		 * if null
		 * 		get db
		 * 		put cache
		 * return
		 * 这是缓存的伪代码 --> 但是不能写在(业务逻辑)service中。
		 * 正确的方式:是写在dao包中(dao:数据访问对象。dao包:访问MySQL数据的,也可以有访问redis数据的。)
		 */
		Seckill seckill = seckillDao.queryById(seckillId);

		// 未查到秒杀商品
		if(seckill == null)
			return new Exposer(false, seckillId);

		Date startTime = seckill.getStartTime();
		Date endTime = seckill.getEndTime();
		// 当前系统的时间
		Date nowTime = new Date(); 
		// 秒杀还未开始或 已经结束。
		// 注:nowTime.getTime() 返回日期时间的毫秒数(long类型)
		if( nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime() )
			return new Exposer(false, seckillId, nowTime.getTime(), startTime.getTime(), endTime.getTime());

		// md5 转化特定字符串的过程,且不可逆
		String md5 = getMD5(seckillId); 
		return new Exposer(true, md5, seckillId);
	}

	// 生成md5 -- 用来加密
	private String getMD5 (long seckillId){
		String base = seckillId + "/" + slat; 
		String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
		return md5;
	}

	@Transactional  // 事务
	/*
	 * 使用注解控制声明式事务的优点:
	 * 	1、开发团队达成一致约定,明确标注事务方法的编程方法。
	 *  2、保证事务方法的执行时间尽可能短,不要加网络操作(如RPC/HTTP请求)。假如必须加网络请求,可以将它们剥离到事物方法之外。
	 *  3、不是全部的方法都需要事务。如只有一条修改操作、只读操作都是不需要事务控制的。(当有两条以上的修改操作需要同时完成时
	 *  	需要事务,如本例中的秒杀=减库存+记录购买明细。或只读操作需要...。详细可看MySQL行级锁相关的文档。)
	 */
	public SeckillExecution executeSeckill (long seckillId, long userPhone, String md5)
			throws SeckillException, RepeatKillException, SeckillCloseException {

		if(md5 == null || !md5.equals(getMD5(seckillId)))
			throw new SeckillException("seckill data rewrite");


		try {
			// 执行秒杀逻辑:减库存 + 记录秒杀行为
			Date nowTime = new Date();
			int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
			if(updateCount <= 0)
				// 没有更新数据记录。即,秒杀结束了
				throw new SeckillCloseException("seckill is closed");
			else {
				// 秒杀成功了,则要记录购买行为
				int insertCount = successKilledDao.insertSuccessKilled(seckillId, userPhone);
				if(insertCount <= 0)
					// 插入行数为 0,则重复秒杀
					throw new RepeatKillException("seckill repeat");
				else {
					// 成功秒杀
					SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
					return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS, successKilled);
				}
			}
		} catch (SeckillCloseException e1) {
			throw e1;
		} catch (RepeatKillException e2) {
			throw e2;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			// 全部编译期异常,转化为运行期异常
			// 这样做的优势:spring申明式事务会给全部运行期异常做回滚(rollback),而编译期异常就不行
			// 目的: 就是,一旦出错,就立即回滚。为的是减库存的操作和记录购买行为的操作没有同时的执行。
			throw new SeckillException("seckill inner error: " + e.getMessage());
		}
	}
}

3、扫描的service包

<?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">

	<!-- 配置:扫描service包下全部使用注解的类型(只要扫描就行,其他都交给注解) -->
	<context:component-scan base-package="org.seckill.service"/>

	<!-- 基于Spring的声明式事务的配置: Mybatis使用的是jdbc的事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 注入数据库的连接池 -->
		<property name="dataSource" ref="dataSource"/>
	</bean>

	<!-- 配置基于注解的声明式事务: 默认使用注解来管理事务行为 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

</beans>
解决方案

40

实现类 注解个@Service。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明Service实现类中不能自动注入Dao对象
喜欢 (0)
[1034331897@qq.com]
分享 (0)