首先寫一個咱們本身的HelloWorld配置類spring
一、基於"註解驅動"實現@Enable模塊編程
@Configuration public class HelloWorldConfiguration { @Bean public String helloWorld() { return "Hello,World"; } }
再模仿Spring Cloud Feign源碼解析 中的@EnableFeignClients代碼寫一個咱們本身的標籤數組
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(HelloWorldConfiguration.class) public @interface EnableHelloWorld { }
@EnableFeignClients Import的是FeignClientsRegistrar.class,而咱們這裏導入的是HelloWorldConfiguration.class服務器
再編寫一個引導類來看一下效果。ide
@EnableHelloWorld @Configuration public class EnabledHelloWorldBootstrap { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(EnabledHelloWorldBootstrap.class); context.refresh(); String helloWorld = context.getBean("helloWorld", String.class); System.out.printf("helloWorld = %s \n",helloWorld); context.close(); } }
運行結果(部分)ui
15:00:46.060 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
15:00:46.065 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
15:00:46.069 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'helloWorld'
helloWorld = Hello,World
15:00:46.069 [main] INFO org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@31a5c39e: startup date [Thu Nov 21 15:00:45 CST 2019]; root of context hierarchy
15:00:46.070 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
15:00:46.070 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5427c60c: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,enabledHelloWorldBootstrap,com.cloud.demo.config.HelloWorldConfiguration,helloWorld]; root of factory hierarchyspa
二、基於"接口編程"實現@Enable模塊.net
基於ImportSelector接口實現server
假設當前應用支持兩種服務類型:HTTP和FTP,經過@EnableServer設置服務器類型(type)提供對應的服務對象
先定義一個服務接口
public interface Server { /** * 啓動服務器 */ void start(); /** * 關閉服務器 */ void stop(); /** * 服務器類型 */ enum Type { HTTP, //HTTP服務器 FTP //FTP服務器 } }
兩個實現類
@Component public class HTTPServer implements Server { @Override public void start() { System.out.println("HTTP服務器啓動中..."); } @Override public void stop() { System.out.println("HTTP服務器關閉中..."); } }
@Component public class FTPServer implements Server { @Override public void start() { System.out.println("FTP服務器啓動中..."); } @Override public void stop() { System.out.println("FTP服務器關閉中..."); } }
實現@Enable模塊驅動
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ServerImportSelector.class) public @interface EnableServer { /** * 設置服務器類型 * @return */ Server.Type type(); }
實現Server ImportSelector接口
public class ServerImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //讀取EnableServer中全部的屬性方法,本例中僅有type()屬性方法 //其中key爲屬性方法的名稱,value爲屬性方法的返回對象 Map<String,Object> annotationAttributes = importingClassMetadata .getAnnotationAttributes(EnableServer.class.getName()); //獲取名爲type的屬性方法,而且強制轉換成Server.Type類型 Server.Type type = (Server.Type) annotationAttributes.get("type"); //導入的類名稱數組 String[] importClassNames = new String[0]; switch (type) { case HTTP: importClassNames = new String[]{HTTPServer.class.getName()}; break; case FTP: importClassNames = new String[]{FTPServer.class.getName()}; break; } return importClassNames; } }
標註@EnableServer到引導類EnableServerBootstrap
@Configuration @EnableServer(type = Server.Type.HTTP) public class EnableServerBootstrap { public static void main(String[] args) { //構建Annotation配置驅動Spring上下文 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //註冊當前引導類(被@Configuration標註)到Spring上下文 context.register(EnableServerBootstrap.class); //啓動上下文 context.refresh(); //獲取Server Bean對象,實際爲HttpServer Server server = context.getBean(Server.class); //啓動服務器 server.start(); //關閉服務器 server.stop(); } }
運行結果(部分)
16:52:08.966 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@2fb3536e]
16:52:08.967 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
16:52:08.975 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
16:52:08.979 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.cloud.demo.server.HTTPServer'
HTTP服務器啓動中...
HTTP服務器關閉中...
基於ImportBeanDefinitionRegistrar接口實現
替換上例中的ServerImportSelector便可
public class ServerImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //複用 {@link ServerImportSelector} 實現,避免重複勞動 ImportSelector importSelector = new ServerImportSelector(); //篩選Class名稱集合 String[] selectedClassNames = importSelector.selectImports(importingClassMetadata); //建立Bean定義 Stream.of(selectedClassNames) //轉化爲BeanDefinitionBuilder對象 .map(BeanDefinitionBuilder::genericBeanDefinition) //轉化爲BeanDefinition .map(BeanDefinitionBuilder::getBeanDefinition) //註冊BeanDefinition到BeanDefinitionRegistry .forEach(beanDefinition -> BeanDefinitionReaderUtils .registerWithGeneratedName(beanDefinition,registry)); } }
替換@EnableServer的@Import
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ServerImportBeanDefinitionRegistrar.class) public @interface EnableServer { /** * 設置服務器類型 * @return */ Server.Type type(); }
運行結果
17:38:53.147 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
17:38:53.150 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
17:38:53.152 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.cloud.demo.server.HTTPServer#0'
HTTP服務器啓動中... HTTP服務器關閉中...