自定義依賴注入注解實現@Autowired功能

通過自定義注解來實現注入功能有兩種方法
第一種通過元注解的方式,在自定義注解上面用@Autowired標注既可以實現

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

第二種是通過向Spring中注冊一個AutowiredAnnotationBeanPostProcessor實現链沼,重點介紹第二種方式

public class DependencyResolutionDemo {

    @MyAutowried
    private User user;

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        context.register(DependencyResolutionDemo.class);

        context.refresh();

        DependencyResolutionDemo bean = context.getBean(DependencyResolutionDemo.class);
        System.out.println(bean.user);

        context.close();
    }

    @Bean
    public User user() {
        User user = new User();
        user.setId(2L);
        return user;
    }
    

    @Bean
    public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
        AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
        postProcessor.setAutowiredAnnotationType(MyAutowried.class);
        return postProcessor;
    }
}

上述代碼可以在不影響原有實現的同時實現對自定義注解的擴展

原理

在Spring啟動時,會獲取類型為BeanPostProcessor.class的bean名稱鸯旁,然后獲取對應Bean的實例,并加入beanFactory中的beanPostProcessors列表當中量蕊,代碼流程如下

public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    
 
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

        List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // 獲取bean實例
                BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    // 將bean添加進集合
                    internalPostProcessors.add(pp);
                }
            }
        }
    // 對internalPostProcessors根據Order進行排序
    sortPostProcessors(internalPostProcessors, beanFactory);
    // 將processors添加進beanFactory的beanPostProcessors中
    registerBeanPostProcessors(beanFactory, internalPostProcessors);
    
}

// BeanFactory中的processors
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
        private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
   
}

對自定義注解的處理

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {
    
    
    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        // 獲取beanFactory中所有的processor遍歷處理
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                // 處理自定義注解相關依賴
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }
    
}



在創(chuàng)建 AutowiredAnnotationBeanPostProcessor 對象時铺罢,方法最好聲明成靜態(tài)方法,這樣在Spring初始化該對象時就可以不用依賴它的外部對象

在該例中残炮,如果beanPostProcessor() 方法不用static修飾韭赘,會造成User對象無法注入問題,

原因就在于Spring要先獲取所有的AutowiredAnnotationBeanPostProcessor 對象势就,在執(zhí)行beanPostProcessor()方法時需要先初始化其外部類 DependencyResolutionDemo泉瞻,當初始化此對象時,就會對User對象開始注入苞冯,但是此時處理@MyAutowoired的注解處理器還沒有初始化完成袖牙,就會造成@MyAutowoired 注解不能被處理

解決方法就是將beanPostProcessor()方法標注為static方法,或者將beanPostProcessor()單獨寫入另一個配置類當中

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末舅锄,一起剝皮案震驚了整個濱河市鞭达,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖畴蹭,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坦仍,死亡現場離奇詭異,居然都是意外死亡叨襟,警方通過查閱死者的電腦和手機繁扎,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糊闽,“玉大人梳玫,你說我怎么就攤上這事∮矣蹋” “怎么了汽纠?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長傀履。 經常有香客問我,道長垢村,這世上最難降的妖魔是什么肿孵? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任灌诅,我火速辦了婚禮,結果婚禮上梆暮,老公的妹妹穿的比我還像新娘。我一直安慰自己绍昂,他們只是感情好啦粹,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窘游,像睡著了一般唠椭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忍饰,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天贪嫂,我揣著相機與錄音,去河邊找鬼艾蓝。 笑死力崇,一個胖子當著我的面吹牛,可吹牛的內容都是我干的赢织。 我是一名探鬼主播亮靴,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼于置!你這毒婦竟也來了茧吊?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饱狂,沒想到半個月后曹步,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡休讳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年讲婚,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俊柔。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡筹麸,死狀恐怖,靈堂內的尸體忽然破棺而出雏婶,到底是詐尸還是另有隱情物赶,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布留晚,位于F島的核電站酵紫,受9級特大地震影響,放射性物質發(fā)生泄漏错维。R本人自食惡果不足惜奖地,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赋焕。 院中可真熱鬧参歹,春花似錦、人聲如沸隆判。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侨嘀。三九已至臭挽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間咬腕,已是汗流浹背埋哟。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留郎汪,地道東北人赤赊。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像煞赢,于是被迫代替她去往敵國和親抛计。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容