天天看點

Spring基于注解的Ioc及Junit內建

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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!--告知spring在建立容器時候需要掃描的包, 配置所需要的标簽不是在bean限制中,而是在一個名為context的名稱空間和限制中.-->
    <context:component-scan base-package="com.mine"></context:component-scan>
</beans>


           
常用注解
  • @Component

    @Component作用是把資源讓 spring 來管理. 相當于在 xml 中配置一個 bean. 它有一個value屬性, 通常用來指定 bean 的 id. 如果不指定 value 屬性,預設 bean 的 id 是目前類的類名, 首字母小寫.

// 在需要建立對象的類中添加注解關鍵字@Component
@Component
public class AccountServiceImpl implements IAccountService {
    public AccountServiceImpl () {
        System.out.println("建立了對象");
    }
}
// 在測試檔案中, 如果@Component注解未指定value值,則預設id為目前類名,首字母小寫.即下面的"accountServiceImpl".
public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cls = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService accountService = (IAccountService) cls.getBean("accountServiceImpl");
        System.out.println(accountService);
    }
}

           
  • @Controller @Service @Repository

    這三個注解的作用跟@Component 一模一樣,差別主要在于:Controller: 一般用于表現層的注解; @Service: 一般用于業務層的注解; @Repository: 一般用于持久層的注解.

  • @Autowired

    @Autowired會自動按照類型注入. 當使用注解注入屬性時, set 方法可以省略. 隻要容器中有唯一一個bean對象類型和要注入的變量類型比對, 就可以注入成功. 它隻能注入其他 bean 類型, 當有多個 類型比對時,使用要注入的對象變量名稱作為 bean 的 id,在 spring 容器查找,找到了也可以注入成功,找不到 就報錯[email protected]注解的位置大多用在變量和方法上,當然不限于此.

@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao dao;
    public void saveAccout() {
        dao.saveAccount();
    }
}

           
  • @Qualifier

    在自動按照類型注入的基礎之上,再按照名稱(Bean的id )注入。它在給類成員注入時不能獨立使用,必須和@Autowire 一起使用; 但是給方法參數注入時,可以獨立使用.

    屬性: 有一個屬性value,用于指定注入的bean 的 id.

    在給類成員注入時,必須要和@Autowired組合使用.

  • @Resource

    直接按照 Bean的 id 注入, 可以獨立使用. 它也隻能注入其他 bean 類型.

  • @Value

    用來注入基本資料類型和 String 類型資料的.它有一個value屬性,用來指定資料的值,它可以使用spring中的SpEL表達式. <SpEL表達式的寫法: ${}>

  • 說明: @Autowired,@Qualifier和@Resource三個都隻能注入其他的bean類型的資料,而基本資料類型和string類型隻能通過@Value來實作.
  • @Scope

    用來指定bean的作用範圍.有一個value屬性值用來指定範圍的值。

    取值包括:singleton prototype request session globalsession

新注解
  • @ComponentScan

    用于指定 spring 在初始化容器時要掃描的包.作用和在 spring 的 xml 配置檔案中的:<context:component-scan base-package=“com.mine”/>是一樣的.其中的basePackages屬性用于指定要掃描的包,和該注解中的 value 屬性作用一樣.

  • @Bean

    Bean注解隻能寫在方法上, 表明使用此方法建立一個對象,并且放入 spring 容器.

    屬性name表示給目前@Bean 注解方法建立的對象指定一個名稱(即 bean 的 id).

    執行個體:需要建立一個SpringConfiguration的類來配置注解相關資訊

  • @Import

    用于導入其他配置類, 在引入其他配置類時, 可以不用再寫@Configuration 注解, 當然,寫上也不影響.

  • @PropertySource

    用于加載.properties 檔案中的配置. 例如我們配置資料源時,可以把連接配接資料庫的資訊寫到 properties 配置檔案中,就可以使用此注解指定 properties 配置檔案的位置. 屬性value[]:用于指定 properties 檔案位置。如果是在類路徑下,需要寫上 classpath.

    如:

    存在一個jdbcConfig.properties的配置檔案

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbcDemo
jdbc.user=root
jdbc.password=12345678
           

在配置檔案中:

@Configuration
@ComponentScan("com.mine")
@PropertySource("jdbcConfig.properties")
public class SpringConfiguration {
    @Value("${jdbc.driver}")
    private String driver;

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

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

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

    /**
     * 建立一個QueryRunner對象
     * @param dataSource
     * @return
     */
    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner (DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name ="dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(user);
            dataSource.setPassword(password);
            return dataSource;
        } catch (Exception e){
            throw new RuntimeException();
        }
    }
 }
 
           

同時在測試子產品需要修改讀取注解的方法:

Junit的內建
  • 分析

    在測試類中,每個測試方法都有以下兩行代碼:

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 
IAccountService as = ac.getBean("accountService",IAccountService.class);
 
           

這兩行代碼的作用是擷取容器,如果不寫的話,直接會提示空指針異常.是以又不能輕易删掉.

  • 為什麼不把測試類配到 xml 中?

    配置到xml當然可以正常使用, 隻是因為:

    ①當我們在 xml 中配置了一個 bean,spring 加載配置檔案建立容器時,就會建立對象.

    ②測試類隻是我們在測試功能時使用,而在項目中它并不參與程式邏輯,也不會解決需求上的問題,是以建立完了,并沒有使用. 那麼存在容器中就會造成資源的浪費. 是以,我們不應該把測試配置到 xml 檔案中.

  • 內建
  1. 導入spring整合junit的jar包(坐标)
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.7.RELEASE</version> 
</dependency>
           

2)使用junit提供的一個main方法把原有的main方法替換掉, 替換成spring提供的@Runwith.

之是以需要替換,是以為junit單元測試中, 沒有main方法也能執行, junit本身內建了一個main方法, 該方法會判斷目前測試類中哪些方法包含@Test的注解,junit就會讓這些帶有@Test的方法執行. 而junit本身并不會關注我們的程式是否內建了spring,是以在執行測試方法時候, 它也不會為我們讀取配置檔案或配置類來為我們建立容器.檢視源碼可知, SpringJUnit4ClassRunner其本身也是繼承了junit. 雖然junit不會為我們建立容器,由于SpringJUnit4ClassRunner是spring提供,是以它一定會為我們建立容器.

3)告知spring的運作期,spring的Ioc建立是基于xml還是注解.并且通過@ContextConfiguration 注解來說明位置.

@ContextConfiguration 注解:

其中,

locations 屬性用于指定配置檔案的位置. 如果是類路徑下,需要用 classpath表明.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
}

           

classes 屬性用于指定注解的類, 當不使用 xml 配置時,需要用此屬性指定注解類的位置.

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

}
           

4)通過以上三步的配置, 在後續的單元測試中, 可以不需要在重複寫建立容器的代碼,簡單配置即可.執行個體如下:

// 替換原有的main方法
 @RunWith(SpringJUnit4ClassRunner.class)
 // 指定注解類的位置
 @ContextConfiguration(classes = SpringConfiguration.class)
public class test {
    // 注入
    @Autowired
    private IAccountService accountService;

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


           

當使用spring 5.x版本時候, 需要junit的包必須是4.12以上,否則會報錯.