一步步從Spring Framework裝配掌握SpringBoot自動裝配
目錄
Spring Framework模式註解
模式註解是一種用於宣告在應用中扮演“元件”角色的註解。如 Spring Framework 中的 @Repository 標註在任何類上 ,用
於扮演倉儲角色的模式註解。
模式註解(角色註解)
Spring Framework 註解 | 場景說明 |
---|---|
@Component | 通用元件模式註解 |
@Controller | Web 控制器模式註解 |
@Service | 服務模式註解 |
@Repository | 資料倉儲模式註解 |
@Configuration | 配置類模式註解 |
在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"> <!-- 啟用註解驅動特性 --> <context:annotation-config /> <!-- 找尋被 @Component 或者其派生 Annotation 標記的類(Class),將它們註冊為 Spring Bean --> <context:component-scan base-package="com.imooc.dive.in.spring.boot" /> </beans>
在Spring中基於Java註解配置方式
@ComponentScan(basePackages = "com.imooc.dive.in.spring.boot")
public class SpringConfiguration {
...
}
實戰:自定義模式註解
@Component 模式註解具有“派生性”和“層次性”,我們能夠自定義建立Bean註解
第一步:自定義SpringBean註解
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface MyServiceAnnotation { String value() default ""; }
第二步:將註解作用在自定義Bean上
@MyServiceAnnotation(value = "testBean")
public class TestBean {
}
第三步:測試是否可以從Spring容器中獲取到自定義Bean
@SpringBootApplication
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Main.class, args);
TestBean testBean = run.getBean("testBean", TestBean.class);
System.out.println("testBean" + testBean.toString());
run.close();
}
}
Spring [email protected]模組裝配
Spring Framework 3.1 開始支援”@Enable 模組驅動“。所謂“模組”是指具備相同領域的功能元件集合, 組合所形成一個獨立的單元。比如 Web MVC 模組、AspectJ代理模組、Caching(快取)模組、JMX(Java 管 理擴充套件)模組、Async(非同步處理)模組等。
@Enable 註解模組舉例
框架實現 | @Enable 註解模組 | 啟用模組 |
---|---|---|
Spring Framework | @EnableWebMvc | Web MVC 模組 |
Spring Framework | @EnableTransactionManagement | 事務管理模組 |
Spring Framework | @EnableCaching | Caching 模組 |
Spring Framework | @EnableMBeanExport | JMX 模組 |
Spring Framework | @EnableAsync | 非同步處理模組 |
Spring Framework | @EnableWebFlux | Web Flux 模組 |
Spring Framework | @EnableAspectJAutoProxy AspectJ | 代理模組 |
Spring Boot | @EnableAutoConfiguration | 自動裝配模組 |
Spring Boot | @EnableManagementContext | Actuator 管理模組 |
Spring Boot | @EnableConfigurationProperties | 配置屬性繫結模組 |
Spring Boot | @EnableOAuth2Sso | OAuth2 單點登入模組 |
...... |
@Enable實現方式
- 註解驅動方式
- 介面程式設計方式
實戰:自定義@Enable註解驅動實現方式
第一步:實現自定義註解@EnableMyBean
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyBeanConfig.class)
public @interface EnableMyBean {
}
PS:注意@Import(MyBeanConfig.class),將匯入MyBeanConfig配置類的相關Bean
第二步:建立MyBeanConfig配置類
@Configuration
public class MyBeanConfig {
@Bean(name = "hello")
public String hello() {
return "word";
}
}
第三步:在應用中測試使用@EnableMyBean
@SpringBootApplication(scanBasePackages = "com.jimisun.learnspringboot.three")
@EnableMyBean
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(Main.class)
.web(WebApplicationType.NONE)
.run(args);
String bean = context.getBean("hello", String.class);
context.close();
}
}
實戰:自定義@Enable介面實現方式
第一步:實現自定義註解@EnableMyBean
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyBeanConfigSelector.class)
public @interface EnableMyBean {
}
PS:注意@Import(MyBeanConfigSelector.class)匯入的類和@Enable註解驅動匯入的不一樣,這裡匯入的是一個實現了ImportSelector介面的類
public class MyBeanConfigSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{new MyBeanConfig().getClass().getName()};
}
}
PS:在MyBeanConfigSelector類中我們可以自定義複雜的邏輯,這裡我們僅僅簡單返回MyBeanConfig配置類。
第三步:建立MyBeanConfig配置類
@Configuration
public class MyBeanConfig {
@Bean
public String hello() {
return "word";
}
}
第四步:在應用中測試使用@EnableMyBean
@SpringBootApplication(scanBasePackages = "com.jimisun.learnspringboot.four")
@EnableMyBean
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(Main.class)
.web(WebApplicationType.NONE)
.run(args);
String bean = context.getBean("hello", String.class);
context.close();
}
}
PS:其實@Enable介面的實現方式和@Enable註解實現方式是基本一樣的,只不過多了一個步驟,方便我們更靈活地進行編寫邏輯。
Spring Framework條件裝配
從 Spring Framework 3.1 開始,允許在 Bean 裝配時增加前置條件判斷
Spring 註解 | 場景說明 | 起始版本 |
---|---|---|
@Profile | 配置化條件裝配 | 3.1 |
@Conditional | 程式設計條件裝配 | 4.0 |
實戰:自定義@Profile 配置化條件裝配
第一步:自定義建立某服務不同的@Profile實現類
public interface UserService {
void println();
}
@Service
@Profile("vip")
public class VipUserservice implements UserService {
@Override
public void println() {
System.out.println("I am VIP User");
}
}
@Service
@Profile("common")
public class CommonUserservice implements UserService {
@Override
public void println() {
System.out.println("I am Common User");
}
}
第二步:在構建Spring容器指定配置
@ComponentScan(basePackages = "com.jimisun.learnspringboot.two")
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext run = new SpringApplicationBuilder(Main.class).
web(WebApplicationType.NONE).
profiles("vip").
run(args);
UserService bean = run.getBean(UserService.class);
bean.println();
run.close();
}
}
實戰:自定義@Conditional 程式設計條件裝配
第一步:建立一個自定義註解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({MyOnConditionProperty.class})
public @interface MyConditionOnPropertyAnnotion {
String prefix() default "";
}
PS:注意@Conditional註解,將會找到MyOnConditionProperty類的matches方法進行條件驗證
第二步:建立該註解的條件驗證類,該類實現Condition介面
public class MyOnConditionProperty implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Map<String, Object> annotationAttributes =
annotatedTypeMetadata.getAnnotationAttributes(MyConditionOnPropertyAnnotion.class.getName());
String prefix = String.valueOf(annotationAttributes.get("prefix"));
return prefix.equals("pass");
}
}
第三步:在Spring應用中應用條件裝配
@SpringBootApplication
public class Main {
@Bean(name = "hello")
@MyConditionOnPropertyAnnotion(prefix = "pass")
public String hello() {
return "word";
}
public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(Main.class)
.web(WebApplicationType.NONE)
.run(args);
String bean = context.getBean("hello", String.class);
context.close();
}
}
PS:本例自定義的MyConditionOnPropertyAnnotion在應用中裝配的時候可以指定prefix值,該值將會在實現了Condition藉口的matches進行條件驗證,如果驗證通過,則在Spring容器中裝配該Bean,反之則不裝配。
SpringBoot 自動裝配
在 Spring Boot 場景下,基於約定大於配置的原則,實現 Spring 元件自動裝配的目的。其中底層使用了一系列的Spring Framework手動裝配的方法來構成Spring Boot自動裝配。
自定義SpringBoot自動裝配
- 啟用自動裝配 - @EnableAutoConfiguration
- 實現自動裝配 - XXXAutoConfiguration
- 配置自動裝配實現 - META-INF/spring.factories
第一步 :啟用自動裝配 - @EnableAutoConfiguration
@EnableAutoConfiguration
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(Main.class)
.web(WebApplicationType.NONE)
.run(args);
String bean = context.getBean("hello", String.class);
context.close();
}
}
第二步:實現自動裝配 - XXXAutoConfiguration
@Configuration
@EnableMyBean
public class HelloWordAutoConfiguration {
}
PS:這裡使用了上面我們建立的@EnableMyBean,這個註解會注入一個名為“hello"的Bean
第三步:配置自動裝配實現 - META-INF/spring.factories
在ClassPath目錄下建立META-INF資料夾再建立spring.factories檔案
#配置自己的自動裝配Bean
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.jimisun.learnspringboot.five.HelloWordAutoConfiguration
最後:執行測試第一步中的Main方法,看是否能獲取到名為“hello”的Bean
本章總結
本章我們主要了解了Spring Framework的模式註解裝配,@Enable裝配和條件裝配。對於SpringBoot的自動裝配我們僅僅做了一下演示,遵循SpringBoot裝配的三個步驟,我們就可以執行SpringBoot的自動裝配。但是對於SpringBoot為什麼要遵循這三個步驟?自動裝配的原理?我們不知所以然,所以下一章節我們仍然以SpringBoot的自動裝配為主題,對SpringBoot的底層原始碼做剖析。