Spring学习笔记01-控制反转IOC&依赖注入DI

11 篇文章 0 订阅

Spring

控制反转 IOC

程序的耦合和解耦

  • 耦合: 程序间的依赖关系.在开发中,应该做到解决编译期依赖,即编译期不依赖,运行时才依赖.
  • 解耦的思路: 使用反射来创建对象,而避免使用new关键字,并通过读取配置文件来获取要创建的对象全限定类名

使用Spring解决程序耦合

准备工作
  1. 使用maven引入依赖,pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yll</groupId>
    <artifactId>Spring01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>

</project>
  1. resources下创建bean的配置文件bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--把对象的创建交给spring来管理-->
    <bean id="accountDao" class="com.yll.dao.impl.AccountDaoImpl"></bean>
    <bean id="accountService" class="com.yll.service.impl.AccountServiceImpl"></bean>
</beans>
  1. 修改表现层代码,通过Spring创建对象
/***
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
//        IAccountService as =  new AccountServiceImpl();
//        as.saveAccount();
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取bean对象
        IAccountService as = (IAccountService) ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);
        System.out.println(as);
        System.out.println(adao);
    }

}

使用xml配置文件实现IOC
  • 获取spring的IOC核心容器,并根据id获取对象
ApplicationContext方式
  • 特点:

    • 读取完配置文件,立马创建对象等待使用
    • 单例对象使用
      • 我们实际开发中使用这个,因为加载策略会随配置文件改变
  • ApplicationContext的三个常用实现类

  1. ClassPathXmlApplicationContext:可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在,加载不了
  2. FileSystemXmlApplicationContext:可以加载磁盘任意路径下的配置文件(必须有访问权限)
  3. AnnotationConfigApplicationContext:用于读取注解创建容器
  • 核心容器的两个接口引发出的问题:
    • ApplicationContext: 单例对象使用
      它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。一读取完配置文件马上就创建配置文件中配置的对象。
    • BeanFactory: 多例对象使用
      它再构建核心容器时,创建对象采取的策略是采用延迟加载的方式。什么时候根据id获取对象了,什么时候才真正创建对象
bean标签
  • 作用: 配置托管给spring的对象,默认情况下调用类的无参构造函数,若果没有无参构造函数则不能创建成功
  • 属性:
    • id: 指定对象在容器中的标识,将其作为参数传入getBean()方法可以获取获取对应对象.
    • class: 指定类的全类名,默认情况下调用无参构造函数
    • scope: 指定对象的作用范围,可选值如下
      • singleton: 单例对象,默认值
      • prototype: 多例对象
      • request: 将对象存入到web项目的request域中
      • session: 将对象存入到web项目的session域中
      • global session: 将对象存入到web项目集群的session域中,若不存在集群,则global session相当于session
    • init-method:指定类中的初始化方法名称,在对象创建成功之后执行
    • destroy-method:指定类中销毁方法名称,对prototype多例对象没有作用,因为多利对象的销毁时机不受容器控制
bean作用范围
  • scope="Singleton"单例对象
    • 作用范围:每个应用只有一个该对象的实例,它的作用范围就是整个应用
    • 生命周期: 单例对象的创建与销毁和容器的创建与销毁时机一致
      • 出生: 当应用加载,创建容器时,对象就被创建
      • 活着: 只要容器存在,对象一直活着
      • 死亡: 当应用卸载,销毁容器时,对象就被销毁
  • scope="prototype"多例对象
    • 作用范围: 每次访问对象时,都会重新创建对象实例.
    • 生命周期: 多例对象的创建与销毁时机不受容器控制
      • 出生: 当使用对象时,创建新的对象实例
      • 活着: 只要对象在使用中,就一直活着
      • 死亡: 当对象长时间不用时,被 java 的垃圾回收器回收了
创建bean的三种方式
  1. 使用默认构造函数创建。
    在spring配置文件中使用Bean标签,配以id和class属性之后,且没有其他属性和标签时。采用的就是默认构造函数创建bean对象,如果此类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.yll.service.impl.AccountServiceImpl"></bean>
  • 必须要有AccountServiceImpl构造函数
/**
 * 账户业务层实现类
 * */
public class AccountServiceImpl implements IAccountService {
    public AccountServiceImpl(){
        System.out.println("accountServiceImpl构造了");
    }
    
    public void saveAccount() {
        System.out.println("accountService……");
    }

    public void init() {
        System.out.println("init……");
    }

    public void destory()
    {
        System.out.println("destory……");
    }

}

  1. 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象。并存入spring容器)
  • 创建一个工厂
public class InstanceFactory {
    public IAccountService getAccountService(){
        return new AccountServiceImpl();
    }
}
<bean id="instanceFactory" class="com.yll.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
  • factory-bean属性:指定实例工厂的id
  • factory-method属性:指定实例工厂中生产对象的方法
  1. 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
  • 创建一个静态工厂 (静态方法不需要实例)
public class StaticFactory {
    public static IAccountService getAccountService(){
        return new AccountServiceImpl();
    }
}
<bean id="accountService" class="com.yll.factory.StaticFactory" factory-method="getAccountService"></bean>
使用注解实现IOC
用于创建对象的注解

这些注解的作用相当于bean.xml中的<bean>标签

  • @Component: 把当前类对象存入spring容器中,其属性如下:
    value: 用于指定当前类的id. 不写时默认值是当前类名,且首字母改小写

  • @Controller: 将当前表现层对象存入spring容器中

  • @Service: 将当前业务层对象存入spring容器中

  • @Repository: 将当前持久层对象存入spring容器中

    @Controller,@Service,@Repository注解的作用和属性与@Component是一模一样的,可以相互替代,它们的作用是使三层对象的分别更加清晰.

用于注入数据的注解

这些注解的作用相当于bean.xml中的<property>标签

  • @Autowired: 自动按照成员变量类型注入.
    • 注入过程
      • 当spring容器中有且只有一个对象的类型与要注入的类型相同时,注入该对象.
      • 当spring容器中有多个对象类型与要注入的类型相同时,使用要注入的变量名作为bean的id,在spring容器查找,找到则注入该对象.找不到则报错.
    • 出现位置: 既可以在变量上,也可以在方法上
    • 细节: 使用注解注入时,set方法可以省略
  • @Qualifier: 在自动按照类型注入的基础之上,再按照bean的id注入.
    • 出现位置: 既可以在变量上,也可以在方法上.注入变量时不能独立使用,必须和@Autowired一起使用; 注入方法时可以独立使用.
    • 属性:
      • value: 指定bean的id
  • @Resource: 直接按照bean的id注入,它可以独立使用.独立使用时相当于同时使用@Autowired@Qualifier两个注解.
    • 属性:
      • name: 指定bean的id
  • @Value: 注入基本数据类型和String类型数据
    • 属性:
      • value: 用于指定数据的值,可以使用Spel表达式(${表达式})
用于改变作用范围的注解

这些注解的作用相当于bean.xml中的<bean>标签的scope属性

  • Scope:指定bean的作用范围
    • 属性
      • value: 用于指定作用范围的取值"singleton","prototype","request","session","globalsession"
和生命周期相关的注解

这些注解的作用相当于bean.xml中的<bean>标签的init-methoddestroy-method属性

  • @PostConstruct: 用于指定初始化方法
  • @PreDestroy: 用于指定销毁方法
一个例子

AccountServiceImpl类

@Service(value = "accountService")
@Scope(value = "singleton")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    @Qualifier(value = "accountDao")
    private IAccountDao accountDao;

    @PostConstruct
    public void init(){
        System.out.println("初始化方法调用");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("销毁方法调用");
    }

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

表现层

public class Client {
    public static void main(String[] args) {
        //获取核心容器对象
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取对象
        IAccountService as = ac.getBean("accountService", IAccountService.class);
        IAccountService as2 = ac.getBean("accountService", IAccountService.class);
        System.out.println("是否为单例:"+as.equals(as2));
        as.saveAccount();
        ac.close();
    }
}

bean.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"
       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">

    <!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,
    而是一个名称为context名称空间和约束中-->
    <context:component-scan base-package="com.yll"></context:component-scan>
</beans>

依赖注入 DI

什么是DI?

  • 依赖注入(Dependency Injection)是spring框架核心ioc的具体实现.

  • 通过控制反转IOC,我们把创建对象托管给了spring,但是代码中不可能消除所有依赖,例如:业务层仍然会调用持久层的方法,因此业务层类中应包含持久化层的实现类对象.我们使用框架通过配置的方式将持久层对象传入业务层,而不是直接在代码中new某个具体的持久化层实现类,这种方式称为依赖注入.

依赖注入的方法

  • 因为我们是通过反射的方式来创建属性对象的,而不是使用new关键字,因此我们要指定创建出对象各字段的取值.
构造函数注入
  • 使用的标签constructor-arg
  • 出现的位置:bean标签内部
  • 标签的属性:
    • type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
    • index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引位置0开始
    • name:用于指定给构造函数中指定名称的参数赋值
      以上三个用于指定给构造函数中的哪个参数赋
    • value:用于提供基本类型和String类型的数据
    • ref:用于指定其他的bean类型数据,指的就是在spring的ioc核心容器中出现的bean对象
  • 优势:
    获取bean对象时,注入操作时必须的操作,否则对象无法创建
  • 弊端:
    改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据也必须提供
  1. 为要注入的类添加字段和构造函数
/**
 * 账户业务层实现类
 * */
public class AccountServiceImpl implements IAccountService {
    //如果是经常变化的数据,并不适用于注入
    private String name;
    private Integer age;
    private Date birthday;

    public AccountServiceImpl(String name,Integer age,Date birthday){
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public void saveAccount() {
        System.out.println("accountService……"+this.name+" "+this.age+" "+this.birthday);
    }
}

  1. 配置bean.xml
    <bean id="accountService" class="com.yll.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="test"/>
        <constructor-arg name="age" value="18" />
        <constructor-arg name="birthday" ref="now"/>
    </bean>
    <bean id="now" class="java.util.Date"></bean>
使用set注入(常用)
  • 涉及的标签:property
  • 出现的位置:bean标签内部
  • 标签的属性:
    • name:用于指定注入时所调用的set方法名称
    • value:用于提供基本类型和String类型的数据
    • ref:用于指定其他的bean类型数据,指的就是在spring的ioc核心容器中出现的bean对象
  • 优势:
    创建对象时没有明确的限制,可以直接使用默认构造函数
  • 弊端:
    如果某个成员必须有值,则获取对象时有可能set方法没有执行
  1. 为要注入的类添加Setter方法
/**
 * 账户业务层实现类
 * */
public class AccountServiceImpl2 implements IAccountService {
    //如果是经常变化的数据,并不适用于注入
    private String name;
    private Integer age;
    private Date birthday;

    public void setUserName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public void saveAccount() {
        System.out.println("accountService……"+this.name+" "+this.age+" "+this.birthday);
    }
}
  1. 配置注入bean.xml
    <bean id="accountService2" class="com.yll.service.impl.AccountServiceImpl2">
        <property name="userName" value="testname"/>
        <property name="age" value="20"/>
        <property name="birthday" ref="now"/>
    </bean>
  • 这里的name属性是setXXX的XXX,不一定非要是属性名
复杂类型的注入/集合类型的注入
  • 集合字段及其对应的标签按照集合的结构分为两类: 相同结构的集合标签之间可以互相替换.
  • 只有键的结构:
    • 数组字段:<array>标签表示集合,<value>标签表示集合内的成员.
    • List字段: <list>标签表示集合,<value>标签表示集合内的成员.
    • Set字段: <set>标签表示集合,<value>标签表示集合内的成员.

其中<array>,<list>,<set>标签之间可以互相替换使用.

  • 键值对的结构:
    • Map字段: <map>标签表示集合,<entry>标签表示集合内的键值对,其key属性表示键,value属性表示值.
    • Properties字段: <props>标签表示集合,<prop>标签表示键值对,其key属性表示键,标签内的内容表示值.
      其中<map>,<props>标签之间 <entry>,<prop>标签之间可以互相替换使用.
  1. 为注入的类添加复杂类型(集合)字段
package com.yll.service.impl;

import com.yll.service.IAccountService;

import java.util.*;

/**
 * 账户业务层实现类
 * */
public class AccountServiceImpl3 implements IAccountService {

    private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties myProps;

    public void setMyStrs(String[] myStrs) {
        this.myStrs = myStrs;
    }

    public void setMylist(List<String> mylist) {
        this.myList = mylist;
    }

    public void setMySet(Set<String> mySet) {
        this.mySet = mySet;
    }

    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    }

    public void setMyProps(Properties myProps) {
        this.myProps = myProps;
    }

    public void saveAccount() {
        System.out.println(Arrays.toString(myStrs));
        System.out.println(myList);
        System.out.println(myMap);
        System.out.println(mySet);
        System.out.println(myProps);
    }
}

  1. 配置bean.xml
 <bean id="accountService3" class="com.yll.service.impl.AccountServiceImpl3">
        <property name="myStrs">
            <array>
                <value>AAAA</value>
                <value>AssssAA</value>
                <value>AAAsssssA</value>
            </array>
        </property>
        <property name="mylist">
            <list>
                <value>list</value>
                <value>asssss</value>
                <value>ssss</value>
                <value>ylssssssss</value>
            </list>
        </property>
        <property name="mySet">
            <set>
                <value>ssssss</value>
                <value>sslllss</value>
                <value>ssmysetsss</value>
            </set>
        </property>
        <property name="myMap">
            <map>
                <entry key="test1" value="test1Value"></entry>
                <entry key="test2" ><value>test2Value</value></entry>
            </map>
        </property>
        <property name="myProps">
            <props>
                <prop key="testPro1">ssasdss</prop>
                <prop key="testPro2">ssssadsasdss</prop>
            </props>
        </property>
    </bean>

案例

纯xml配置案例

  1. 编写业务层
    IAccountService.java
public interface IAccountService {

    /**
     * 查询所有
     * @return
     */
    List<Account> findAllAccount();

    /**
     * 查询一个
     * @param id
     * @return
     */
    Account findAccountById(Integer id);

    /**
     *  保存操作
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新
     * @param account
     */
    void updateAccount(Account account);

    /**
     * 删除
     * @param id
     */
    void deleteAccount(Integer id);
}
  1. 业务层实现类 AccountServiceImpl.java,调用持久层对象的函数
public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public List<Account> findAllAccount() {
        return accountDao.findAllAccount();
    }

    @Override
    public Account findAccountById(Integer id) {
        return accountDao.findAccountById(id);
    }

    @Override
    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    @Override
    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    @Override
    public void deleteAccount(Integer id) {
        accountDao.deleteAccount(id);
    }

}
  1. 编写持久层
    IAccountDao.java
public interface IAccountDao {
    /**
     * 查询所有
     * @return
     */
    List<Account> findAllAccount();

    /**
     * 查询一个
     * @return
     */
    Account findAccountById(Integer id);

    /**
     *  保存操作
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新
     * @param account
     */
    void updateAccount(Account account);

    /**
     * 删除
     * @param id
     */
    void deleteAccount(Integer id);
}
  1. 持久层实现类AccountDaoImpl.java,完成数据库的操作
public class AccountDaoImpl implements IAccountDao {
    private QueryRunner runner;

    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

    @Override
    public List<Account> findAllAccount() {
        try {
            return runner.query("select * from account", new BeanListHandler<>(Account.class));
        } catch (SQLException e) {
            throw new RuntimeException();
        }
    }

    @Override
    public Account findAccountById(Integer id) {
        try {
            return runner.query("select * from account where id = ?", new BeanHandler<>(Account.class),id);
        } catch (SQLException e) {
            throw new RuntimeException();
        }
    }

    @Override
    public void saveAccount(Account account) {
        try {
            runner.update("insert into account(name,money) values(?,?)",account.getName(),account.getMoney());
        } catch (SQLException e) {
            throw new RuntimeException();
        }
    }

    @Override
    public void updateAccount(Account account) {
        try {
            runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
        } catch (SQLException e) {
            throw new RuntimeException();
        }
    }

    @Override
    public void deleteAccount(Integer id) {
        try {
            runner.update("delete from account where id=?",id);
        } catch (SQLException e) {
            throw new RuntimeException();
        }
    }

}
  1. 编写控制层
    Account.java
/**
 * 账户的实体类
 */
public class Account {
    private Integer id;
    private String name;
    private Float money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getMoney() {
        return money;
    }

    public void setMoney(Float money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

  1. 配置xml
    bean.xml,使用property代表需要提供setter方法注入
<?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">

    <!--配置Service-->
    <bean id="accountService" class="com.yll.service.impl.AccountServiceImpl">
        <!--注入dao-->
        <property name="accountDao" ref="accountDao"/>
    </bean>
    <!--配置Dao对象-->
    <bean id="accountDao" class="com.yll.dao.impl.AccountDaoImpl">
        <property name="runner" ref="queryRunner"/>
    </bean>
    <!--配置QueryRunner对象-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--注入数据源-->
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必要信息-->
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai"/>
        <property name="user" value="root"/>
        <property name="password" value="52151"/>
    </bean>
</beans>

  1. 编写测试类
/**
 * 使用junit单元测试配置
 */
public class AccountServiceTest {
    @Test
    public void testFindAll() {
        //1.获取容器
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        List<Account> accounts = as.findAllAccount();
        accounts.forEach(System.out::println);
    }
    @Test
    public void testFindOne() {
        //1.获取容器
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = as.findAccountById(1);
        System.out.println(account);
    }
    @Test
    public void testSave() {
        //1.获取容器
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = new Account();
        account.setName("test");
        account.setMoney(1234f);
        as.saveAccount(account);
        System.out.println(account);
    }
    @Test
    public void testUpdate() {
        //1.获取容器
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = as.findAccountById(1);
        account.setMoney(555f);
        as.updateAccount(account);
        System.out.println(account);
    }
    @Test
    public void testDelete() {
        //1.获取容器
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        as.deleteAccount(3);
    }
}

半注解配置案例

  1. 修改业务层
    删除setter,方法,改为注解形式
@Service("accountService")
public class AccountServiceImpl implements IAccountService {

    @Resource(name = "accountDao")
    private IAccountDao accountDao;
    .....
}

  1. 修改持久层
    删除setter方法,改为注解形式
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {

    @Resource(name = "queryRunner")
    private QueryRunner runner;
    ....
}
  1. 修改xml配置
  • 添加命名空间依赖,删除可用注解代替的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"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

    <context:component-scan base-package="com.yll"/>

    <!--配置QueryRunner对象-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--注入数据源-->
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必要信息-->
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai"/>
        <property name="user" value="root"/>
        <property name="password" value="52151"/>
    </bean>
</beans>

纯注解配置案例

  1. 新建一个总配置类 config.SpringConfiguration,并用注解配置扫描的包和子配置类的字节码
	/**
	 * 此类是配置类,和bean.xml作用一样
	 */
	@Configuration
	@ComponentScan(basePackages = "com.yll")
	@Import(JdbcConfig.class)
	public class SpringConfiguration {

	}
  1. 创建子配置类 config.jdbcConfiguration,并配置properties文件源,注入jdbc相关配置和bean
/**
 * 关于数据库的配置类
 */
@Configuration
@PropertySource("classpath:jdbcConfig.properties")
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    /**
     * 用于创建一个QueryRunner对象
     * @param dataSource 数据源
     * @return 对象
     */
    @Bean(name = "queryRunner")
    public QueryRunner createQueryRunner(DataSource dataSource){
        return new QueryRunner(dataSource);
    }

    /**
     * 创建数据源对象
     * @return
     */
    @Bean(name = "dataSource")
    @Scope("prototype")
    public DataSource createDataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        try {
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
        return dataSource;
    }
}
  1. 创建jdbc配置文件
    resources下创建配置文件jdbcConfig.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=52151
  1. 修改测试类
    将获取容器的实现类修改为AnnotationConfigApplicationContext
AbstractApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值