1. 程式人生 > >Spring Boot 使用Java程式碼建立Bean並註冊到Spring中

Spring Boot 使用Java程式碼建立Bean並註冊到Spring中

從 Spring3.0 開始,增加了一種新的途經來配置Bean Definition,這就是通過 Java Code 配置 Bean Definition。
與Xml和Annotation兩種配置方式不同點在於:

前兩種Xml和Annotation的配置方式為預定義方式,即開發人員通過 XML 檔案或者 Annotation 預定義配置 bean 的各種屬性後,啟動 Spring 容器,Spring 容器會首先解析這些配置屬性,生成對應都?Bean Definition,裝入到 DefaultListableBeanFactory 物件的屬性容器中去。與此同時,Spring 框架也會定義一些內部使用的 Bean 定義,如 bean 名為”org.springframework.context.annotation.internalConfigurationAnnotationProcessor”的 ConfigurationClassPostProcessor 定義。

而後此刻不會做任何 Bean Definition 的定義解析動作,Spring 框架會根據前兩種配置,過濾出 BeanDefinitionRegistryPostProcessor 型別的 Bean 定義,並通過 Spring 框架生成其對應的 Bean 物件(如 ConfigurationClassPostProcessor 例項)。結合 Spring 上下文原始碼可知這個物件是一個 processor 型別工具類,Spring 容器會在例項化開發人員所定義的 Bean 前先呼叫該 processor 的 postProcessBeanDefinitionRegistry(…) 方法。此處實現基於 Java Code 配置Bean Definition的處理。

基於 Java Code 解析 Bean 的順序圖(檢視大圖
這裡寫圖片描述
該圖供大家瞭解即可,這裡不做詳細說明。

基於 Java Code 的配置方式,其執行原理不同於前兩種。它是在 Spring 框架已經解析了基於 XML 和 Annotation 配置後,通過加入 BeanDefinitionRegistryPostProcessor 型別的 processor 來處理配置資訊,讓開發人員通過 Java 程式設計方式定義一個 Java 物件。其優點在於可以將配置資訊集中在一定數量的 Java 物件中,同時通過 Java 程式設計方式,比基於 Annotation 方式具有更高的靈活性。並且該配置方式給開發人員提供了一種非常好的範例來增加使用者自定義的解析工具類。其主要缺點在於與 Java 程式碼結合緊密,配置資訊的改變需要重新編譯 Java 程式碼,另外這是一種新引入的解析方式,需要一定的學習成本。

另外提及一點的就是,Spring框架有3個主要的Hook類,分別是:

org.springframework.context.ApplicationContextAware
它的setApplicationContext 方法將在Spring啟動之前第一個被呼叫。我們用來同時啟動Jdon框架。

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
它的postProcessBeanDefinitionRegistry 和 postProcessBeanFactory 方法是第二和第三被呼叫,它們在Bean初始化建立之前啟動,如果Spring的bean需要的其他第三方中的元件,我們在這裡將其注入給Spring。

org.springframework.context.ApplicationListener
用於在初始化完成後做一些事情,當Spring所有XML或元註解的Bean都啟動被建立成功了,這時會呼叫它的唯一方法onApplicationEvent。

下面我們來完成一個,自己通過java程式碼建立bean,並註冊為Spring管理。
本例中,我們建立一個介面,然後建立該介面的2個實現類,分別命名不同的名字,然後在需要注入的地方使用@Qualifier 指定注入對應的例項。

1、介面Shanhy.java

package org.springboot.sample.config;

public interface Shanhy {

    void display();

}

2、實現類ShanhyA.java

package org.springboot.sample.config;

public class ShanhyA implements Shanhy {

    @Override
    public void display() {
        System.out.println("AAAAAAAAAAAA");
    }

}

3、實現類ShanhyB.java

package org.springboot.sample.config;

public class ShanhyB implements Shanhy {

    @Override
    public void display() {
        System.out.println("BBBBBBBBBBBB");
    }

}

4、定義介面BeanDefinitionRegistryPostProcessor的實現

package org.springboot.sample.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ScopeMetadata;
import org.springframework.context.annotation.ScopeMetadataResolver;

/**
 * 實現自己例項化bean並註冊為Spring管理
 *
 * @author   單紅宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月21日
 */
@Configuration
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    private static final Logger logger = LoggerFactory.getLogger(MyBeanDefinitionRegistryPostProcessor.class);

    private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        logger.info("Invoke Metho postProcessBeanFactory");
        // 這裡可以設定屬性,例如
        BeanDefinition bd = beanFactory.getBeanDefinition("dataSourceA");  
        MutablePropertyValues mpv =  bd.getPropertyValues();  
        mpv.addPropertyValue("driverClassName", "com.mysql.jdbc.Driver");
        mpv.addPropertyValue("url", "jdbc:mysql://localhost:3306/test");
        mpv.addPropertyValue("username", "root");
        mpv.addPropertyValue("password", "123456");
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        logger.info("Invoke Metho postProcessBeanDefinitionRegistry");
        registerBean(registry, "shanhyA", ShanhyA.class);
        registerBean(registry, "shanhyB", ShanhyB.class);
        registerBean(registry, "dataSourceA", org.apache.tomcat.jdbc.pool.DataSource.class);
    }

    private void registerBean(BeanDefinitionRegistry registry, String name, Class<?> beanClass){
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        // 可以自動生成name
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, registry));

        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }
}

5、使用測試
和平常一樣可以直接注入我們的物件,對於同樣介面的我們需要指定name

/**
 * 測試引數注入
 *
 * @author   單紅宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月13日
 */
@Configuration
public class MyConfiguration {

    @Bean
    public FilterRegistrationBean filterRegistrationBean(@Qualifier("shanhyB") Shanhy shanhy) {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        shanhy.display();
        // 省略程式碼
        return filterRegistration;
    }
}

使用@Resource 或者 @Autowired並指定@Qualifier 也可以

@RestController
@RequestMapping("/hello")
public class HelloController {

    @Resource(name="shanhyA")
    private Shanhy shanhyA;

    @Autowired
    @Qualifier("shanhyB")
    private Shanhy shanhyB;

    // 省略程式碼

}

這裡有點經驗要說一下,在 @Configuration 中,不能使用注入屬性的方式注入,只能通過引數的方式注入,其原因就是@Configuration的類一開始變被載入,此時你想進行屬性注入,需要注入的bean物件都還不存在呢。

下一篇文章,我們將使用這種方法動態建立基於MyBatis的多資料來源。

下面的程式碼片段也可以註冊Bean,比較簡單:

@Configuration
@Import(Registrar.class)
public class TestConfig {

}

class Registrar implements ImportBeanDefinitionRegistrar {

    private static final String BEAN_NAME = "myTestBean";

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        if (!registry.containsBeanDefinition(BEAN_NAME)) {
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(ExamplePostProcessor.class);
            beanDefinition.setSynthetic(true);
            registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
        }
    }

}

相關推薦

Spring Boot 使用Java程式碼建立Bean註冊Spring

從 Spring3.0 開始,增加了一種新的途經來配置Bean Definition,這就是通過 Java Code 配置 Bean Definition。 與Xml和Annotation兩種配置方式不同點在於: 前兩種Xml和Annotation的配置方式

41. Spring Boot 使用Java程式碼建立Bean註冊Spring【從零開始學Spring Boot

【視訊&交流平臺】 http://study.163.com/course/introduction.htm?courseId=1004329008&utm_campaign=commission&utm_source=40000000

java建立bean註冊spring

從Spring 3.0開始,增加了一種新的途徑來配置Bean Definition,這就是通過Java Code配置Bean Definition。        與XML和Annotation兩種配置方式不同點在於:     前兩種方式XML和Annotatio

Spring. 通過Java程式碼裝配bean

儘管在很多情況下通過元件掃描和自動裝配來實現 Spring 的自動化配置是更為推薦的方式,但有時候自動化配置的方案行不通,因此需要明確配置 Spring。比如說你想要將第三方庫中的元件裝配到你的應用中,在這種情況下,是沒辦法在它的類上新增 @Component 和 @Autowired 註解的,

Spring Boot 框架學習 (一)配置執行Spring Boot 框架

下載開發工具: 下載完成開啟以後,第一步檢查環境 檢視jdk是否配置: 接著一定要注意,maven通常情況下它是沒有給你配置的,要自行配置:  右鍵新建:   然後依賴選擇web、跟Mybatis就行了。 建立好專案後,會發現自帶了這個Applicatio

由淺入深分散式(5)dubbo提供者用內網地址註冊provider以及 spring boot admin client用主機名註冊spring boot admin server

之前遇到過dubbo提供者用內網地址註冊provider的問題 當時改了host檔案成功了 但是沒有想為什麼會有這個問題 現在使用spring boot admin 來監控spring boot專案出現瞭如下問題, 如果是client和server端 分離,而且不在一臺機器

Docker 二:IDEA + Docker 外掛建立映象執行 spring boot 專案

IDEA 上提供了 Docker integration 外掛,可以很方便的管理映象和容器,當然這些操作通過命令列也能完成,使用 IDEA 外掛方式的另一個便利在於 IDEA 提供了 Docker 配套的 Configuration,可以一次性定義好操作序列,修改程式碼或資源後只需 Ru

Spring裝配之——JAVA程式碼裝配Bean

首先建立幾個普通的JAVA物件,用於測試JAVA程式碼裝配bean的功能。 1 package soundsystemJava; 2 3 //作為介面 定義了CD播放器對一盤CD所能進行的操作 4 public interface CD { 5 void play(); 6

Spring Boot 攔截器建立註冊

一、攔截器```public class MyInterceptorimplements HandlerInterceptor {private Loggerlogger = LoggerFactory.getLogger ( MyInterceptor.class );    private NamedTh

java後臺程式碼建立表格填充相應的內容

       java後臺程式碼建立表格(生成圖片)                                             /**      * 動態建立5行兩列表格,並填充相應的內容      *      * @param       * @

Spring裝配Bean -- 通過Java程式碼裝配Bean

建立可被發現的Bean:        建立CD介面:package main.java.Demo1; /** * @author [email protected] * @date 18-4-15 下午6:53 */ public interface C

曹工說Spring Boot原始碼(3)-- 手動註冊Bean Definition不比遊戲好玩嗎,我們來試一下

寫在前面的話 相關背景及資源: 曹工說Spring Boot原始碼系列開講了(1)-- Bean Definition到底是什麼,附spring思維導圖分享 工程程式碼地址 思維導圖地址 工程結構圖: 大體思路 選擇bean definition實現類,並例項化bean definition 註冊bea

Java框架spring Boot學習筆記(八):Spring相關概念

擴展 靜態 輕量級 想要 spring配置 核心 使用 oot 調用方法 Spring是開源、輕量級、一站式框架。 Spring核心主要兩部分 aop:面向切面編程,擴展功能不是修改源代碼實現 ioc:控制反轉,比如一個類,在類裏面有方法(不是靜態的方法),想要調用類

Spring Boot, Java Config - No mapping found for HTTP request with URI [/…] in DispatcherServlet with name 'dispatcherServlet'

dispatch name req let servlet patch request found pack Spring Boot 啟用應用: error: No mapping found for HTTP request with URI [/…]

Spring Boot - 獲取所有的Bean信息

util one cto str org start oot ner patch 前言 Spring Boot啟動的時候需要加載許多Bean實現最小化配置,本文將嘗試找出Spring啟動後加載的所有Bean信息; 通過ApplicationContext 去獲取所有的Bea

Spring Boot普通類呼叫bean

轉:http://412887952-qq-com.iteye.com/blog/2292388 我們知道如果我們要在一個類使用spring提供的bean物件,我們需要把這個類注入到spring容器中,交給spring容器進行管理,但是在實際當中,我們往往會碰到在一個普通的Ja

資料新增非同步解析重新整理大資料量redis (——)(三)Spring Boot普通類呼叫bean【從零開始學Spring Boot

部落格分類:  從零開始學Spring Boot 從零開始學Spring BootSpring Boot普通類呼叫bean    【視訊&交流平臺】 à SpringBoot視訊 http://stu

Spring框架幾種建立bean的方式

Spring框架下,Bean的建立和裝配非常的靈活,提供了三種主要的方式,並且相互見可以互相看見,也就是你可以隨意地採用你喜歡且合適的方式建立Bean,而不用擔心他們之間的相容問題。     一、使用XML顯示配置Bean      

spring boot 實現最基礎的登陸註冊功能。

spring boot 實現最基礎的登陸註冊功能: 首先先看程式碼:資料庫: 先說自己遇到的坑:第一:資料庫的配置是複製之前的資料庫,導致自己在另一個數據庫中查詢資料,這點大家在application.properties這個裡面注意下   這句 spring.dat

【springboot】spring boot修改程式碼後無需重啟設定,在開發時實現熱部署

熱部署是什麼 大家都知道在專案開發過程中,常常會改動頁面資料或者修改資料結構,為了顯示改動效果,往往需要重啟應用檢視改變效果,其實就是重新編譯生成了新的Class檔案,這個檔案裡記錄著和程式碼等對應的各種資訊,然後Class檔案將被虛擬機器的ClassLoader載入。 而熱部署正是利用了這