Spring 注解分类
Spring 注解驱动模型
Spring 元注解
@Documented
@Retention()
@Target()
// 可以继承相关的属性
@Inherited
@Repeatable()
Spirng 模式注解
@ComponentScan 原理
ClassPathScanningCandidateComponentProvider#findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
组合注解
比如@RestController,@SpringBootApplication
注解转换为AnnotationAttributes然后进行合并统一
Spring属性别名
显性别名:
隐式别名:
这个组合注解
继承EnableAutoConfiguration的属性,用隐式别名来表达,也就是直接拿过来不需要改变它的值:
如果说我们要补充语义,引用某个属性,自己定义新的属性名称来引用父类的:
举例如果我们要派生这个注解,我们不可能在注解里面写死扫描路径,这个时候就要通过隐式别名来继承注解ComponentScan的属性,这样我们就可以配置scanBasePackages
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@ComponentScan
public @interface MyComponentScan {
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String scanBasePackages() default "";
}
我们也可以这样:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@ComponentScan
public @interface MyComponentScan {
// 传递性别名 basePackages -> value value -> scanBasePackages
@AliasFor(annotation = ComponentScan.class, attribute = "value")
String scanBasePackages() default "";
}
Spring属性覆盖
注解和原注解出现同名属性的时候会覆盖原注解的属性
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@ComponentScan
public @interface MyComponentScan {
@AliasFor(annotation = ComponentScan.class, attribute = "value")
String scanBasePackages() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@MyComponentScan
public @interface MyComponentScan2 {
// 显示覆盖
String[] scanBasePackages() default "";
// 隐式覆盖
@AliasFor(attribute = "scanBasePackages")
String[] packages() default {};
}
@MyComponentScan2(packages = {"com.yong.annotationpkg"})
// packages 覆盖scanBasePackages scanBasePackages覆盖MyComponentScan scanBasePackages scanBasePackages 引用的是ComponentScan
Spring @Enable 模块驱动
案例1通过@Configration实现
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DemoConfig.class)
public @interface EnableDemo {
}
@Configuration
public class DemoConfig {
@Bean
Person person() {
Person person = new Person();
person.setName("liy");
person.setId(11L);
return person;
}
}
@EnableDemo
public class EnableAnnotationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(EnableAnnotationDemo.class);
context.refresh();
Person bean = context.getBean(Person.class);
System.out.println(bean);
}
}
案例2通过ImportSelector接口实现:
public class DemoImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.yong.annotationpkg.DemoConfig"};
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DemoImportSelector.class)
public @interface EnableDemo {
}
@EnableDemo
public class EnableAnnotationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(EnableAnnotationDemo.class);
context.refresh();
Person bean = context.getBean(Person.class);
System.out.println(bean);
}
}
案例3通过
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DemoImportBeanDefinitionRegister.class)
public @interface EnableDemo {
}
public class DemoImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
AnnotatedBeanDefinition annotatedBeanDefinition = new AnnotatedGenericBeanDefinition(DemoConfig.class);
registry.registerBeanDefinition("demoConfig", annotatedBeanDefinition);
}
}
Spring 条件注解
@Configuration
public class ProfileDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(ProfileDemo.class);
ConfigurableEnvironment environment = context.getEnvironment();
// 兜底方案
environment.setDefaultProfiles("odd");
// 激活方案
environment.setActiveProfiles("even");
context.refresh();
Object odd = context.getBean(Integer.class);
System.out.println(odd);
context.close();
}
// 激活不同的环境注册不同的Bean
@Bean
@Profile("odd")
public Integer odd() {
return 2;
}
@Bean
@Profile("even")
public Integer even() {
return 1;
}
}
自定义实现:
public class EvenProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
return environment.acceptsProfiles("even");
}
}
@Bean
@Conditional(EvenProfileCondition.class)
public Integer even() {
return 1;
}
ConditionEvaluator#shouldSkip
参考资料
小马哥核心编程思想