Spring Boot自定義@Enable模塊驅動
註解驅動
先看下Spring Framework已有的實現,@EnableWebMvc
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
@Import({DelegatingWebMvcConfiguration.class}),引用了DelegatingWebMvcConfiguration類。
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
...
}
可以看出,DelegatingWebMvcConfiguration只是一個@Configuration類。
接下來實現我們自己@Enable模塊驅動
自定義@Configuration類
@Configuration
public class HelloWorldConfiguration {
@Bean
public String helloWorld() {
return "hello world";
}
}
實現@EnableHelloWorld
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
自定義啓動類
@EnableHelloWorld
@Configuration
public class EnableHelloWorldBootStrap {
public static void main(String[] args) {
//構建Spring上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//將當前引導類註冊到Spring中
context.register(EnableHelloWorldBootStrap.class);
//啓動
context.refresh();
//獲取名稱爲helloWorld的Bean
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println("helloWorld = " + helloWorld);
}
}
這樣我們就基於註解實現了模塊驅動。
接口驅動
基於接口進行實現,需要實現ImportSelector或者ImportBeanDefinitionRegistrar接口
實現ImportSelector
假設學校裏有學生和老師,Student和Teacher,通過@EnablePeople來設置人員類型。
定義接口
public interface People {
void work();
enum Type {
/**
* 學生
*/
STUDENT,
/**
* 老師
*/
TEACHER,
}
}
實現StudentPeople和TeacherPeople
/**
* 遵循約定,確保是spring的組件。
*/
@Component
public class StudentPeople implements People {
@Override
public void work() {
System.out.println("這是學生在工作");
}
}
/**
* 遵循約定,確保是spring的組件。
*/
@Component
public class TeacherPeople implements People {
@Override
public void work() {
System.out.println("這是老師在工作");
}
}
定義@EnablePeople
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(PeopleImportSelector.class)
public @interface EnablePeople {
People.Type type();
}
實現PeopleImportSelector
public class PeopleImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//讀取EnablePeople中所有的屬性方法
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnablePeople.class.getName());
People.Type type = (People.Type) annotationAttributes.get("type");
//導入的類名稱數組
String[] importClassNames = new String[0];
switch (type) {
case STUDENT:
importClassNames = new String[]{StudentPeople.class.getName()};
break;
case TEACHER:
importClassNames = new String[]{TeacherPeople.class.getName()};
break;
default:
break;
}
return importClassNames;
}
}
創建啓動類
@Configuration
@EnablePeople(type = People.Type.STUDENT)
public class BootStrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(BootStrap.class);
context.refresh();
People bean = context.getBean(People.class);
bean.work();
}
}
這是學生在工作
得到了我們想要的結果,然後將STUDENT修改爲TEACHER,
這是老師在工作
實現ImportBeanDefinitionRegistrar
其它與實現ImportSelector一致。
實現ImportBeanDefinitionRegistrar接口
public class PeopleImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//讀取EnablePeople中所有的屬性方法
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnablePeople.class.getName());
People.Type type = (People.Type) annotationAttributes.get("type");
//導入的類名稱數組
String[] importClassNames = new String[0];
switch (type) {
case STUDENT:
importClassNames = new String[]{StudentPeople.class.getName()};
break;
case TEACHER:
importClassNames = new String[]{TeacherPeople.class.getName()};
break;
default:
break;
}
Stream.of(importClassNames)
//轉化爲BeanDefinitionBuilder對象
.map(BeanDefinitionBuilder::genericBeanDefinition)
//轉化爲BeanDefinition
.map(BeanDefinitionBuilder::getBeanDefinition)
//註冊到BeanDefinitionRegistry
.forEach(beanDefinition ->
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry));
}
}
修改@EnablePeople導入類
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(PeopleImportBeanDefinitionRegistrar.class)
public @interface EnablePeople {
People.Type type();
}
重新啓動,觀察結果。一切正常。