- 元注解
- 自定义注解
- @ConditionalOn
- @FunctionalInterface
注解
元注解
注解其他注解
java.lang.annotation包中四个标准meta-annotation:
@Target 描述注解的适用范围
@Retention 表示需要在什么级别保存该注释信息,描述注解的生命周期 Source < Class < Runtime
- RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成 .class 文件的时候,被其标注的注解被遗弃;
- RetentionPolicy.CLASS:注解被保留到class文件中,但jvm加载 .class 文件时候,被其标注的注解会被遗弃,这是默认的生命周期;
- RetentionPolicy.RUNTIME:注解不仅被保留到 .class 文件中,jvm 加载 .class 文件之后,被其标注的注解仍然存在,所以这个时候才可能通过反射机制读取注解的信息,而前两个生命周期中,通过反射机制读取不到注解信息的;
对应的生命周期:Java源文件(.java文件) —> .class文件 —> 内存中的字节码
@Document 说明该注解被包含在javadoc中
@Inherited 说明子类可继承父类的该注解
自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface myannotation { String attr() default ""; }
class Ps1 { @myannotation(attr = "my_annotation") private String name; }
|
@ConditionalOn
??????
@FunctionalInterface
只能有一个抽象方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @FunctionalInterface public interface MyIntf1 { MyIntf1 DEFAULT = (sss) -> { return new MyImp1(sss); };
MyImp1 create12(String s); }
class MyImp1 implements MyIntf1 {
String name;
@Override public MyImp1 create12(String s) { return new MyImp1(s); }
public MyImp1(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override public String toString() { return "MyImp1{" + "name='" + name + '\'' + '}'; } }
//调用 MyIntf1 myImp1 = MyIntf1.DEFAULT.create12("hello vvf");
|
@Import
倒入类到容器,使其成为bean
导入一个或多个配置类(@Configuration 类)或普通的组件类(如 @Component、@Service 等)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Configuration public class ConfigA { @Bean public BeanA beanA() { return new BeanA(); } }
@Configuration @Import(ConfigA.class) // 导入 ConfigA,使其 Bean 定义生效 public class ConfigB { @Bean public BeanB beanB() { return new BeanB(); } }
|
导入普通类
1 2 3 4 5 6 7 8 9 10
| public class ServiceA { public void doSomething() { System.out.println("ServiceA works!"); } }
@Configuration @Import(ServiceA.class) // 直接导入 ServiceA,使其成为一个 Bean public class AppConfig { }
|
ServiceA 会被 Spring 容器管理,可以通过 @Autowired 注入。
导入 ImportSelector 实现类
1 2 3 4 5 6 7 8 9 10 11 12
| public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 返回需要导入的配置类全限定名 return new String[] { "com.example.ConfigA", "com.example.ConfigB" }; } }
@Configuration @Import(MyImportSelector.class) // 动态导入配置类 public class AppConfig { }
|
导入 ImportBeanDefinitionRegistrar 实现类 ImportBeanDefinitionRegistrar 允许以编程方式注册 Bean 定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class MyBeanRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry ) { // 手动注册一个 Bean RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class); registry.registerBeanDefinition("myBean", beanDefinition); } }
@Configuration @Import(MyBeanRegistrar.class) // 动态注册 Bean public class AppConfig { }
|
常用于框架集成(如 MyBatis、Spring Boot 自动配置)
与 @ComponentScan 结合使用
@ComponentScan 负责扫描包,而 @Import 负责显式引入额外的配置
1 2 3 4 5
| @Configuration @ComponentScan("com.example.services") // 扫描包 @Import(ConfigA.class) // 额外导入配置类 public class AppConfig { }
|
在 Spring Boot 中的应用
- 引入第三方库的配置(如 @EnableXXX 注解底层通常使用 @Import)
- 模块化配置,拆分多个 @Configuration 类并按需导入。
1 2 3 4 5 6 7
| @SpringBootApplication @Import({ SecurityConfig.class, DatabaseConfig.class }) // 导入多个配置类 public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
|
应用
ConfigurationProperties注解
@RefreshScope //热更新
@ConfigurationProperties(prefix=”elasticsearch.info”){
private String username;
private String password;
private String hostname;
private int port;
private String scheme;
}