Spring Boot 走向自動裝配

Spring 模式注解裝配

模式注解(Stereotype Annotations)

A stereotype annotation is an annotation that is used to declare the role that a component plays within the application. For example, the @Repository annotation in the Spring Framework is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).
@Component is a generic stereotype for any Spring-managed component. Any component annotated with
@Component is a candidate for component scanning. Similarly, any component annotated with an annotation that is itself meta-annotated with @Component is also a candidate for component scanning. For example,
@Service is meta-annotated with @Component 

模式注解是一種用于聲明在應(yīng)用中扮演“組件”角色的注解车吹。如 Spring Framework 中的 @Repository 標(biāo)注在任何類上 钱贯,用 于扮演倉儲角色的模式注解搀罢。 @Component 作為一種由 Spring 容器托管的通用模式組件陶因,任何被 @Component 標(biāo)準(zhǔn)的組件均為組件掃描的候選對象。類 似地买乃,凡是被 @Component 元標(biāo)注(meta-annotated)的注解锈死,如 @Service ,當(dāng)任何組件標(biāo)注它時掸宛,也被視作組件掃 描的候選對象

模式注解舉例

Spring Framework 注解 場景說明 起始版本
@Repository 數(shù)據(jù)倉儲模式注解 2.0
@Component 通用組件模式注解 2.5
@Service 服務(wù)模式注解 2.5
@Controller Web 控制器模式注解 2.5
@Configuration 配置類模式注解 3.0

裝配方式

  • <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">
<!-- 激活注解驅(qū)動特性 --> <context:annotation-config />
<!-- 找尋被 @Component 或者其派生 Annotation 標(biāo)記的類(Class)死陆,將它們注冊為 Spring Bean --> <context:component-scan base-package="com.imooc.dive.in.spring.boot" />
</beans>
  • @ComponentScan 方式
public class SpringConfiguration {
... 
}

自定義模式注解

  • @Component "派生性"
/**
* 一級 {@link Repository @Repository}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
    String value() default "";
}
* @Component
    * @Repository
        * @FirstLevelRepository
  • @Component "層次性"
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
    String value() default "";
}
* @Component
    * @Repository
        * @FirstLevelRepository
            * @SecondLevelRepository 

Spring @Enable模塊裝配

Spring Framework 3.1 開始支持”@Enable 模塊驅(qū)動“。所謂“模塊”是指具備相同領(lǐng)域的功能組件集合唧瘾, 組合所形成一個獨立 的單元措译。比如 Web MVC 模塊、AspectJ代理模塊饰序、Caching(緩存)模塊领虹、JMX(Java 管 理擴展)模塊、Async(異步處 理)模塊等求豫。

@Enable 注解模塊舉例

框架實現(xiàn) @Enable 注解模塊 激活模塊
Spring Framework @EnableWebMvc Web MVC 模塊
@EnableTransactionManagement 事務(wù)管理模塊
@EnableCaching Caching 模塊
@EnableMBeanExport JMX 模塊
@EnableAsync 異步處理模塊
@EnableWebFlux Web Flux 模塊
@EnableAspectJAutoProxy AspectJ 代理模塊
Spring Boot @EnableAutoConfiguration 自動裝配模塊
@EnableManagementContext Actuator 管理模塊
@EnableConfigurationProperties 配置屬性綁定模塊
@EnableOAuth2Sso OAuth2 單點登錄模塊
Spring Cloud @EnableEurekaServer Eureka服務(wù)器模塊
@EnableConfigServer 配置服務(wù)器模塊
@EnableFeignClients Feign客戶端模塊
@EnableZuulProxy 服務(wù)網(wǎng)關(guān) Zuul 模塊
@EnableCircuitBreaker 服務(wù)熔斷模塊

實現(xiàn)方式

注解驅(qū)動方式

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

@Configuration
public class DelegatingWebMvcConfiguration extends
WebMvcConfigurationSupport {
... 
}

注解驅(qū)動方式

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
...
 }
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
    /**
    * {@inheritDoc}
    * @return {@link ProxyCachingConfiguration} or {@code
    AspectJCacheConfiguration} for
    * {@code PROXY} and {@code ASPECTJ} values of {@link
    EnableCaching#mode()}, respectively
    */
    public String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] {
AutoProxyRegistrar.class.getName(),ProxyCachingConfiguration.class.getName() };
        case ASPECTJ:
            return new String[] {
                AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME };
        default:
    } 
}

自定義 @Enable 模塊

基于注解驅(qū)動實現(xiàn) @EnableHelloWorld

public class HelloWorldConfiguration {
    @Bean
    public String helloWorld(){
        return "hello world 2018";
    }

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldConfiguration.class) //基于注解
public @interface EnableHelloWorld {
}

基于接口驅(qū)動實現(xiàn)

public class HelloWorldConfiguration {
    @Bean
    public String helloWorld(){
        return "hello world 2018";
    }

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldImportSelector.class)//基于接口 彈性
public @interface EnableHelloWorld {
}

public class HelloWorldImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{HelloWorldConfiguration.class.getName()};
    }
}

Spring 條件裝配

從 Spring Framework 3.1 開始塌衰,允許在 Bean 裝配時增加前置條件判斷

條件注解舉例

Spring注解 場景說明 起始版本
@Profile 配置化條件裝配 3.1
@Conditional 編程條件裝配 4.0

實現(xiàn)方式

  • 配置方式-@Profile
  • 編程方式-@Conditional
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
   /**
    * The classes that must be present. Since this annotation is parsed by loading class
    * bytecode, it is safe to specify classes here that may ultimately not be on the
    * classpath, only if this annotation is directly on the affected component and
    * <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
    * use this annotation as a meta-annotation, only use the {@link #name} attribute.
    * @return the classes that must be present
    */
   Class<?>[] value() default {};
   /**
    * The classes names that must be present.
    * @return the class names that must be present.
    */
     String[] name() default {};
}

自定義條件裝配

基于配置方式實現(xiàn)-@Profile

計算服務(wù),多整數(shù)求和 sum

  • 引導(dǎo)類
@ComponentScan(basePackages = "com.imooc.diveinspringboot.service")
public class CalculateServiceBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootstrap.class)
                .web(WebApplicationType.NONE).profiles("java8")
                .run(args);
        CalculateService calculateService = context.getBean(CalculateService.class);
        System.out.println("sum :"+calculateService.sum(1,2,3,4,5,6,7,8,9,10));
        context.close();
    }
}
  • 計算接口
public interface CalculateService {
    /**
     * 多個整數(shù)求和
     * @param values v
     * @return sum
     */
     Integer sum(Integer...values);

}
  • @Profile("Java7") : for 循環(huán)
@Profile("java7")
@Service
public class Java7CalculateService implements CalculateService {

    @Override
    public Integer sum(Integer... values) {
        System.out.println("java7 sum");
        int sum = 0;
        for(Integer v :values){
            sum+=v;
        }
        return sum;
    }
}
  • @Profile("Java8") : Lambda
@Profile("java8")
@Service
public class Java8CalculateService implements CalculateService {

    @Override
    public Integer sum(Integer... values) {
        System.out.println("java8 sum");
        return Stream.of(values).reduce(0,Integer::sum);
    }
}

基于編程方式實現(xiàn)-@ConditionalOnSystemProperty 通過判斷系統(tǒng)配置值來裝載Bean

  • 引導(dǎo)類
public class SystemPropertyConditionBootstrap {

    @ConditionOnSystemProperty(name = "user.name",value = "zed")
    @Bean
    public String helloWorld(){
        return "hello zed!";
    }
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(SystemPropertyConditionBootstrap.class).web(WebApplicationType.NONE).run(args);
        String helloWorld = context.getBean("helloWorld",String.class);
        System.out.println(helloWorld);
        context.close();
    }

}
  • Condition 注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionOnSystemProperty {
    /**
     * 名稱
     * @return name
     */
    String name();

    /**
     * 值
     * @return value
     */
    String value();
}
  • 條件實現(xiàn)類 implements Condition
public class OnSystemPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String,Object> attributes = metadata.getAnnotationAttributes(ConditionOnSystemProperty.class.getName());
        String propertyName = String.valueOf(attributes.get("name"));
        String propertyValue = String.valueOf(attributes.get("value"));

        String javaPropertyValue = System.getProperty(propertyName);

        return javaPropertyValue.equals(propertyValue);
    }
}

Spring Boot 自動裝配

底層裝配技術(shù)

  • Spring 模式注解裝配
  • Spring @Enable 模塊裝配
  • Spring 條件裝配
  • Spring 工廠加載機制
    • 實現(xiàn)類: SpringFactoriesLoader
    • 配置資源:META-INF/spring.factories

自動裝配舉例

參考 `META-INF/spring.factories`

實現(xiàn)方法

1.激活自動裝配-@EnableAutoConfiguration
2.實現(xiàn)自動裝配-XXXAutoConfiguration
3.配置自動裝配實現(xiàn)-META-INF/spring.factories

自定義自動裝配

HelloWorldAutoConfiguration
* 條件判斷:user.name == "zed"
* 模式注解: @Configuration
* @Enable 模塊:@EnableHelloWorld-> HelloWorldImportSelector->HelloWorldConfiguration->helloWorld

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝠嘉,一起剝皮案震驚了整個濱河市最疆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚤告,老刑警劉巖努酸,帶你破解...
    沈念sama閱讀 212,294評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杜恰,居然都是意外死亡获诈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評論 3 385
  • 文/潘曉璐 我一進店門心褐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舔涎,“玉大人,你說我怎么就攤上這事逗爹⊥鱿樱” “怎么了?”我有些...
    開封第一講書人閱讀 157,790評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昼伴。 經(jīng)常有香客問我匾旭,道長,這世上最難降的妖魔是什么圃郊? 我笑而不...
    開封第一講書人閱讀 56,595評論 1 284
  • 正文 為了忘掉前任价涝,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己吠勘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,718評論 6 386
  • 文/花漫 我一把揭開白布居兆。 她就那樣靜靜地躺著,像睡著了一般竹伸。 火紅的嫁衣襯著肌膚如雪泥栖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,906評論 1 290
  • 那天勋篓,我揣著相機與錄音吧享,去河邊找鬼。 笑死譬嚣,一個胖子當(dāng)著我的面吹牛钢颂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拜银,決...
    沈念sama閱讀 39,053評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼殊鞭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尼桶?” 一聲冷哼從身側(cè)響起操灿,我...
    開封第一講書人閱讀 37,797評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疯汁,沒想到半個月后牲尺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卵酪,經(jīng)...
    沈念sama閱讀 44,250評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡幌蚊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,570評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溃卡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溢豆。...
    茶點故事閱讀 38,711評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瘸羡,靈堂內(nèi)的尸體忽然破棺而出漩仙,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評論 4 332
  • 正文 年R本政府宣布队他,位于F島的核電站卷仑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏麸折。R本人自食惡果不足惜锡凝,卻給世界環(huán)境...
    茶點故事閱讀 40,018評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垢啼。 院中可真熱鬧窜锯,春花似錦、人聲如沸芭析。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馁启。三九已至驾孔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惯疙,已是汗流浹背助币。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留螟碎,地道東北人眉菱。 一個月前我還...
    沈念sama閱讀 46,461評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像掉分,于是被迫代替她去往敵國和親俭缓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,595評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理酥郭,服務(wù)發(fā)現(xiàn)华坦,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,778評論 6 342
  • 1.1 Spring IoC容器和bean簡介 本章介紹了Spring Framework實現(xiàn)的控制反轉(zhuǎn)(IoC)...
    起名真是難閱讀 2,578評論 0 8
  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器不从,...
    simoscode閱讀 6,703評論 2 22
  • 如果說家是一座房子,那孝就是地基寝优,勤是房梁条舔,恕是屋頂。 永遠要記住乏矾, 在某一個高度之上孟抗,就沒有風(fēng)雨云層迁杨。 如果你生...
    宜可老師閱讀 327評論 0 3