Spring5框架入門學習之常見註解配置(三)

Spring除了提供基於xml配置還提供了基於註解的配置,開發中經常用基於註解的方式。Spring提供了很多註解掌握其使用方法與實現原理是非常有必要的。

@Required

最新Spring5中該註解標記爲過時的,此註解應用於JavaBean的setter方法上。

@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Required {
}

這個註解表明Bean設置屬性的時候必須裝配明確的屬性值,下面演示其用法。

  • 新增JavaBean
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Setter
public class Student {
    private String name;
    private Integer age;
    private Grade grade;
    @Required
    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}


@Data
public class Grade {
    private String gradeLevel;
}
  • 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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="student" class="com.codegeek.day7.Student"/>
    <bean id="grade" class="com.codegeek.day7.Grade"/>
</beans>

我們在 StudentsetGrade 方法加入了註解,表明當容器初始化創建Student 類的時候必須也要初始化 Grade 類然後將 Grade 值注入 Student 類中,如果我們像上面那樣編輯器會給我們一個錯誤提示:
在這裏插入圖片描述
然後我們對xml配置文件做以下改動:
在這裏插入圖片描述
然後發現編輯器不在告警。

@Autowired

相信大家對此註解一定不會陌生,在日常開發中最常見的使用場景就是:如果類A需要調用類B的方法,此時我們可以將類B做爲類A的成員屬性然後在這個成員屬性加上此註解即可。

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;
}

下面演示其用法 我們在Student 類注入 Grade 類。
在這裏插入圖片描述
然後爲Grade類屬性進行賦值:
在這裏插入圖片描述
運行測試類:
在這裏插入圖片描述

注入原理

在這裏插入圖片描述
當要注入 Grade 對象 @Autowired 註解首先會跟着類型去匹配IOC容器中類型爲Grade 的類,找到就返回並設置否則返回 NoSuchBeanDefinitionException 異常。
如果有多個類型的Bean那麼IOC容器會注入那個呢?讓我們先定義兩個同類型的Bean如下所示:
在這裏插入圖片描述
然後在跑一次測試的代碼:我們發現注入的依然是idgrade 的那個 Bean 對象。
在這裏插入圖片描述
原因是:當發現多個類型的Bean對象的時候,Spring會以注入對象的變量名稱做爲 id 去IOC容器中匹配該id。在這裏插入圖片描述
若是找到就返回否則會報以下錯誤:
在這裏插入圖片描述
例如我們將變量名稱改爲 grade1 如下:

    @Autowired
    private Grade grade1;

然後我們運行以下測試類的代碼就拋出異常如下所示:
在這裏插入圖片描述

@Qualifier

上面我們發現注入類類型有多個時,Spring容器會進行拋異常處理。我們可以指定id的類此時就要使用到 @Qualifier註解。
在這裏插入圖片描述
我們再次運行測試類我們發現grade2對象已經注入成功。
在這裏插入圖片描述

@Resource

Spring也支持JSR-250註解 @Resource默認情況下其也是根據類的成員變量名去IOC容器中查找類,如下我們使用 @Resource 註解 Spring容器會在IOC容器查找 idgrade1Grade,與上面類似找到就返回對象並注入否則還是拋出異常。

  @Resource
    private Grade grade1;

在這裏插入圖片描述
我們對注入對象進行如下修改:

  @Resource(name = "grade2")
    private Grade grade1;

然後Spring容器會在容器查找 idgrade2Grade 類對象。此時指定了 name 屬性的 @Resource 等價與@Autowired@Qualifier 組合。
在這裏插入圖片描述

@Configuration @Bean

@Configuration 註解表明該類爲配置類其功能相當於我們常常配置的xml數據源配置.
@Bean 聲明一個受Spring管理的JavaBean對象其相當於我們xml配置中的<bean> 標籤。我們定義以下配置類:

@Configuration
public class ApplicationConfiguration {

    @Bean(name = "student2")
    public Student createStudent() {
        return new Student("張三", 23);
    }
}

然後xml中配置可以掃描此註解的功能:
在這裏插入圖片描述
跑一下測試的代碼如下:
在這裏插入圖片描述

@Primary

一般按照如下根據類型獲取Bean會獲取多個類型時,此時可以對某個Bean設置 @Primary 這樣Spring優先返回指定了此註解的Bean。
在這裏插入圖片描述
我們對配置類進行如下更改:
在這裏插入圖片描述
然後我們在跑一下測試類的代碼:
在這裏插入圖片描述
我們發現Spring容器優先返回了加 @Primary 的Bean對象。

類路徑掃描註解@Component及其同義註解

相信開發人員對 @Service @Controller @Repository 已經很熟悉了,我們都知道其分別對應着服務層、表現層、持久層而 @Component 屬於Spring管理組件的通用註解。通過查看源碼我們可以看到其他三個註解都是構建在 @Component 之上
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
開發中如果想要Spring可以自動檢測加了註解的類並注入其相應的Bean,需要我們加入 @ComponentScan
在這裏插入圖片描述
也可以通過xml配置 <context:component-scan> ,兩者效果是一致的。
在這裏插入圖片描述

@Import

與我們常常在某個Xml中 import 其他模塊xml配置一樣,我們也可以使用某個配置類import 其他配置類正向下面這樣。

  • xml中導入其他配置xml信息
    在這裏插入圖片描述
  • 配置類導入其他配置類
@Configuration
public class DataConfiguration {
    @Bean
    public Grade createGrade() {
        return new Grade("大學一年級");
    }
}

在這裏插入圖片描述

@ImportResource

我們在xml配置了一個id爲 grade2Grade 類如下所示:
在這裏插入圖片描述
然後我們使用 AnnotationConfigApplicationContext 這個類去獲取上面Grade類代碼如下所示:

    @Test
    public void testRequired() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(ApplicationConfiguration.class);
        annotationConfigApplicationContext.refresh();
        Grade bean = annotationConfigApplicationContext.getBean("grade2", Grade.class);
        System.out.println("\n" + bean);
    }

運行確報錯 No bean named 'grade2' available 的異常。
在這裏插入圖片描述
出現這個原因是我們的 ApplicationConfiguration 這個類沒有配置名稱爲grande2 的對象但我們的xml配置文件已經定義了該Bean,此時我們可以使用@ImportResource 將配置文件內容加入到 ApplicationConfiguration 這個類中解決問題。
在這裏插入圖片描述

@Profile

在開發中經常有這樣的需求:不同開發環境下注冊不同的Bean對象以方便我們在不同環境下完成不同的業務邏輯如:開發環境、測試環境、生產環境等。此時我們可藉助@Profile幫助我們在不同的環境註冊不同的Bean,下面以一個簡單的案例演示其使用。

  • 新增三個不同環境配置類
@Configuration
@Profile(value = "dev")
public class DevConfiguration {

    @Bean(name = "dataSource")
    public DataSource createDataSource(@Qualifier("dataConfig") DataConfig config) throws SQLException {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setDriver(config.getDriver());
        dataSource.setUsername(config.getUserName());
        dataSource.setPassword(config.getPassword());
        return dataSource;
    }

    @Bean(name = "dataConfig")
    public DataConfig devData() throws SQLException {
        String url = "jdbc:mysql://localhost/test?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true";
        Driver driver = new Driver();
        String userName = "root";
        String password = "123456";
        return new DataConfig(driver, url, userName, password);
    }
}


@Configuration
@Profile(value = "prop")
public class PropConfiguration {
    @Bean(name = "dataSource")
    public DataSource createDataSource(@Qualifier("dataConfig") DataConfig config) throws SQLException {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setDriver(config.getDriver());
        dataSource.setUsername(config.getUserName());
        dataSource.setPassword(config.getPassword());
        return dataSource;
    }

    @Bean(name = "dataConfig")
    public DataConfig devData() throws SQLException {
        String url = "jdbc:mysql://10.211.55.1/test?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true";
        Driver driver = new Driver();
        String userName = "root";
        String password = "123456";
        return new DataConfig(driver, url, userName, password);
    }
}


@Configuration
@Profile(value = "qa")
public class QAConfiguration {

    @Bean(name = "dataSource")
    public DataSource createDataSource(@Qualifier("dataConfig") DataConfig config) throws SQLException {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setDriver(config.getDriver());
        dataSource.setUsername(config.getUserName());
        dataSource.setPassword(config.getPassword());
        return dataSource;
    }

    @Bean(name = "dataConfig")
    public DataConfig devData() throws SQLException {
        String url = "jdbc:mysql://10.211.55.5/test?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true";
        Driver driver = new Driver();
        String userName = "root";
        String password = "123456";
        return new DataConfig(driver, url, userName, password);
    }
}

在這裏插入圖片描述

@PropertySource

Spring中有個接口Environment,它對應用環境建立了一個Profile 與<kbdProperty 兩個概念。我們可以設置額外的Properties文件並將其加入到Spring配置文件中,如下是一個簡單的使用案例:

  • 新增JavaBean對象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeployConfiguration {

    private String deployUrl;
    private String deployUser;
    private String deployPath;
    private String deployEnvironment;
}

@Configuration
@PropertySource(value = "classpath:day7/customize.properties")
public class PropertySourceConfiguration {

    @Autowired
    private Environment environment;

    @Bean(name = "deployConfiguration")
    public DeployConfiguration create() {
        DeployConfiguration configuration = new DeployConfiguration();
        configuration.setDeployEnvironment(environment.getProperty("deploy.environment"));
        configuration.setDeployPath(environment.getProperty("deploy.path"));
        configuration.setDeployUrl(environment.getProperty("deploy.url"));
        configuration.setDeployUser(environment.getProperty("deploy.user"));
        return configuration;
    }
}

  • 新增 customize.properties
deploy.environment=linux
deploy.path=/soft/service/spring-tomcat
deploy.user=codegeekgao
deploy.url=10.211.55.1

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章