文章目录
6.使用注解简化Spring的IOC配置
6.1 为什么需要注解配置?
因为我们已经完后了 spring IOC和DI 也进行了Spring 一张表的CURD操作,但是我们发现了一个问题
<!-- 创建一个DAO层对象 -->
<bean id="userDAO" class="com.hnxy.dao.impl.UserDAOImpl">
<property name="qr" ref="qr" />
</bean>
<!-- 创建一个Service对象 -->
<bean id="userService" class="com.hnxy.service.impl.UserServiceImpl">
<property name="userDAO" ref="userDAO" />
</bean>
上面这段代码,看似好像没有什么问题,但是大家可以仔细的想一想,如果你的DAO对象和Service对象有很多个需要配置的话,那么Bean的数量将会是惊人的一个数量
那么此时就有一个问题 : Bean的数量增多 XML配置的难度也随之增加 维护起来也不好维护
遇到这样问题我们改如何解决 ?
解决XML问题的通用玩法 如果你觉得你的XML配置很难 那么一定 要先考虑使用注解优化一个配置!
注解 :
标记语言 可以把一个类 一个方法标记为一个功能
注解 和 XML的本质其实是一样
6.2 IOC与DI的注解优化配置
删除spring配置文件中的原有对象bean的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 需要一个数据源对象 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/userdb?characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 创建SQL的执行对象 -->
<bean id="qr" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 构造函数创建对象 -->
<constructor-arg name="ds" ref="dataSource" />
</bean>
</beans>
注意只保留 DataSource 和 QueryRunner 我们自己定义的类的bean我们用注解配置
我们删除了两个bean 一个是 UserDAOImpl 一个是UserServiceImpl
6.3 IOC与DI的注解配置
注解存在的意义 : XML的另外一种配置方案而已,它能够减少我们在XML中配置的bean标签的数量,从而简化XML配置
主要用途 : 配置bean
@Component = <bean id="" class="" />
@Component("userDAO") = <bean id="userDAO" class="com.hnxy.dao.impl.UserDAOImpl" />
@Component
public class UserDAOImpl implements UserDAO {
这句话就相当于
<bean id="UserDAOImpl" class="com.hnxy.dao.impl.UserDAOImpl" />
最起码注解的好处就是 你不用再指定类型
但是 此处需要注意的是,你的bean虽然创建完了 但是它被创建在类中了 spring配置文件并不知道你有这个bean
所以我们必须让spring知道我们现在有一个bean在UserDAOImpl
那么我们怎么让spring配置文件知道我有这么一个bean
其实 spring给你提供了一个 注解bean的包扫描器的功能可以通过配置包扫描器 扫描某个包下的所有注解bean
那么此处我们怎么配置注解bean的包扫描器呢?
- 引入相关的功能 这个包扫描器的功能 在spring-context这个包下,所以我们要引入
这个context功能
声明引入功能标签
xmlns:context="http://www.springframework.org/schema/context"
添加这个标签的XSD文件
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
- 引入完成后我们直接配置包的扫描器即可
<!-- 节省时间 -->
<context:component-scan base-package="com.hnxy.dao" />
<context:component-scan base-package="com.hnxy.service" />
改造完成后经过测试可以知道 我们用注解创建的bean是单例模式,那么怎么把单例的bean变成多例的bean
如果你想把一个bean变成多例 只需要加入一个 @scope注解即可
@Component("userService")
@Scope("prototype")
public class UserServiceImpl implements UserService {
......代码略
}
那么到此我们已经可以用注解创建bean,但是bean里面的属性我们无法赋值那怎么办呢?
6.4 注解
6.4.1 @Autowired
按类型注入属性值 给属性按类型赋值
6.4.2 @Qualifier(“UserService”)
可以按照bean的id进行配置 给属性按名称赋值
@Autowired 注解可以按类型注入相关的属性值,但是有一个问题,按类型注入一个类型只能出现一个bean
假如说你按类型注入的时候报错了,那么你其实还可以按照BeanID的形式指定需要注入的bean
@Autowired
@Qualifier("qr1")
private QueryRunner qr;
@Component 可以把一个类变成bean,当然这个注解的语义不够明显,
6.4.3 @Component又被分成三个注解
@Repository 可以把一个DAO层变成一个bean
@Service 可以把一个service的变成bean
@controller 可以把一个controller变成一个bean
6.4.4 区别 :
@Service @Controller @Repository 只是语义更加明确了,功能都是一样的其实底层就是Component
给某个具体的注解bean加上ID值 创建一个对象
@Service(“UserService”)
6.5 具体实现
6.5.1 实体类 UserInfo.java
package com.hnxy.entity;
import java.util.Date;
/**
* 以OOP思想为基础
* @author My
*
*/
public class UserInfo {
// 私有属性
private Integer uid; // 主键ID
private String uname; // 客户姓名
private Date regDate; // 注册时间
private Double money; // 用户余额
// 共有方法
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Date getRegDate() {
return regDate;
}
public void setRegDate(Date regDate) {
this.regDate = regDate;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "UserInfo [uid=" + uid + ", uname=" + uname + ", regDate=" + regDate + ", money=" + money + "]";
}
}
6.5.2 Spring配置文件 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
">
<!-- 配置注解bean的包扫描器 -->
<context:component-scan base-package="*.*.dao" />
<context:component-scan base-package="*.*.service" />
<!-- 需要一个数据源对象 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/userdb?characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 创建SQL的执行对象 -->
<bean id="qr" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 构造函数创建对象 -->
<constructor-arg name="ds" ref="dataSource" />
</bean>
</beans>
6.5.3 改造的实现类 DAOImpl
package com.hnxy.dao.impl;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.hnxy.dao.UserDAO;
import com.hnxy.entity.UserInfo;
/**
* UserDAO接口的实现类
* @author My
* @Component = <bean id="UserDAOImpl" class="类的全限定名字">
* @Component("userDAO") = <bean id="userDAO" class="类的全限定名称">
* @Repository 继承于 @Component 专门用来标记DAO层bean的一个注解
* 约定 : @Repository只能用于DAO层
*/
@Repository
public class UserDAOImpl implements UserDAO {
// DAO层到底需要哪些个对象才能完成这个需求? DAO 操作数据库 执行SQL语句
// 数据源(c3p0)-->SQL执行对象(dbutils queryrunner)
// @Autowired 代表这个属性自动按照类型注入
@Autowired
private QueryRunner qr;
@Override
public int findUserByPageListCount() throws Exception {
// 创建方法的返回值
int totalCount = 0;
// 编写SQL语句
String sql = "select count(*) from v1";
// 占位符赋值
// 执行
Number num = qr.query(sql, new ScalarHandler<Number>(1));
// 处理返回值
totalCount = num.intValue();
// 返回
return totalCount;
}
@Override
public List<UserInfo> findUserByPageList(Integer start, Integer size) throws Exception {
// 创建方法的返回值
List<UserInfo> list = null;
// 创建SQL语句
String sql = "select * from v1 limit ?,?";
// 占位符赋值
Object[] params = {start,size};
// 执行
list = qr.query(sql, new BeanListHandler<UserInfo>(UserInfo.class),params);
// 返回
return list;
}
@Override
public UserInfo findUserByID(Integer uid) throws Exception {
// 创建方法的返回值
UserInfo user = null;
// 创建SQL语句
String sql = "select * from v1 where uid = ?";
// 占位符赋值
Object[] params = {uid};
// 执行
user = qr.query(sql, new BeanHandler<UserInfo>(UserInfo.class),params);
// 返回
return user;
}
@Override
public int insertUser(UserInfo user) throws Exception {
// 创建方法的返回值
int count = 0;
// 创建SQL语句
String sql = "insert into user_info values (null,?,?,?)";
// 占位符赋值
Object[] params = {user.getUname(),user.getRegDate(),user.getMoney()};
// 执行
count = qr.update(sql,params);
// 返回
return count;
}
@Override
public int updateUser(UserInfo user) throws Exception {
// 创建方法的返回值
int count = 0;
// 创建SQL语句
String sql = "update user_info set u_name=?,u_regdate=?,u_money=? where u_id = ?";
// 占位符赋值
Object[] params = {user.getUname(),user.getRegDate(),user.getMoney(),user.getUid()};
// 执行
count = qr.update(sql,params);
// 返回
return count;
}
@Override
public int deleteUser(UserInfo user) throws Exception {
// 创建方法的返回值
int count = 0;
// 创建SQL语句
String sql = "delete from user_info where u_id = ?";
// 占位符赋值
Object[] params = {user.getUid()};
// 执行
count = qr.update(sql,params);
// 返回
return count;
}
}
6.5.4 ServiceImpl
package com.hnxy.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.hnxy.dao.UserDAO;
import com.hnxy.entity.UserInfo;
import com.hnxy.service.UserService;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public int findUserByPageListCount() throws Exception {
return userDAO.findUserByPageListCount();
}
@Override
public List<UserInfo> findUserByPageList(Integer pageIndex, Integer pageSize) throws Exception {
List<UserInfo> list = null;
if(null != pageIndex && null != pageSize){
if(pageIndex > 0 && pageSize > 0){
list = userDAO.findUserByPageList((pageIndex-1)*pageSize, pageSize);
}
}
// 返回
return list;
}
@Override
public UserInfo findUserByID(Integer uid) throws Exception {
return userDAO.findUserByID(uid);
}
@Override
public int insertUser(UserInfo user) throws Exception {
return userDAO.insertUser(user);
}
@Override
public int updateUser(UserInfo user) throws Exception {
return userDAO.updateUser(user);
}
@Override
public int deleteUser(UserInfo user) throws Exception {
return userDAO.deleteUser(user);
}
}
6.6 注解bean的配置总结
-
注解bean的配置 只针对我们自己写的类 注解可不可以配置在接口上?接口不可以配置注解bean! 为啥?因为接口不能new
-
一定要记住
Service的bean 怎么配置注解 @Service
DAO中的bean 怎么配置注解 @Repository
注意 我们这么配置注解的话 其实 就相当于配置了一个<bean class="">
没有配置id 所以我们在获取这个bean的对象的时候 用 类型获取 -
如果你想给某个bean下的属性进行赋值 那么你应该使用 @Autowired
而且此处需要注解 当你使用 @Autowired注解的时候 你是不用给属性提供set方法 -
注解配置完的bean 散落在了不同的包里 那么spring要想组织这些信息 它必须知道这些bean都在哪?
后我们一定要注意一个问题 :
在大多数同学些 Spring注解的时候 经常忘记写@Repository,@Service
我们以后再编写类的时候这两个注解一定要先 千万不要忘了