注解

  • 元注解
  • 自定义注解
  • @ConditionalOn
  • @FunctionalInterface

注解

元注解

注解其他注解
java.lang.annotation包中四个标准meta-annotation:

  • @Target 描述注解的适用范围

  • @Retention 表示需要在什么级别保存该注释信息,描述注解的生命周期 Source < Class < Runtime

    1. RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成 .class 文件的时候,被其标注的注解被遗弃;
    2. RetentionPolicy.CLASS:注解被保留到class文件中,但jvm加载 .class 文件时候,被其标注的注解会被遗弃,这是默认的生命周期;
    3. 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;
}