Spring Framework模式注解
模式注解是一種用於聲明在應用中扮演“組件”角色的注解。如 Spring Framework 中的 @Repository 標注在任何類上 ,用
於扮演倉儲角色的模式注解。
模式注解(角色注解)
Spring Framework 注解 | 場景說明 |
---|---|
@Component | 通用組件模式注解 |
@Controller | Web 控制器模式注解 |
@Service | 服務模式注解 |
@Repository | 數據倉儲模式注解 |
@Configuration | 配置類模式注解 |
在Spring中進行裝配context:component-scan 方式
<?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 Framework@Enable模塊裝配
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的底層源碼做剖析。
該教程所屬Java工程師之SpringBoot系列教程,本系列相關博文目錄 Java工程師之SpringBoot系列教程前言&目錄