Spring Bean注冊的幾種方式


條條大路通羅馬

前提:怕讀者沒有頭緒,請在https://blog.csdn.net/dong19891210/article/details/105697175的情況下看

Spring bean有以下幾種注冊方式:

1.  通過GenericBeanDefinition注冊

示例代碼:

消息輔助類

public class Message { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public void print() { System.out.println("消息是: " + message); } }

注冊測試類:

/** * * @author dgm * @describe "GenericBeanDefinition注冊bean定義" * @date 2020年4月27日 */ public class GenericBeanDefinitionExample { public static void main (String[] args) { DefaultListableBeanFactory context = new DefaultListableBeanFactory(); //在此構造bean定義 GenericBeanDefinition gbd = new GenericBeanDefinition(); gbd.setBeanClass(Message.class); // MutablePropertyValues mpv = new MutablePropertyValues(); mpv.add("message", "this is a bean"); //注冊到環境上下文 context.registerBeanDefinition("myBean", gbd); Message bean = context.getBean(Message.class); bean.print(); Message myBean = (Message) context.getBean("myBean"); myBean.print(); } }

結果:


2.  通過BeanDefinitionBuilder注冊

/** * * @author dgm * @describe "" * @date 2020年4月16日 */ public class BeanDefinitionBuilderExample { public static void main (String[] args) { DefaultListableBeanFactory context = new DefaultListableBeanFactory(); //用到了構建者模式 BeanDefinitionBuilder b = BeanDefinitionBuilder.rootBeanDefinition(Message.class) .addPropertyValue("message", "this is a bean"); context.registerBeanDefinition("myBean", b.getBeanDefinition()); Message bean = context.getBean(Message.class); bean.print(); Message myBean = (Message) context.getBean("myBean"); myBean.print(); } } 

效果同第一種情況,只是用的是BeanDefinitionBuilder模式

3. 通過BeanFactoryPostProcessor

public class MessageBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { // TODO Auto-generated method stub GenericBeanDefinition gbd = new GenericBeanDefinition(); gbd.setBeanClass(Message.class); MutablePropertyValues mpv = new MutablePropertyValues(); mpv.add("message", "this is a BeanFactoryPostProcessor bean"); gbd.setPropertyValues(mpv); ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition( "myBean", gbd); } } 

配置類

@Configuration public class MyConfig { @Bean MessageBeanFactoryPostProcessor messageConfigBean () { return new MessageBeanFactoryPostProcessor(); } }

測試類:

/** * * @author dgm * @describe "測試BeanFactoryPostProcessor" * @date 2020年4月27日 */ public class BeanFactoryPostProcessorExample { public static void main (String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); //MyBean bean = context.getBean(MyBean.class); //bean.doSomething(); //bean.doOtherSomething(); Message bean = context.getBean(Message.class); bean.print(); Message myBean = (Message) context.getBean("myBean"); myBean.print(); } } 

效果:


4. 通過BeanDefinitionRegistryPostProcessor

public class MessageBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { // TODO Auto-generated method stub } @Override public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry registry) throws BeansException { // TODO Auto-generated method stub GenericBeanDefinition gbd = new GenericBeanDefinition(); gbd.setBeanClass(Message.class); MutablePropertyValues mpv = new MutablePropertyValues(); mpv.add("message", "this is a BeanDefinitionRegistryPostProcessor bean"); gbd.setPropertyValues(mpv); registry.registerBeanDefinition( "myBean", gbd); } } 

配置類

@Configuration public class MyConfig { @Bean ConfigBeanFactoryPostProcessor myConfigBean () { return new ConfigBeanFactoryPostProcessor(); } /*@Bean MessageBeanFactoryPostProcessor messageBeanFactoryPostProcessor () { return new MessageBeanFactoryPostProcessor(); }*/ @Bean MessageBeanDefinitionRegistryPostProcessor messageBeanDefinitionRegistryPostProcessor () { return new MessageBeanDefinitionRegistryPostProcessor(); } } 

測試類:

public class BeanDefinitionRegistryPostProcessorExample { public static void main (String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); //MyBean bean = context.getBean(MyBean.class); //bean.doSomething(); //bean.doOtherSomething(); Message bean = context.getBean(Message.class); bean.print(); Message myBean = (Message) context.getBean("myBeanDefinitionRegistry"); myBean.print(); } } 

效果:


 

5. 通過Import

import類型有以下幾類:

5.1  ImportSelector導入

public interface PrintService { void print(String msg); } public class PrintServiceImpl implements PrintService{ @Override public void print(String msg) { System.out.println("Hello : " + msg); } } //重點,實現了ImportSelector public class MessageImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // TODO Auto-generated method stub return new String[] {PrintServiceImpl.class.getName()}; } } //配置類 @Configuration @Import(MessageImportSelector.class) public class MessageImportSelectorConfiguration { } 

測試代碼和效果:

 

注:我是以demo演示(selectImports()寫死了),實際場景中可以動態注入bean,想象空間很大。

 5.2  ImportBeanDefinitionRegistrar注冊

/** * * @author dgm * @describe "實現ImportBeanDefinitionRegistrar " * @date 2020年4月28日 */ public class MessageImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 只以演示為例,現實場景通過importingClassMetadata拿到動態數據 GenericBeanDefinition gbd = new GenericBeanDefinition(); gbd.setBeanClass(Message.class); MutablePropertyValues mpv = new MutablePropertyValues(); mpv.add("message", "this is a ImportBeanDefinitionRegistrar bean"); gbd.setPropertyValues(mpv); registry.registerBeanDefinition("myBean", gbd); GenericBeanDefinition printBeanDefinition = new GenericBeanDefinition(); printBeanDefinition.setBeanClass(PrintServiceImpl.class); registry.registerBeanDefinition("printBean", printBeanDefinition); } }

配置類:

@Configuration @Import(MessageImportBeanDefinitionRegistrar.class) public class MessageImportBeanDefinitionRegistrarConfiguration { } 

 測試

/** * * @author dgm * @describe "測試ImportBeanDefinitionRegistrar" * @date 2020年4月28日 */ public class ImportBeanDefinitionRegistrarDemo { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext( MessageImportBeanDefinitionRegistrarConfiguration.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); System.out.println(Arrays.asList(beanNames)); Message bean = applicationContext.getBean(Message.class); bean.print(); PrintService ps = (PrintService) applicationContext .getBean(PrintService.class); ps.print("ImportBeanDefinitionRegistrar demo"); } } 

​ 

5.3 組合式,比如kafak集成到spring

/** * * @author dgm * @describe "實現了ImportSelector接口的導入" * @date 2020年4月28日 */ public class MessageImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // TODO Auto-generated method stub //return new String[] {PrintServiceImpl.class.getName()}; //不再寫死了,用上元數據 Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(PrintServiceScan.class.getName()); String[] basePackages = (String[]) annotationAttributes.get("basePackages"); if (basePackages == null || basePackages.length == 0) {//PrintServiceScan的basePackages默認為空數組 String basePackage = null; try { basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName(); } catch (ClassNotFoundException e) { e.printStackTrace(); } basePackages = new String[] {basePackage}; } ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); TypeFilter printServiceFilter = new AssignableTypeFilter(PrintService.class); scanner.addIncludeFilter(printServiceFilter); Set<String> classes = new HashSet<>(); for (String basePackage : basePackages) { scanner.findCandidateComponents(basePackage).forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName())); } return classes.toArray(new String[classes.size()]); } }
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import(MessageImportSelector.class) public @interface PrintServiceScan { @AliasFor("value") String[] basePackages() default {}; @AliasFor("basePackages") String[] value() default {}; }

 

/** * * @author dgm * @describe "" * @date 2020年4月28日 */ @Configuration //@Import(MessageImportSelector.class) @PrintServiceScan("spring.service.impl") public class MessageImportSelectorConfiguration { } 
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Indexed; import spring.config.MessageImportSelectorConfiguration; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(MessageImportSelectorConfiguration.class) public @interface EnablePrintService { } 

最終測試:

/** * * @author dgm * @describe "測試組合式ImportSelector" * @date 2020年4月28日 */ public class ImportSelectorDemo { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MessageImportSelectorConfiguration.class); PrintService ps = (PrintService) applicationContext.getBean(PrintService.class); ps.print("組合式 ImportSelector demo"); } }

 

附詳情參考源碼ConfigurationClassParser類處理如何處理不同的import


 

總結:我是層層遞進寫的,spring bean 注冊幾種方式:GenericBeanDefinition,BeanDefinitionBuilder(設計模式無處不在),BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor,Import型。

靈活性很強,很難達成統一(連交通規矩都難一統,更何況這),條條大路通羅馬,沒有最好只有合適,如果讓你選擇注冊bean或擴展性開發或集成第三方,你會選哪種呢,可以參考mybatis(用ImportBeanDefinitionRegister注冊) ,activemq,kafak組合式,dubbo,redis等,甚至spring aop也算是bean的注冊(用了其他的方式注冊進來)擴展,也包括Spring Boot里@SpringBootApplication,springboot也是spring bean的擴展開發,不是嗎!!!決定已知性的bean可寫死注冊,不確定性的最好可配置性組合。搞懂了Spring bean及衍生品(就像金融衍生品一樣),就搞懂了90%中國軟件開發java領域業務技術的方向

 

參考:

0. https://www.programcreek.com/java-api-examples/index.php?class=org.springframework.beans.factory.support.GenericBeanDefinition&method=setAttribute

1. BeanDefinitionBuilder.java https://alvinalexander.com/java/jwarehouse/spring-framework-2.5.3/src/org/springframework/beans/factory/support/BeanDefinitionBuilder.java.shtml

2. bean definition for automatic FilterRegistrationBeanFactory http://dimafeng.com/2015/11/27/dynamic-bean-definition/

3. 使用@import導入實現了ImportBeanDefinitionRegistrar接口的類 https://blog.51cto.com/14672031/2474904

4. Spring向容器注冊Bean的高級應用 https://cloud.tencent.com/developer/article/1497795

5. How to integrate Jdon Framework with Spring http://en.jdon.com/springIntegration.html

6. Spring Boot dynamically injects beans through importbeandefinitionregister

https://programmer.help/blogs/spring-boot-dynamically-injects-beans-through-importbeandefinitionregister.html

7. Spring - Using ImportBeanDefinitionRegistrar

https://www.logicbig.com/tutorials/spring-framework/spring-core/import-bean-registrar.html

 8. importbeandefinitionregistrar   https://www.javatips.net/api/org.springframework.context.annotation.importbeandefinitionregistrar

 9. MessagingGatewayRegistrar.java  http://javadox.com/org.springframework.integration/spring-integration-core/4.0.4.RELEASE/org/springframework/integration/config/MessagingGatewayRegistrar.java.html

10. Spring - Dynamically register beans  https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM