• Spring之依赖注入


    前言

    上文说道Spring IOC思想:

    Spring的IOC容器通过读取spring配置文件,可以帮助我们创建各种各样的对象,以实现调用方和被调用方在编译阶段的解耦 ,这些由Spring IOC创建出来的对象统称为Bean;

    当我们把通过spring配置文件把需要的bean放到spring的IOC容器之后,如果这些容器中对象需要调用容器中其他对象,应该如何操作呢?  

    这就需要spring的依赖注入技术,容器+依赖注入(Dependency injection)实现Spring IOC思想:

    当1个bean对象的控制权由调用方转交给spring的IOC容器之后;

    我们可以通过Spring的xml配置文件或者注解,完成当前bean对象的依赖注入,去调用其他bean对象;

    一、Bean的作用域

    在Spring中,bean支持多种作用域如下所示,我们可以通过配置文件和注解进行配置;

    • singleton(默认) 单例模式:即对象创建1次,创建之后一直存在,除非Spring IOC容器关闭;
    • prototype 多例模式:即每次获取bean的时候,IOC都给我们创建一个新对象
    • request域中生效:Spring创建一个Bean的对象,将对象存入到request域中
    • session域中生效:Spring创建一个Bean的对象,将对象存入到session域中

     1.Bean单例模式配置

    <bean scope="singleton" id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">

     2.Bean多例模式配置

    <bean scope="prototype" id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">

    二、Bean的生命周期

    生命周期指得是1个事物,从创建到销毁的过程; 

    在Spring中,bean的作用范围会影响到其生命周期,所以我们要分单例和多例对象来研究bean的生命周期

    init-method:指定的方法在当前对象(bean)创建之后执行

    destroy-method指定的方法在当前对象(bean)销毁之前执行

     <bean init-method="UserDao" destroy-method="destory" id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">

    1.单例模式下bean的生命周期

    创建:在容器创建的时候

    销毁:在容器销毁的时候

    2.多例模式下bean的生命周期

    创建:每次调用getBean获取对象的时候

    销毁:Spring不知道多例模式下,对象什么时候销毁;(bean创建之后Spring IOC容器就把对象交出去了,此时Spring IOC容器不再拥有bean的控制权);

    三、Bean的依赖注入

    依赖注入(Dependency Injection,DI) 其实就是给对象(bean)中的属性赋值

    以下两种方式,都可以实现依赖注入,使用原则是能用set方法进行依赖注入尽量不使用构成函数

    • 使用构造函数:如果类是别人写的,没有set方法时使用;
    • set方法:          推荐使用

    1.通过构造函数进行依赖注入

    在bean标签中嵌套constructor-arg标签可以完成bean对象构造函数赋值; 

    1.1.在类中添加有参构造

    public class UserDaoImpl implements UserDao {
        private String name;
        private Integer age;
        private Date brithday; //对象属性
    
        //添加无参构造器
        public UserDaoImpl() {
    
        }
    
        //添加全参构造器
        public UserDaoImpl(String name, Integer age, Date brithday) {
            this.name = name;
            this.age = age;
            this.brithday = brithday;
        }

    1.2.通过配置文件配置属性的值

     <!--相当于创建了1个对象Date brithday=new Date(); -->
        <bean id="date" class="java.util.Date"></bean>
        <!--
        constructor-arg:构造函数完成依赖注入
        name="name":指定构造器中形参的名称
        value="张根":指定给当前属性赋的值【简单类型:基本类型+基本类型包装类+String】
        vref="张根":指定给当前属性赋的值【引用类型】
    
        -->
        <bean id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">
            <constructor-arg name="name" value="张根"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
            <constructor-arg name="brithday" ref="date"></constructor-arg>
        </bean>

    1.3.测试

    UserDaoImpl{name='张根', age=18, brithday=Wed May 18 21:08:06 CST 2022}

    2.通过set方法进行依赖注入

    在bean标签中嵌套property 标签可以完成bean对象构造函数赋值; 

    2.1.在类中提供属性的set方法

    //在类中提供属性的set()方法
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Date getBrithday() {
            return brithday;
        }
    
        public void setBrithday(Date brithday) {
            this.brithday = brithday;
        }

    2.2.在配置文件中设置属性的值

      <!--相当于创建了1个对象Date brithday=new Date(); -->
        <bean id="date" class="java.util.Date"></bean>
        <!--
        property:set方法完成依赖注入
        name="name":指定构造器中形参的名称
        value="张根":指定给当前属性赋的值【简单类型:基本类型+基本类型包装类+String】
        vref="张根":指定给当前属性赋的值【引用类型】
        -->
        <bean id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">
            <property name="name" value="张根"></property>
            <property name="age" value="18"></property>
            <property name="brithday" ref="date"></property>
        </bean>

    2.3.测试

    UserDaoImpl{name='张根', age=18, brithday=Wed May 18 21:27:22 CST 2022}

    3.注入集合属性

    在property 标签嵌套list、set、array、map标签,可以对bean对象的集合属性赋值;

    3.1.增加集合复杂属性

    package com.zhanggen.dao.impl;
    
    import com.zhanggen.dao.UserDao;
    
    import java.util.*;
    
    public class UserDaoImpl implements UserDao {
        //简单类型属性
        private String name;
        private Integer age;
        //对象属性
        private Date brithday;
        //集合复杂属性
        private Set<String> mySet;
        private List<String> myList;
        private String[] myArr;
        private Map<String, String> myMap;
    
        //在类中提供属性的set()方法
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Date getBrithday() {
            return brithday;
        }
    
        public void setBrithday(Date brithday) {
            this.brithday = brithday;
        }
    
        public Set<String> getMySet() {
            return mySet;
        }
    
        public void setMySet(Set<String> mySet) {
            this.mySet = mySet;
        }
    
        public List<String> getMyList() {
            return myList;
        }
    
        public void setMyList(List<String> myList) {
            this.myList = myList;
        }
    
        public String[] getMyArr() {
            return myArr;
        }
    
        public void setMyArr(String[] myArr) {
            this.myArr = myArr;
        }
    
        public Map<String, String> getMyMap() {
            return myMap;
        }
    
        public void setMyMap(Map<String, String> myMap) {
            this.myMap = myMap;
        }
    
        public void save() {
            System.out.println("用户保存成功");
        }
    
        @Override
        public String toString() {
            return "UserDaoImpl{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", brithday=" + brithday +
                    ", mySet=" + mySet +
                    ", myList=" + myList +
                    ", myArr=" + Arrays.toString(myArr) +
                    ", myMap=" + myMap +
                    '}';
        }
    }
    UserDaoImpl.java

    3.2.配置文件赋值

       <bean id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">
            <property name="name" value="张根"></property>
            <property name="age" value="18"></property>
            <property name="brithday" ref="date"></property>
            <property name="myList">
                <list>
                    <value>林心如</value>
                    <value>范冰冰</value>
                </list>
            </property>
            <property name="mySet">
                <set>
                    <value>CC</value>
                    <value>DD</value>
                </set>
            </property>
            <property name="myArr">
                <array>
                    <value>奔驰</value>
                    <value>宝马</value>
                </array>
            </property>
            <property name="myMap">
                <map>
                    <entry key="key1" value="18"></entry>
                    <entry key="key2" value="19"></entry>
                </map>
            </property>
        </bean>

    3.3.测试

    
    

    UserDaoImpl{name='张根', age=18, brithday=Wed May 18 21:50:56 CST 2022, mySet=[CC, DD], myList=[林心如, 范冰冰], myArr=[奔驰, 宝马], myMap={key1=18, key2=19}}

     

    四、多配置文件使用

    我们现在的配置都集中配在了一个applicationContext.xml文件中,这样会使这个文件很难维护。

    针对这个问题,Spring给我们提供了两种解决方案:

    • 在创建springIOC容器的时,同时引入多个配置文件
    • 在主配置文件中引入其他配置文件

     注意:

    • 同一个xml文件中不允许出现相同id的bean,如果出现会报错
    • 多个xml文件如果出现相同id的bean,不会报错,但是后加载的会覆盖前加载,所以尽量保证bean的名称是唯一的

    1.同时引入多个配置文件

    在创建spring IOC容器时一次读取多个配置文件

     //1.读取多个配置文件,初始化SpringIOC容器
     ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml","dateBean.xml");

    2.引入1个主配置文件

    spring IOC使用1个主配置文件,在主配置文件中引入其他配置文件

    <!--引入其他配置文件-->
    <import resource="dateBean.xml"></import>

     五、Spring IOC实现service和dao层(配置文件版本)

     通过配置文件配置spring的IOC容器,实现service层和dao层解耦;

    1.添加依赖

    <?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">
        <parent>
            <artifactId>spring</artifactId>
            <groupId>com.zhanggen</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>day02-01-jt</artifactId>
        <dependencies>
            <!--spring核心-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.1.6.RELEASE</version>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <!--druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.15</version>
            </dependency>
    
            <!--jdbcTemplate依赖所在-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.1.6.RELEASE</version>
            </dependency>
    
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.20</version>
            </dependency>
    
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
            </dependency>
        </dependencies>
    
    
    </project>
    pom.xml

    2.定义dao层接口

    package com.zhanggen.dao;
    
    import com.zhanggen.domain.Account;
    
    import java.util.List;
    
    public interface AccountDao {
        //保存
        void save(Account account);
    
        //查询所有
        List<Account> queryAll();
    
        //查询1条记录(根据name)
        Account queryByName(String name);
    
        //修改(根据name修改余额balance)
        void update(Account account);
    
        //删除(根据主键删除)
        void delete(Integer aid);
    }
    AccountDao.interface

    3.创建dao层实现类

    package com.zhanggen.dao.impl;
    
    import com.zhanggen.dao.AccountDao;
    import com.zhanggen.domain.Account;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import java.util.List;
    
    public class AccountDaoImpl implements AccountDao {
        //Spring的思想:需要对象了不能自己new了,而是向Spring 要1个bean
        private JdbcTemplate jdbcTemplate;//=new JdbcTemplate();
    
        //期望Spring依赖注入
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        @Override
        public void save(Account account) {
            jdbcTemplate.update("insert into account values (null,?,?)", account.getName(), account.getBalance());
        }
    
        @Override
        public List<Account> queryAll() {
            List<Account> accountList = jdbcTemplate.query("select * from account;", new BeanPropertyRowMapper<Account>(Account.class));
            return accountList;
        }
    
        @Override
        public Account queryByName(String name) {
            Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), name);
            return account;
        }
    
        @Override
        public void update(Account account) {
            jdbcTemplate.update("update account set balanc=? where name=?", account.getBalance(), account.getName());
        }
    
        @Override
        public void delete(Integer aid) {
            jdbcTemplate.update("delete from account where aid=?", aid);
    
        }
    }
    AccountDaoImpl.java

    4.定义service层接口

    service层不对dao层数据进行任何数据加工, 所以和dao层接口一致;

    package com.zhanggen.serive;
    
    import com.zhanggen.domain.Account;
    
    import java.util.List;
    
    public interface AccountService {
        //保存
        void save(Account account);
    
        //查询所有
        List<Account> queryAll();
    
        //查询1条记录(根据name)
        Account queryByName(String name);
    
        //修改(根据name修改余额balance)
        void update(Account account);
    
        //删除(根据主键删除)
        void delete(Integer aid);
    }
    AccountService.interface

    5.创建service层实现类

    package com.zhanggen.serive.impl;
    
    import com.zhanggen.dao.AccountDao;
    import com.zhanggen.domain.Account;
    import com.zhanggen.serive.AccountService;
    
    import java.util.List;
    
    public class AccountServiceImpl implements AccountService {
        private AccountDao accountDao;
    
        //Spring注入
        public void setAccountDao(AccountDao accountDao) {
            this.accountDao = accountDao;
        }
    
        @Override
        public void save(Account account) {
            accountDao.save(account);
        }
    
        @Override
        public List<Account> queryAll() {
            List<Account> accountList = accountDao.queryAll();
            return accountList;
        }
    
        @Override
        public Account queryByName(String name) {
            Account account = accountDao.queryByName(name);
            return account;
        }
    
        @Override
        public void update(Account account) {
            accountDao.update(account);
        }
    
        @Override
        public void delete(Integer aid) {
            accountDao.delete(aid);
        }
    }
    AccountServiceImpl.java

    6.加入spring的配置文件

    就是到service层的实现类对象、dao层实现类对象,以及相关依赖都放到spring的IOC容器中,由spring的IOC容器进行管理;

    <?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:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                             http://www.springframework.org/schema/context
                             http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    
        <!--
        druidDataSource对象放到容器
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8");
        druidDataSource.setUsername("zhanggen");
        druidDataSource.setPassword("123.com");
        -->
        <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"></property>
            <property name="username" value="zhanggen"></property>
            <property name="password" value="123.com"></property>
        </bean>
        <!--
        jdbcTemplate对象放到容器
          JdbcTemplate jdbcTemplate = new JdbcTemplate(druidDataSource);
        -->
        <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <constructor-arg name="dataSource" ref="druidDataSource"></constructor-arg>
            <!--<property name="dataSource" ref="druidDataSource"></property>-->
        </bean>
        <!--dao对象放入容器-->
        <bean id="accountDao" class="com.zhanggen.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="JdbcTemplate"></property>
        </bean>
    
        <!--
            servicl对象放到spring容器
            AccountService accountService=new AccountServiceImpl();
            accountService.setAccountDao(accountDao);
            -->
        <bean id="accountService" class="com.zhanggen.serive.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>
    
    </beans>
    applicationContext.xml

    7.测试

    创建spring的IOC容器,从spring的IOC容器中获取service层对象;

    package com.zhanggen.test;
    
    import com.zhanggen.domain.Account;
    import com.zhanggen.serive.AccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.List;
    
    public class AccountServiceTest {
        @Test
        public void testQueryAll() {
            //1.初始化Spring的IOC容器
            ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
            //2.从Spring的IOC容器中获取AccountService的实现类对象
            AccountService accountService = act.getBean(AccountService.class);
            List<Account> accountList = accountService.queryAll();
            for (Account account : accountList) {
                System.out.println(account);
            }
        }
    }
    AccountServiceTest.java

     

     五、常用注解

    首先明确注解就是对原来XML配置的简化,2者实现的功能是一样的。

    1.对象(bean)创建注解

    以下注解用于在spring的IOC容器中创建对象(bean);

    1.1.@Component注解

    用于实例化对象,相当于配置文件中的<bean id="" class=""/>
    它支持一个属性value,相当于xml中bean的id,如果不写,默认值为类名的首字母小写

    1.2.@Controller @Service @Repository

    这3个注解的功能跟@Component类似,他们分别标注在不同的层上。

    • @Controller 标注在表示层的类上
    • @Service 标注在业务层的类上
    • @Repository 标注在持久层的类上

    推荐使用这三个,当一个类实在不好归属在这三个层上时,再使用@Component

    2.bean的作用域

    @Scope用于指定bean的作用范围(单例和多例),相当于配置文件中的<bean scope="">

    @Repository
    @Scope("singleton")
    public class AccountDaoImpl implements AccountDao {

    3.bean的生命周期注解

    @PostConstruct:此注解标注的方法会在当前对象创建之后自动执行

    @PreDestroy:此注解标注的方法会在当前对象销毁之前自动执行

    相当于<bean init-method="init" destroy-method="destory" />

    //标注在类上表示使用AccountDaoImpl实现类创建1个对象放入spring的IOC容器里面
    //@Component("accountDao") //定义当前对象在spring的IOC容器中表示,相当于xml的id,如果不声明id默认为当前类名首字母变小写
    @Repository
    @Scope("singleton")
    public class AccountDaoImpl implements AccountDao {
    
        public void save() {
            System.out.println("保存成功了.....");
        }
        @PostConstruct//此注解标注的方法会在当前对象创建之后自动执行
        public void init() {
            System.out.println("对象创建完毕了.....");
        }
        @PreDestroy //此注解标注的方法会在当前对象销毁之前自动执行
        public void destory() {
            System.out.println("对象即将销毁.....");
        }
    
    }

    4.对象依赖的注入

    其实大部分注入的依赖都是对象,如1个对象(bean)中的属性是另1个对象时,就需要进行对象依赖注入;

    4.1. @Autowired

    这个注解表示依赖注入,可以标注在属性上,也可以标注在方法上,当@Autowired标注在属性上的时候,属性对应的set方法可以省略不写

    4.2. @Qualifier

    跟@Autowired联合使用,代表在按照类型匹配的基础上,再按照名称匹配

    4.3.自动注入依赖原理

    @Autowired:Spring会在他的IOC容器中按照被标注属性的类型进行寻找,如果查找到了一个就进行注入,如果查找不到或者查找到多个就报错

    @Qualifier:   跟@Autowired联合使用,代表在按照类型匹配的基础上,再按照名称匹配

    5.注解总结

    spring容器是IOC思想的载体和体现;

    @Component、@Controller/@Service/@Repository是把当前对象放到spring容器中;

    @Autowired、@Qualifier是指定当前bean对象,需要依赖哪些spring的容器中bean对象;

    getBean():1个对象的所有属性赋值(注入)成功之后,再向spring的IOC容器要出这个对象,调用该对象的方法;

    xml配置注解配置说明
    < bean id="" class="" > @Component、@Controller/@Service/@Repository bean的实例化
    < property name="" ref=""> @Autowired、@Qualifier bean的对象属性注入
    < property name="" value=""> @Value bean的简单属性注入
    < bean scope=""> @Scope 控制bean的作用范围
    < bean init-method="init" destroy-method="destory" /> @PostConstruct、@PreDestroy bean创建之后和销毁之前调用

     

    6.常用注解实现service和dao层

    我们自己写的类(service层和dao层实现类)使用注解配置, 第三方的类(JdbcTemplate和Druid类对象)继续使用xml配置,实现web应用的service和dao层;

    6.1.spring配置文件

    <?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-3.0.xsd
                             http://www.springframework.org/schema/context
                             http://www.springframework.org/schema/context/spring-context-3.0.xsd">
        <!--注解扫描-->
        <context:component-scan base-package="com.zhanggen"></context:component-scan>
    
        <!--
        druidDataSource对象放到容器
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8");
        druidDataSource.setUsername("zhanggen");
        druidDataSource.setPassword("123.com");
        -->
        <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"></property>
            <property name="username" value="zhanggen"></property>
            <property name="password" value="123.com"></property>
        </bean>
        <!--
        jdbcTemplate对象放到容器
          JdbcTemplate jdbcTemplate = new JdbcTemplate(druidDataSource);
        -->
        <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <constructor-arg name="dataSource" ref="druidDataSource"></constructor-arg>
            <!--<property name="dataSource" ref="druidDataSource"></property>-->
        </bean>
    
    </beans>
    applicationContext.xml

    6.2.dao层

    package com.zhanggen.dao.impl;
    
    import com.zhanggen.dao.AccountDao;
    import com.zhanggen.domain.Account;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    @Repository
    public class AccountDaoImpl implements AccountDao {
        //Spring的思想:需要对象了不能自己new了,而是向Spring 要1个bean
        @Autowired
        private JdbcTemplate jdbcTemplate;//=new JdbcTemplate();
    
        @Override
        public void save(Account account) {
            jdbcTemplate.update("insert into account values (null,?,?)", account.getName(), account.getBalance());
        }
    
        @Override
        public List<Account> queryAll() {
            List<Account> accountList = jdbcTemplate.query("select * from account;", new BeanPropertyRowMapper<Account>(Account.class));
            return accountList;
        }
    
        @Override
        public Account queryByName(String name) {
            Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), name);
            return account;
        }
    
        @Override
        public void update(Account account) {
            jdbcTemplate.update("update account set balanc=? where name=?", account.getBalance(), account.getName());
        }
    
        @Override
        public void delete(Integer aid) {
            jdbcTemplate.update("delete from account where aid=?", aid);
    
        }
    }
    AccountDaoImpl.java

    6.3.service层

    package com.zhanggen.serive.impl;
    
    import com.zhanggen.dao.AccountDao;
    import com.zhanggen.domain.Account;
    import com.zhanggen.serive.AccountService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    //把AccountServiceImpl对象放到spring的容器中
    @Service
    public class AccountServiceImpl implements AccountService {
        //去spring的容器中自动寻找AccountDao类型的bean进行依赖注入
        @Autowired
        private AccountDao accountDao;
    
        @Override
        public void save(Account account) {
            accountDao.save(account);
        }
    
        @Override
        public List<Account> queryAll() {
            List<Account> accountList = accountDao.queryAll();
            return accountList;
        }
    
        @Override
        public Account queryByName(String name) {
            Account account = accountDao.queryByName(name);
            return account;
        }
    
        @Override
        public void update(Account account) {
            accountDao.update(account);
        }
    
        @Override
        public void delete(Integer aid) {
            accountDao.delete(aid);
        }
    }
    AccountServiceImpl.java

    6.4.测试

    package com.zhanggen.test;
    
    import com.zhanggen.domain.Account;
    import com.zhanggen.serive.AccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.List;
    
    public class AccountServiceTest {
        @Test
        public void testQueryAll() {
            //1.初始化Spring的IOC容器
            ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
            //2.从Spring的IOC容器中获取AccountService的实现类对象
            AccountService accountService = act.getBean(AccountService.class);
            List<Account> accountList = accountService.queryAll();
            for (Account account : accountList) {
                System.out.println(account);
            }
        }
    }
    AccountServiceTest.java

      

    六、纯注解

    随着SpringBoot的兴起,纯注解方式也变得越来越重要;

    纯注解就是将xml中的所有 配置项、自己写的类和第三方提供类,全部使用注解实现对象的实例化,并放到spring的容器中 。

    @ComponentScan注解作用:扫描指定注解的类注册到IOC容器中;

    @ComponentScan用于类或接口上主要是指定扫描路径,spring会把指定路径下带有指定注解的类注册到IOC容器中。

    会被自动装配的注解包括@Controller、@Service、@Component、@Repository等等。

    其作用等同于<context:component-scan base-package="com.maple.learn" />配置。

     

    1.创建注解配置类

    将原来spring配置文件中配置全部转换成1个Java类,这个Java类叫spring 配置类;

    xml中的bean标签,转换成方法;

    xml中非bean标签(如ComponentScan注解扫描),转换成方法的注解;

    package com.zhanggen.config;
    
    import com.alibaba.druid.pool.DruidAbstractDataSource;
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import javax.sql.DataSource;
    
    //把spring配置中的配置内容,全部转换到当前配置类
    /*
    bean标签---->方法
    非bean标签(例如ComponentScan注解扫描)---->方法的注解
    */
    @ComponentScan("com.zhanggen") //注解扫描
    public class SpringConfig {
        /*
        编写1个方法,在方法中去创建对应对象,并且通过@bean注解来标识该方法
        @Bean注解仅仅可以够标注在方法上,作用是将标注方法的返回值放到spring的容器
        如果当前方法需要参数,@Bean可以自动从spring的容器中根据该参数类型查询(dl)到该参数,自动完成依赖注入
        @Bean("druidDataSource")此注解可以声明bean的id,默认为getDataSource
        */
        @Bean("druidDataSource")
        public DataSource getDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8");
            dataSource.setUsername("zhanggen");
            dataSource.setPassword("123.com");
            return dataSource;
        }
    
    
        //@Bean注解:自动从spring的容器中根据dataSource参数声明的DataSource类型,查询(dl)到dataSource参数,自动完成依赖注入
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
    }
    SpringConfig.java

    2.提取外部properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8
    jdbc.username=zhanggen
    jdbc.password=123.com
    db.properties

    --------------------------------------------------------------------------------------------------------------

    @PropertySource("db.properties")//导入类路径下某一个配置文件

    @Value():用于给对象中简单属性进行赋值

    package com.zhanggen.config;
    
    import com.alibaba.druid.pool.DruidAbstractDataSource;
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import javax.sql.DataSource;
    
    //把spring配置中的配置内容,全部转换到当前配置类
    /*
    bean标签---->方法
    非bean标签(例如ComponentScan注解扫描)---->方法的注解
    */
    @ComponentScan("com.zhanggen") //注解扫描
    @PropertySource("db.properties")//导入类路径下某一个配置文件
    public class SpringConfig {
        /*
        编写1个方法,在方法中去创建对应对象,并且通过@bean注解来标识该方法
        @Bean注解仅仅可以够标注在方法上,作用是将标注方法的返回值放到spring的容器
        如果当前方法需要参数,@Bean可以自动从spring的容器中根据该参数类型查询(dl)到该参数,自动完成依赖注入
        @Bean("druidDataSource")此注解可以声明bean的id,默认为getDataSource
        */
    
        // @Value():用于给对象中简单属性进行赋值
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean("druidDataSource")
        public DataSource getDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
    
    
        //@Bean注解:自动从spring的容器中根据dataSource参数声明的DataSource类型,查询(dl)到dataSource参数,自动完成依赖注入
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
    }
    SpringConfig.java

    3.多配置类

    spring的IOC容器创建时,可以1次加载多个配置文件(配置类),也可以先加载1个主配置文件(配置类),再由主配置文件加载其他配置文件(配置类);

    3.1.方式1

    Spring的容器实创建时,1次加载2个配置文件

    package com.zhanggen.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.PropertySource;
    
    import javax.sql.DataSource;
    //导入类路径下某一个配置文件
    @PropertySource("db.properties")
    public class DbConfig {
        // @Value():用于给对象中简单属性进行赋值
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean("druidDataSource")
        public DataSource getDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
    }
    DbConfig.java

    ------------------------------------------------------------------------------------------------------------

    package com.zhanggen.config;
    
    import com.alibaba.druid.pool.DruidAbstractDataSource;
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import javax.sql.DataSource;
    
    //把spring配置中的配置内容,全部转换到当前配置类
    /*
    bean标签---->方法
    非bean标签(例如ComponentScan注解扫描)---->方法的注解
    */
    @ComponentScan("com.zhanggen") //注解扫描
    public class SpringConfig {
        /*
        编写1个方法,在方法中去创建对应对象,并且通过@bean注解来标识该方法
        @Bean注解仅仅可以够标注在方法上,作用是将标注方法的返回值放到spring的容器
        如果当前方法需要参数,@Bean可以自动从spring的容器中根据该参数类型查询(dl)到该参数,自动完成依赖注入
        @Bean("druidDataSource")此注解可以声明bean的id,默认为getDataSource
        */
        //@Bean注解:自动从spring的容器中根据dataSource参数声明的DataSource类型,查询(dl)到dataSource参数,自动完成依赖注入
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
    }
    SpringConfig.java

    ---------------------------------------------------------------------------------------------------

      ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class, DbConfig.class);

    3.2.方式2

    Spring的容器实创建时,先加载1个主配置文件,在由主配置文件加载其他子配置文件;

    @Import(DbConfig.class) //从1个配置类中导入另1个配置类;

    package com.zhanggen.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.PropertySource;
    
    import javax.sql.DataSource;
    //导入类路径下某一个配置文件
    @PropertySource("db.properties")
    public class DbConfig {
        // @Value():用于给对象中简单属性进行赋值
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean("druidDataSource")
        public DataSource getDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
    }
    DbConfig.java

    ------------------------------------------------------------------------------------------------------------------

    package com.zhanggen.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Import;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import javax.sql.DataSource;
    
    //把spring配置中的配置内容,全部转换到当前配置类
    /*
    bean标签---->方法
    非bean标签(例如ComponentScan注解扫描)---->方法的注解
    */
    @ComponentScan("com.zhanggen") //注解扫描
    @Import(DbConfig.class) //从1个配置类中导入另1个配置类
    public class SpringConfig {
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
    }
    SpringConfig.java

    4.配置类声明

    使用@Configuration声明的类就是配置类,本质是1个@Component注解;

    在spring容器初始化的时候, 该配置类会自动创建并进入spring容器,以供主配置类的对象进行调用;

    package com.zhanggen.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    import javax.sql.DataSource;
    //导入类路径下某一个配置文件
    @PropertySource("db.properties")
    //@Configuration 声明的类就是配置类,在spring容器初始化的时候, 配置类会自动创建并进入容器
    @Configuration
    public class DbConfig {
        // @Value():用于给对象中简单属性进行赋值
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean("druidDataSource")
        public DataSource getDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
    }
    DbConfig.java

    ------------------------------------------------------------------------------------------------------------------

    package com.zhanggen.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Import;
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import javax.sql.DataSource;
    
    //把spring配置中的配置内容,全部转换到当前配置类
    /*
    bean标签---->方法
    非bean标签(例如ComponentScan注解扫描)---->方法的注解
    */
    @ComponentScan("com.zhanggen") //注解扫描
    public class SpringConfig {
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
    }
    SpringConfig.java

    5.纯注解总结

    @ComponentScan
    组件扫描注解。 相当于xml配置文件中的< context:component-scan base-package=""/>

    @Bean
    该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。

    @PropertySource
    用于引入其它的properties配置文件

    @Import
    在一个配置类中导入其它配置类的内容

    @Configuration
    被此注解标注的类,会被Spring认为是配置类。Spring在启动的时候会自动扫描并加载所有配置类,然后将配置类中bean放入容器。

    6.Spring整合到Junit测试

    当我们吧bean对象放到spring的容器之后,如果相对这个bean对象进行功能测试;

    无需每次都需创建1个ApplicationContext对象然后再去运行spring的容器;

    Junit支持通过@runWith()注解的方式,快速运行spring容器对象,以供我们调用spring容器中对象的功能;

    6.1.加入Spring单元测试的依赖

     <!--spring单元测试-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.1.6.RELEASE</version>
            </dependency>
    pom.xml

    6.2.修改测试类

    package com.zhanggen.test;
    import com.zhanggen.domain.Account;
    import com.zhanggen.service.AccountService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import java.util.List;
    
    //1.切换运行器:使用SpringJUnit4ClassRunner启动spring的容器
    @RunWith(SpringJUnit4ClassRunner.class)
    //2.启动spring的容器时加载配置类
    //@ContextConfiguration(classes = SpringConfig.class)
    ////2.启动spring的容器时加载配置文件
    //@ContextConfiguration("classpath:applicationContext.xml")
    public class AccountServiceTest {
        @Autowired
        private AccountService accountService;
    
        @Test
        public void testQueryAll() {
            List<Account> accountList = accountService.queryAll();
            for (Account account : accountList) {
                System.out.println(account);
            }
        }
    }
    AccountServiceTest.java

    7.@PostConstruc和@PreDestroy注解

    @PostConstruc注释的方法,在当前对象初始化完成之后执行;

    @PreDestory注释的方法,在对象销毁之前执行;

    @Autowired不能注释static修饰的变量,静态成员属于类的,当类加载器加载静态变量时,Spring上下文尚未加载所以类加载器不会在bean中正确注入静态类,并且会失败

    执行顺序如下

    Constructor(对象的构造方法) -----> @Autowired(依赖注入) --------> @PostConstruct(注释的方法)

     

    参考

  • 相关阅读:
    CodeIgniter 2.X 于 PHP5.6 兼容错误
    解决 TextMate 2 无法安装 Emmet 插件
    Windows 10 KMS 激活方法
    Sublime Text 3 如何修改默认快捷键
    Grunt快速使用笔记
    CSS3字体发光效果
    CSS3使用盒模型实现三栏布局
    CSS3Transition添加多个过渡效果
    Javascript 判断网页横竖屏
    【iOS知识汇】OC点语法的坑
  • 原文地址:https://www.cnblogs.com/sss4/p/16286061.html
Copyright © 2020-2023  润新知