暑期自學 Day 18 | Spring (四)

Borris發表於2020-06-25

IoC 註解

使用註解建立物件之後,就不用像之前那樣透過bean標籤手動配置建立物件的屬性了。
註解要寫在需要注入的類或者成員方法前。
按作用分為四類:

建立物件

  • 和 bean 標籤功能一樣
    • @Component - 把當前物件存入 spring 容器
    • 屬性:value: 指定 bean 的 id,預設值是當前類名,但首字母要小寫
    • 衍生註解:使三層物件更加清晰,相當於@Component的子類
      • @Controller:表現層
      • @Service:業務層
      • @Repository:持久層

在 bean.xml 中配置 context 名稱空間

<?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">

<!-- 配置 component 註解所需的標籤 -->
    <context:component-scan base-package="spring.selflearning"></context:component-scan>

</beans>

注入資料

  • 和 property 功能一樣
  • @Autowired: 自動按照型別注入資料,只要容器中有唯一的一個bean物件型別和要注入的變數型別匹配,就能注入成功。
    • 可以出現在變數上,也可以出現在方法上。
    • 此時無需set方法
  • @Qualifier:按照型別注入的基礎上再按照名稱注入。給類成員注入時不能單獨使用,給方法引數注入時可以。
  • @Value:注入基本型別和String型別
  • 集合型別注入只能透過xml實現
  • 改變作用範圍
    • 和 scope 一樣
    • @Scope,取值可以是 singleton 或 prototype
  • 生命週期相關
    • 和 init-method 和 destroy-method 作用一樣
    • @PreDestroy 銷燬
    • @PostConstruct 初始化
    • 需要用 close() 方法釋放容器
    • 只能銷燬單例物件

Spring 的一些新註解

這些新註解功能和bean.xml中的一些屬性功能相同,為的是取代bean.xml中的配置方式。

@Configuration

  • 表示當前類是個配置類
  • 當配置類作為AnnotationConfigApplicationContext物件建立的引數時,該註解可以不寫。

如某個方法中使用ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);建立物件,那麼無需在方法上使用@Configuration註解,因為Java會自動找到SpringConfiguration.class這個配置類建立物件。

AnnotationConfigApplicationContext方法中可以寫多個配置類,用逗號分隔。

@ComponentScan

  • 指定spring建立容器時需要掃描的包;屬性:basePackages
  • 功能和 <context:component-scan base-package="spring.selflearning"></context:component-scan> 一樣。

@Bean

  • 把當前方法的返回值作為bean物件存入ioc容器中;屬性:name,指定bean的id,不寫時預設值為當前方法的名稱
  • 如果bean註解有值,spring會去容器中查詢是否有可用的bean物件,查詢方式和AutoWired註解的功能一樣

如給建立一個QueryRunner物件的方法新增註解:

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

@Import

  • 指定其他配置類的位元組碼
  • 使用Import註解之後的類就是父配置類,匯入的是子配置類。此時建立物件時只需註解父類配置類即可。

PropertySource

  • 用於指定properties的位置
  • @Value:指定檔案路徑和名稱,classpath,表示在類路徑下
  • 在我實際使用中,發現Value註解無法正常讀取properties配置檔案,目前這個問題還沒解決。附自己的程式碼:

父配置類:SpringConfiguration.java

@ComponentScan(basePackages = "spring.selflearning") // 屬性是陣列型別,如果需要掃描多個類則需加大括號
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {}

子配置類:JdbcConfig.java

package config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.sql.DataSource;

@Component("jdbcConfig")
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;

    public String getDriver() {
        return driver;
    }

    public String getUrl() {
        return url;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    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);
        }
    }
}

jdbcConfig.properties

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

關於何時使用 xml,何時使用註解

實際上註解並不總是能減少配置過程中的程式碼量,如配置JDBC連線時。
配置注入的物件在別人寫好的類中,那麼使用xml更好;如果是自己寫的類,直接在類中新增註解則更為方便。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章