spring第二天IOC:使用注解进行依赖注入

基于注解开发,注解xml整合,纯注解,spring整合c3p0和dbUtils

使用之前的基于xml配置的项目进行一步步改造为纯注解
在这里插入图片描述
再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.itheima"/>
</beans>

之前的纯xml用<bean>标签来注入accountDao和accountService,现在只需加入component-scan标签

  • 曾经XML的配置:
 <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
 <property name=""  value="" | ref=""></property>
 </bean>
常用注解名词解释

用于创建对象的
他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的

  • Component:
    作用:用于把当前类对象存入spring容器中
    属性:value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。

Controller:一般用在表现层
Service:一般用在业务层
Repository:一般用在持久层

  •  以上三个注解他们的作用和属性与Component是一模一样。
    

它们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰


用于注入数据的
他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的

  • Autowired:
    作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
    如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
    如果Ioc容器中有多个类型匹配时:
    出现位置:
    可以是变量上,也可以是方法上

细节:

  • 在使用注解注入时,之前使用的xml注入的set方法就不是必须的了。
  • Qualifier:
    作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(在Autowired下)
    属性:
    value:用于指定注入bean的id。
  • Resource
    作用:直接按照bean的id注入。它可以独立使用
    属性:
    name:用于指定bean的id。
  • 以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
  • 另外,集合类型的注入只能通过XML来实现。

  • Value
    作用:用于注入基本类型和String类型的数据
    属性:
    value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
    SpEL的写法:${表达式}

  • 用于改变作用范围的
    他们的作用就和在bean标签中使用scope属性实现的功能是一样的
    Scope
    作用:用于指定bean的作用范围
    属性:
    value:指定范围的取值。常用取值:singleton prototype

  • 和生命周期相关
    他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
    PreDestroy
    作用:用于指定销毁方法
    PostConstruct
    作用:用于指定初始化方法


AccountServiceImpl:

 @Component
 //把当前类对象存入spring容器中
public class AccountServiceImpl implements IAccountService {
        @Autowired
        @Qualifier("accountDao2")//按照名称注入 
         private IAccountDao accountDao;
	
	//public void setAccountDao(IAccountDao accountDao) {
    //    this.accountDao = accountDao;
    //}
    
    public void  saveAccount(){
        int i = 1;
        accountDao.saveAccount();
        System.out.println(i);
        i++;
    }
}

在开发中业务层就直接用@Service来注解了

Dao包中有两个accountDao和accountDao2,有多个对象,则按照名称注入,不然会报错
此时的accountDao的set方法就不需要了

@Repository("accountDao1")
public class AccountDaoImpl implements IAccountDao {

    public  void saveAccount(){

        System.out.println("保存了账户1111111111111111");
    }
}

在持久层中使用Repository将dao注入spring容器中

@Repository("accountDao2")
public class AccountDaoImpl2 implements IAccountDao {

    public  void saveAccount(){

        System.out.println("保存了账户22222222222");
    }
}

spring整合c3p0和dbUtils **************

在这里插入图片描述
首先引入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
    </dependencies>

其中spring-test标签就是spring和JUnit整合的依赖
添加此标签就在测试类上使用spring的注解了

先使用xml配置

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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注入service-->
    <bean id="accountService" class="com.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!-- 提供dao的ref -->
    <bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
        <property name="runner" ref="runner"></property>
    </bean>

    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!-- constructor-arg用于注入其他bean类型 -->
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>
    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 连接数据库的信息 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean> 
</beans>

复习:constructor-arg用于注入其他bean类型
然后在实现CRUD以及通过id查询的方法
(其他方法省略,这里只贴dao的实现类)
AccountDaoImpl:

public class AccountDaoImpl implements AccountDao {

    private QueryRunner runner;
	//注意此处使用set注入
    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

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

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

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

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

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

测试类:AccountServiceTest
此处是经过注解改造的,目的是减少代码的重复,

		//获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //得到业务层对象
        AccountService as =  ac.getBean("accountService",AccountService.class);

不需要再重复的使用getBean()来得到bean.xml配置文件了

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {
    @Autowired
    private AccountService as = null;

    @Test
    public void testFindAll(){
        List<Account> accounts =  as.findAllAccount();
        for(Account account:accounts){
            System.out.println(account);
        }

    }
    @Test
    public void testFindOne(){
        Account account = as.findAccountById(3);
        System.out.println(account);
    }
    @Test
    public void testSave(){
        Account account = new Account();
        account.setMoney(1000.0);
        account.setName("name");
        as.saveAccount(account);
    }
    @Test
    public void testUpdate(){
        Account account = new Account();
        account.setMoney(10100.0);
        account.setName("name2");
        account.setId(4);

        as.updateAccount(account);
    }
    @Test
    public void testDelete(){

        as.deleteAccount(2);
    }

}

  • 使用Junit单元测试:测试我们的配置
  • Spring整合junit的配置
    1、导入spring整合junit的jar(坐标)
    2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
  • @Runwith
    3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
  • @ContextConfiguration
    locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
    classes:指定注解类所在地位置
    当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
使用注解方法

使用注解,首先将bean.xml的约束换成注解的约束,然后告诉spring要扫描的包
AccountServiceImpl中要使用AccountDao,所以要注入,使用@Service和@Autowried来注入(因为只需在AccountServiceImpl注入一个对象,就只用Autowried)
AccountDaoImpl需要使用QueryRunner,因为是在持久层,所以使用@Repository和@Autowried来注入
此时的测试类并没有用注解来优化,所以有很多的重复代码

public class AccountServiceTest {
    @Test
    public void testFindAll(){
        //获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //得到业务层对象
        AccountService as =  ac.getBean("accountService",AccountService.class);
        List<Account> accounts =  as.findAllAccount();
        for(Account account:accounts){
            System.out.println(account);
        }

    }
    @Test
    public void testFindOne(){
        //获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //得到业务层对象
        AccountService as =  ac.getBean("accountService",AccountService.class);
        Account account = as.findAccountById(3);
        System.out.println(account);
    }
    @Test
    public void testSave(){
        Account account = new Account();
        account.setMoney(1000.0);
        account.setName("欧美");
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //得到业务层对象
        AccountService as =  ac.getBean("accountService",AccountService.class);
        as.saveAccount(account);
    }
    @Test
    public void testUpdate(){
        Account account = new Account();
        account.setMoney(10100.0);
        account.setName("欧美2");
        account.setId(4);
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //得到业务层对象
        AccountService as =  ac.getBean("accountService",AccountService.class);
        as.updateAccount(account);
    }
    @Test
    public void testDelete(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //得到业务层对象
        AccountService as =  ac.getBean("accountService",AccountService.class);
        as.deleteAccount(2);
    }

}
纯注解实现

要改造成纯注解,就是要不使用bean.xml,而单纯的用注解实现,但是现在先不删除bean.xml,因为里面的很多东西还有用(等一下用到了再复制粘贴,用完再删)
目光放到bean.xml中数据源的注入,此时已经将各个字段写死了,按照以往的经验,可以将其写到一个properties文件中,创建一个jdbcConfig.properties文件,按照key,value格式来取数据

jdbc.Driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=123456

然后创建一个springConfiguration
在这里插入图片描述

@ComponentScan("com")
@Import(JDBCConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class springConfiguration {



}
  • 该类是一个配置类,它的作用和bean.xml是一样的
  • spring中的新注解
  • Configuration
    作用:指定当前类是一个配置类
    细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
  • ComponentScan
    作用:用于通过注解指定spring在创建容器时要扫描的包
    属性:
    value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
    我们使用此注解就等同于在xml中配置了:
    <context:component-scan base-package=“com.itheima”></context:component-scan>
  • Bean
    作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
    属性:
    name:用于指定bean的id。当不写时,默认值是当前方法的名称
    细节:
    当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
    查找的方式和Autowired注解的作用是一样的
  • Import
    作用:用于导入其他的配置类
    属性:
    value:用于指定其他配置类的字节码。
    当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
  • PropertySource
    作用:用于指定properties文件的位置
    属性:
    value:指定文件的名称和路径。
    关键字:classpath,表示类路径下

用import导入其他的配置类

public class JDBCConfig {
    @Value("${jdbc.Driver}")
    private String driver;
	//此处使用了SpEL的写法:${表达式}
    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 创建一个queryRunner对象
     * @return
     */
    @Bean(name = "runner")
    public QueryRunner createQueryRunner(@Qualifier("ds1") DataSource dataSource){
        return new QueryRunner(dataSource);
    }
	//调用多个数据库
    @Bean(name = "ds2")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Bean(name = "ds1")
    public DataSource createDataSource1(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/eesy02");
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

此处使用了SpEL的写法:${表达式}
现在就可以删掉bean.xml文件了
如果有调用多个数据库的需求,这时候的数据源就有两个,这时候就可以在获取QueryRunner的createQueryRunner()方法的参数中加入注解@Qualifier(“ds1”) ,用来指定数据源。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值