1. 程式人生 > 實用技巧 >java後端開發三年!你還不瞭解Spring 依賴注入,憑什麼給你漲薪

java後端開發三年!你還不瞭解Spring 依賴注入,憑什麼給你漲薪

前言

前兩天和一個同學吃飯的時候同學跟我說了一件事,說他公司有個做了兩年的人向他提出要漲薪資,他就順口問了一個問題關於spring依賴注入的,那個要求漲薪的同學居然被問懵了。。。事後回家想了想這一塊確實有點難度的就寫篇文章把我自己知道的和網上整理的分享給大家,至少大家在被問到這一塊的時候能答上來,不會因為這個被卡漲薪。話不多說,滿滿的乾貨都在下面了!

1.什麼是Spring的依賴注入?

依賴注入,是IOC的一個方面,是個通常的概念,它有多種解釋。這概念是說你不用建立物件,而只需要描述它如何被建立。你不在程式碼裡直接組裝你的元件和服務,但是要在配置檔案裡描述哪些元件需要哪些服務,之後一個容器(IOC容器)負責把他們組裝起來。

2. IOC的作用

降低程式間的耦合(依賴關係)
依賴關係的管理:
以後都交給spring來維護
在當前類需要用到其他類的物件,由spring為我們提供,我們只需要在配置檔案中說明依賴關係的維護,就稱之為依賴注入。

3.Spring依賴注入的幾種方式

能注入的資料:有三類

基本型別和String。
其他bean型別(在配置檔案中或者註解配置過的bean)。
複雜型別/集合型別。
注入的方式:有三種

使用建構函式提供。
使用set方法提供。
使用註解提供。

建構函式注入

顧名思義,就是使用類中的建構函式,給成員變數賦值。注意,賦值的操作不是我們自己做的,而是通過配置的方式,讓 spring 框架來為我們注入。具體程式碼如下:

<!--建構函式注入:
    使用的標籤:constructor-arg
    標籤出現的位置:bean標籤的內部
    標籤中的屬性
        type:用於指定要注入的資料的資料型別,該資料型別也是建構函式中某個或某些引數的型別
        index:用於指定要注入的資料給建構函式中指定索引位置的引數賦值。索引的位置是從0開始
        name:用於指定給建構函式中指定名稱的引數賦值
        ================以上三個用於指定給建構函式中哪個引數賦值===================
        value:用於提供基本型別和String型別的資料
        ref:用於指定其他的bean型別資料。它指的就是在spring的Ioc核心容器中出現過的bean物件

    優勢:
        在獲取bean物件時,注入資料是必須的操作,否則物件無法建立成功。
    弊端:
        改變了bean物件的例項化方式,使我們在建立物件時,如果用不到這些資料,也必須提供。
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <constructor-arg name="name" value="泰斯特"></constructor-arg>
    <constructor-arg name="age" value="18"></constructor-arg>
    <constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>

<!-- 配置一個日期物件 -->
<bean id="now" class="java.util.Date"></bean>

  

Set方式注入

顧名思義,就是在類中提供需要注入成員的 set 方法。具體程式碼如下:

<!-- set方法注入 --->   更常用的方式
    涉及的標籤:property
    出現的位置:bean標籤的內部
    標籤的屬性
        name:用於指定注入時所呼叫的set方法名稱
        value:用於提供基本型別和String型別的資料
        ref:用於指定其他的bean型別資料。它指的就是在spring的Ioc核心容器中出現過的bean物件
    優勢:
        建立物件時沒有明確的限制,可以直接使用預設建構函式
    弊端:
        如果有某個成員必須有值,則獲取物件是有可能set方法沒有執行。
-->
<bean id="accountService2" class="com.itheima.service.impl.AccountServiceImpl2">
    <property name="name" value="tom" ></property>
    <property name="age" value="23"></property>
    <property name="birthday" ref="now"></property>
</bean>

  

集合方式注入

顧名思義,就是給類中的集合成員傳值,它用的也是set方法注入的方式,只不過變數的資料型別都是集合。
我們這裡介紹注入陣列,List,Set,Map,Properties。

複雜型別的注入/集合型別的注入

用於給List結構集合注入的標籤:
list,array,set
用於個Map結構集合注入的標籤:
map,props

程式碼如下:

User類

public class User {
    private String name;
    private Integer age;
    private Date birth;

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

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

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public User(){
        System.out.println("我被建立了...");
    }
    public void show(){
        System.out.println("user中的show方法呼叫了。。。");
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birth=" + birth +
                '}';
    }
}

  

Person類

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

  

CollectionDemo類

public class CollectionDemo {
    private String[] arr;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties myProp;

    public void setArr(String[] arr) {
        this.arr = arr;
    }

    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 setMyProp(Properties myProp) {
        this.myProp = myProp;
    }

    public String[] getArr() {
        return arr;
    }

    public List<String> getMyList() {
        return myList;
    }

    public Set<String> getMySet() {
        return mySet;
    }

    public Map<String, String> getMyMap() {
        return myMap;
    }

    public Properties getMyProp() {
        return myProp;
    }
}

  

配置檔案:

<!-- 基於xml形式裝配bean -->
<bean id="user" class="com.atguigu.java1.User"></bean>

<!--使用get方法建立bean-->
<bean id="user2" class="com.atguigu.java1.User">
    <property name="name" value="張"></property>
    <property name="age">
        <value>20</value>
    </property>
    <property name="birth" ref="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>

<!--集合和陣列型別的依賴注入-->
<bean id="demo" class="com.atguigu.java1.CollectionDemo">
    <property name="arr">
        <array>
            <value>111</value>
            <value>222</value>
            <value>333</value>
        </array>
    </property>
    <property name="myList">
        <list>
            <value>111</value>
            <value>222</value>
            <value>333</value>
        </list>
    </property>
    <property name="mySet">
        <set>
            <value>111</value>
            <value>222</value>
            <value>333</value>
        </set>
    </property>
    <property name="myMap">
        <map>
            <entry key="aaa" value="aaa"></entry>
            <entry key="bbb" value="bbb"></entry>
            <entry key="ccc" value="ccc"></entry>
        </map>
    </property>
    <property name="myProp">
        <props>
            <prop key="aaa">aaa</prop>
            <prop key="bbb">bbb</prop>
            <prop key="ccc">ccc</prop>
        </props>
    </property>
</bean>

<!--使用預設構造器建立bean-->
<bean id="person" class="com.atguigu.java1.Person">
    <constructor-arg name="name" value="張三丰"></constructor-arg>
    <constructor-arg name="age" value="18"></constructor-arg>
</bean>

  

測試類:

/**
 * 測試基於xml形式的spring ioc獲取物件
 */
@Test
public void test3(){
    ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
    User user= (User) ioc.getBean("user");//在此處打斷點驗證物件是什麼時候被建立的。
    user.show();
}

/**
 * 採用預設構造器的形式建立bean物件
 */
@Test
public void test(){
    ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
    Person p= (Person) ioc.getBean("person");
    Person p2= (Person) ioc.getBean("person");
    System.out.println(p.toString());
}
/**
 * 使用get方法進行依賴注入
 */
@Test
public void test4(){
    ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
    User user= (User) ioc.getBean("user2");//在此處打斷點驗證物件是什麼時候被建立的。
    System.out.println(user.toString());
}

/**
 * 集合和陣列的依賴注入
 */
@Test
public void test5(){
    ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
    CollectionDemo demo= (CollectionDemo) ioc.getBean("demo");
    System.out.println(Arrays.toString(demo.getArr()));
    System.out.println(demo.getMyList());
    System.out.println(demo.getMySet());
    System.out.println(demo.getMyMap());
    System.out.println(demo.getMyProp());
}

  

4.使用spring的ioc實現賬戶的CRUD

4.1 基於xml形式

1.引用外部屬性檔案

2.SPEL表示式

Spring Expression Language,Spring表示式語言,簡稱SpEL。支援執行時查詢並可以操作物件圖。
和JSP頁面上的EL表示式、Struts2中用到的OGNL表示式一樣,SpEL根據JavaBean風格的getXxx()、setXxx()方法定義的屬性訪問物件圖,完全符合我們熟悉的操作習慣。

2.基本語法
SpEL使用#{…}作為定界符,所有在大框號中的字元都將被認為是SpEL表示式。

3.使用字面量
    ●整數:<property name="count" value="#{5}"/>
    ●小數:<property name="frequency" value="#{89.7}"/>
    ●科學計數法:<property name="capacity" value="#{1e4}"/>
    ●String型別的字面量可以使用單引號或者雙引號作為字串的定界符號
        <property name=”name” value="#{'Chuck'}"/>
        <property name='name' value='#{"Chuck"}'/>
    ●Boolean:<property name="enabled" value="#{false}"/>

4.引用其他bean
    <bean id="emp04" class="com.atguigu.parent.bean.Employee">
        <property name="empId" value="1003"/>
        <property name="empName" value="jerry"/>
        <property name="age" value="21"/>
        <property name="detp" value="#{dept}"/>
    </bean>

5.引用其他bean的屬性值作為自己某個屬性的值
    <bean id="emp05" class="com.atguigu.parent.bean.Employee">
        <property name="empId" value="1003"/>
        <property name="empName" value="jerry"/>
        <property name="age" value="21"/>
        <property name="deptName" value="#{dept.deptName}"/>
    </bean>

6.呼叫非靜態方法
    <!-- 建立一個物件,在SpEL表示式中呼叫這個物件的方法 -->
    <bean id="salaryGenerator" class="com.atguigu.spel.bean.SalaryGenerator"/>

    <bean id="employee" class="com.atguigu.spel.bean.Employee">
        <!-- 通過物件方法的返回值為屬性賦值 -->
        <property name="salayOfYear" value="#{salaryGenerator.getSalaryOfYear(5000)}"/>
    </bean>

7.呼叫靜態方法
    <bean id="employee" class="com.atguigu.spel.bean.Employee">
        <!-- 在SpEL表示式中呼叫類的靜態方法 -->
        <property name="circle" value="#{T(java.lang.Math).PI*20}"/>
    </bean>

8.運算子
    ①算術運算子:+、-、*、/、%、^
    ②字串連線:+
    ③比較運算子:<、>、==、<=、>=、lt、gt、eq、le、ge
    ④邏輯運算子:and, or, not, |
    ⑤三目運算子:判斷條件?判斷結果為true時的取值:判斷結果為false時的取值
    ⑥正則表示式:matches

  

程式碼如下:

配置檔案

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.2.xsd
        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-4.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
  
    <bean id="accountDao" class="com.atguigu.dao.impl.AccountDaoImpl">
        <property name="runner" ref="runner"></property>
    </bean>
    <bean id="accountService" class="com.atguigu.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <bean id="account" class="com.atguigu.domain.Account"></bean>
  
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>
  
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
</beans>

  

持久層

/*
  賬戶的持久層實現類
 */
public class AccountDaoImpl implements IAccountDao {
    
    private QueryRunner runner;

    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 accountId) {
        try{
            runner.update("delete from account where id=?",accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

  

業務層

/*
  賬戶的業務層實現類
 */
public class AccountServiceImpl implements IAccountService{
    
    private IAccountDao accountDao;

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

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

    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

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

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

    public void deleteAccount(Integer acccountId) {
        accountDao.deleteAccount(acccountId);
    }
}

  

測試類

public class Test1 {
    ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
    @Test
    public void test1(){
        IAccountService service= (IAccountService) ioc.getBean("accountService");
        service.deleteAccount(2);
    }
}

  

4.2 xml和註解的混搭

XML配置形式:

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope="" 
        init-method="" destroy-method="">
    <property name=""  value="" | ref=""></property>
</bean>

  

1.用於建立物件的

他們的作用就和在XML配置檔案中編寫一個標籤實現的功能是一樣的。

Component:
作用:用於把當前類物件存入spring容器中
屬性:
value:用於指定bean的id。當我們不寫時,它的預設值是當前類名,且首字母改小寫。

Controller:一般用在表現層

Service:一般用在業務層

Repository:一般用在持久層

以上個註解他們的作用和屬性與Component是一模一樣。
他們是spring框架為我們提供明確的層使用的註解,使我們的層物件更加清晰。

2.用於注入資料的

他們的作用就和在xml配置檔案中的bean標籤中寫一個標籤的作用是一樣的。

Autowired:
作用:自動照型別注入。只要容器中唯一的一個bean物件型別和要注入的變數型別匹配,就可以注入成功。
如果ioc容器中沒任何bean的型別和要注入的變數型別匹配,則報錯。
如果Ioc容器中多個型別匹配時:

出現位置:
可以是變數上,也可以是方法上。

細節:
在使用註解注入時,set方法就不是必須的了。

Qualifier:
作用:在照類中注入的基礎之上再照名稱注入。在給類成員注入時不能單獨使用。但是在給方法引數注入時可以。

屬性:
value:用於指定注入bean的id。

Resource:
作用:直接照bean的id注入。它可以獨立使用。

屬性:
name:用於指定bean的id。
以上注入都只能注入其他bean型別的資料,而基本型別和String型別無法使用上述註解實現。
另外,集合型別的注入只能通過XML來實現。

Value:
作用:用於注入基本型別和String型別的資料。

屬性:
value:用於指定資料的值。它可以使用spring中SpEL(也就是spring的el表示式
SpEL的寫法:${表示式}

3.用於改變作用範圍的

他們的作用就和在bean標籤中使用scope屬性實現的功能是一樣的。

Scope:
作用:用於指定bean的作用範圍。

屬性:
value:指定範圍的取值。常用取值:singleton prototype

4.和生命週期相關(瞭解)

他們的作用就和在bean標籤中使用init-method和destroy-methode的作用是一樣的。

PreDestroy
作用:用於指定銷燬方法。
PostConstruct
作用:用於指定初始化方法。

程式碼如下:

配置檔案

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.2.xsd
        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-4.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
  
    <!--設定自動掃描的包-->
    <context:component-scan base-package="com.atguigu"></context:component-scan>
  
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>
  
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
</beans>

  

持久層

業務層

····
/**

賬戶的業務層實現類
*/
@Service("accountService")
public class AccountServiceImpl implements IAccountService{
@Autowired
private IAccountDao accountDao;

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

public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}

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

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

public void deleteAccount(Integer acccountId) {
accountDao.deleteAccount(acccountId);
}
}
····

  

測試類

public class AccountServiceTest {
    @Test
    public void testFindAll() {
        //1.獲取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到業務層物件
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.執行方法
        List<Account> accounts = as.findAllAccount();
        for(Account account : accounts){
            System.out.println(account);
        }
    }

    @Test
    public void testFindOne() {
        //1.獲取容易
        ApplicationContext 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() {
        Account account = new Account();
        account.setName("test");
        account.setMoney(12345f);
        //1.獲取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到業務層物件
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.執行方法
        as.saveAccount(account);
    }

    @Test
    public void testUpdate() {
        //1.獲取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到業務層物件
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.執行方法
        Account account = as.findAccountById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        //1.獲取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到業務層物件
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.執行方法
        as.deleteAccount(4);
    }
}

  

4.3 純註解配置

1.註解

該類是一個配置類,它的作用和bean.xml是一樣的。

spring中的新註解:

Configuration:

作用:指定當前類是一個配置類。
細節:當配置類作為AnnotationConfigApplicationContext物件建立的引數時,該註解可以不寫。

ComponentScan:

作用:用於通過註解指定spring在建立容器時要掃描的包。

屬性:
value:它和basePackages的作用是一樣的,都是用於指定建立容器時要掃描的包。
我們使用此註解就等同於在xml中配置了:

<!--告知spring在建立容器時要掃描的包,配置所需要的標籤不是在beans的約束中,
    而是一個名稱為context名稱空間和約束中-->
<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,表示類路徑下。

  

2.spring整合junit4

說明:
1、應用程式的入口
main方法

2、junit單元測試中,沒有main方法也能執行
junit集成了一個main方法
該方法就會判斷當前測試類中哪些方法有 @Test註解
junit就讓有Test註解的方法執行

3、junit不會管我們是否採用spring框架
在執行測試方法時,junit根本不知道我們是不是使用了spring框架,
所以也就不會為我們讀取配置檔案/配置類建立spring核心容器。

4、由以上三點可知
當測試方法執行時,沒有Ioc容器,就算寫了Autowired註解,也無法實現注入。

使用Junit單元測試:
Spring整合junit的配置:測試我們的配置
1、匯入spring整合junit的jar(座標)

2、使用Junit提供的一個註解把原有的main方法替換了,替換成spring提供的
@Runwith(SpringJUnit4ClassRunner.class)

3、告知spring的執行器,spring和ioc建立是基於xml還是註解的,並且說明位置
@ContextConfiguration

引數說明:

locations:指定xml檔案的位置,加上classpath關鍵字,表示在類路徑下。
classes:指定註解類所在地位置。
注意:當我們使用spring 5.x版本的時候,要求junit的jar必須是4.12及以上。

程式碼如下:

配置類

/**
 * @author Guohai
 * @createTime 2020-07-13 17:14
 */
@Configuration
@ComponentScan("com.atguigu")
@Import(JdbcConfig.class)
@PropertySource("classpath:c3p0.properties")
public class SpringConfig {

}

  

配置子類

/**
 * @author Guohai
 * @createTime 2020-07-13 17:16
 */
public class JdbcConfig {
    @Bean(name="runner")
    @Scope(value = "prototype")
    public QueryRunner getRunner(@Qualifier("ds1") DataSource dataSource) {
        QueryRunner runner = new QueryRunner(dataSource);
        return runner;
    }

    private static DataSource dataSource = null;

    @Bean(name="ds1")
    public DataSource getDataSource() {
        try {
            Properties prop = new Properties();
            InputStream is = JdbcConfig.class.getClassLoader().getResourceAsStream("jdbc.properties");
            prop.load(is);
            dataSource = DruidDataSourceFactory.createDataSource(prop);
            return dataSource;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
  
    @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(name="ds2")
    public DataSource getDataSource2(){
        try {
            ComboPooledDataSource dataSource=new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            return dataSource;
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return null;
    }
}

  

測試類

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {

    @Autowired
    private IAccountService as = null;

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

    @Test
    public void testFindOne() {
        //3.執行方法
        Account account = as.findAccountById(1);
        System.out.println(account);
    }

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test anno");
        account.setMoney(12345f);
        //3.執行方法
        as.saveAccount(account);
    }

    @Test
    public void testUpdate() {
        //3.執行方法
        Account account = as.findAccountById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        //3.執行方法
        as.deleteAccount(4);
    }
}

  

5.Spring的自動裝配

在spring中,物件無需自己查詢或建立與其關聯的其他物件,由容器負責把需要相互協作的物件引用賦予各個物件,使用autowire來配置自動裝載模式。

在Spring框架xml配置中共有5種自動裝配:
(1)no:預設的方式是不進行自動裝配的,通過手工設定ref屬性來進行裝配bean。
(2)byName:通過bean的名稱進行自動裝配,如果一個bean的 property 與另一bean 的name 相同,就進行自動裝配。
(3)byType:通過引數的資料型別進行自動裝配。
(4)constructor:利用建構函式進行裝配,並且建構函式的引數通過byType進行裝配。
(5)autodetect:自動探測,如果有構造方法,通過 construct的方式自動裝配,否則使用 byType的方式自動裝配。

最後

大家看完有什麼不懂的可以在下方留言討論,也可以關注我私信問我,我看到後都會回答的。也歡迎大家關注我的公眾號:前程有光,金三銀四跳槽面試季,整理了1000多道將近500多頁pdf文件的Java面試題資料,文章都會在裡面更新,整理的資料也會放在裡面。謝謝你的觀看,覺得文章對你有幫助的話記得關注我點個贊支援一下!