前言
在编程中,@import
注解通常用于导入外部的类、接口或其他资源,以便在当前代码文件中使用。它可以提供一种简洁、方便的方式来引入外部依赖,并且有以下几个主要的应用场景和好处:
引入外部类/接口:使用
@import
注解可以将其他模块或库中的类/接口引入到当前的代码文件中,使得我们可以直接使用这些类/接口,而无需手动编写完整的类名。这样可以减少代码中的冗余,提高可读性和编码效率。静态方法/常量引入:通过
@import
注解还可以引入外部类中的静态方法和常量,使得我们可以直接在当前代码文件中调用这些静态方法或使用常量,而无需每次都使用完整的类名进行访问。这样不仅简化了代码书写,还提高了代码的可读性。展示注解:
@import
注解也可以用于展示某个特定的注解,以便在当前代码文件中使用这个注解。这在一些特定的编程框架和库中非常常见,例如在使用 Spring 框架时,我们可以使用@import
注解来导入其他配置类,从而实现依赖注入等功能。
总结来说,@import
注解提供了一种便捷的方式来引入外部的类、接口、静态方法和常量,以及展示注解。它简化了代码书写、提高了可读性和编码效率,并且在一些特定的框架和库中具有特殊的用途。
一、开始学习
1、新建项目,结构如下
2、添加 spring 依赖
<!-- spring 的核心依赖 -->
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
</dependencies>
3、在 anno 包下新建一个 MyAnno 注解类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
}
这段代码定义了一个名为MyAnno
的注解。让我们一步步解析这段代码的含义:
@Target(ElementType.TYPE)
:这行代码使用@Target
注解来指定了注解的作用目标。在这里,指定的目标是ElementType.TYPE
,表示该注解可以应用于类、接口(包括注解类型)或枚举类型。
@Retention(RetentionPolicy.RUNTIME)
:这行代码使用@Retention
注解来指定了注解的生命周期。在这里,指定的生命周期是RetentionPolicy.RUNTIME
,表示该注解在运行时仍然可用,即可以通过反射等方式获取到该注解的信息。
public @interface MyAnno
:这行代码定义了一个注解类型MyAnno
。通过在类上使用@interface
关键字,将一个普通的接口声明为一个注解类型。
综上所述,这段代码定义了一个运行时可见的注解MyAnno
,并且可以应用于类、接口或枚举类型。你可以使用这个注解来修饰类、接口或枚举类型,然后在运行时通过反射等方式获取到被注解元素的相关信息。
4、在 controller 包下新建一个 UserController 类
@Slf4j
@MyAnno
public class UserController {
public void add(){
log.info("添加用户");
}
}
这段代码为UserController
类添加了@MyAnno
注解和@Slf4j
注解。让我们一步步解析这段代码的含义:
@MyAnno
:这个注解用来修饰UserController
类,表示该类被注解为MyAnno
类型。由于我们在MyAnno
注解中指定了作用目标为类、接口或枚举类型,所以这个注解可以应用于类。
@Slf4j
:这个注解是 Lombok 库提供的一个注解,用来自动生成日志记录器变量log
(即private static final Logger log = LoggerFactory.getLogger(UserController.class);
),避免了手动编写日志记录器的繁琐过程。
public class UserController
:这是一个普通的 Java 类定义,表示一个名为UserController
的类。
public void add()
:这是一个方法定义,表示UserController
类中的一个名为add
的公共实例方法。该方法使用了@Slf4j
注解生成的log
变量,用来记录日志信息。
综上所述,这段代码为UserController
类添加了@MyAnno
注解和@Slf4j
注解,并且定义了一个名为add
的公共实例方法,在该方法中调用了自动生成的日志记录器变量log
记录日志信息。
5、在 config 包下新建 Annoimportlector 配置类
/**
* @Date 2023-10-08
* @Author qiu
* 自定义导入选择器,如果类上标注了 @MyAnno 的注解,
* 就将其纳入 Spring 容器中管理
*/
public class AnnoimportSelector implements ImportSelector {
/**
*
* @param importingClassMetadata
* @return 所有需要导入类的完整类名
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 创建一个集合保存带有注解的类的完整类名
ArrayList<String> classNameList = new ArrayList<>();
// 解析类上是否存在 @MyAnno注解
if (UserController.class.isAnnotationPresent(MyAnno.class)){
classNameList.add(UserController.class.getName());
}
return StringUtils.toStringArray(classNameList);
}
}
这段代码定义了一个名为AnnoimportSelector
的类,实现了ImportSelector
接口。让我们一步步解析这段代码的含义:
public class AnnoimportSelector implements ImportSelector
:这是一个类定义,表示一个名为AnnoimportSelector
的类,实现了ImportSelector
接口。
@Override
:这个注解表示该方法是对父类或接口中同名方法的重写。
public String[] selectImports(AnnotationMetadata importingClassMetadata)
:这是一个方法定义,实现了ImportSelector
接口中的selectImports
方法。该方法的作用是根据指定的条件选择需要导入的类,并以完整类名的形式返回。
ArrayList<String> classNameList = new ArrayList<>();
:这行代码创建了一个ArrayList
集合,用于保存带有@MyAnno
注解的类的完整类名。
if (UserController.class.isAnnotationPresent(MyAnno.class))
:这行代码判断UserController
类是否存在@MyAnno
注解。如果存在,则将UserController
类的完整类名添加到classNameList
集合中。
return StringUtils.toStringArray(classNameList);
:这行代码将classNameList
集合转换为字符串数组,并作为selectImports
方法的返回值。
综上所述,这段代码定义了一个自定义的导入选择器AnnoimportSelector
,用于根据条件选择需要导入的类。在该选择器中,如果某个类标注了@MyAnno
注解,则将其纳入Spring容器中进行管理。
6、在 config 包下新建一个 AppConfig 配置类
不使用 @Import 注解实现调用 UserService 的方法
@Configuration
public class AppConfig {
@Bean
public UserController userController(){
return new UserController();
}
}
在该配置类中使用
@Bean
注解定义了一个名为userController
的Bean,该Bean是UserController
类的实例。通过这种方式,我们告诉Spring容器在启动时创建并管理这个UserController
的实例,从而可以在其他地方通过依赖注入的方式使用它。
7、测试
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserController bean = context.getBean(UserController.class);
bean.add();
}
}
运行结果
二、使用 @Import 注解
1、 使用 @Import 注解导入(装配)普通的 bean
更改 AppConfig 配置类
@Configuration
@Import(UserController.class)
public class AppConfig {
}
在该配置类中使用
@Import
注解将UserController
类导入到该配置类中进行管理。通过这种方式,我们告诉Spring容器在启动时创建并管理这个UserController
的实例,从而可以在其他地方通过依赖注入的方式使用它。
1)、测试
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserController bean = context.getBean(UserController.class);
bean.add();
}
}
运行结果
2、使用 @Import 注解导入其他的配置类(常用)
1)在 config 包下新建 MvcConfig、MybatisConfig 配置类
MvcConfig 配置类
@Configuration
public class MvcConfig {
}
MybatisConfig 配置类
@Configuration
public class MybatisConfig {
}
2)更改 AppConfig 配置类
@Configuration
@Import({MvcConfig.class,MybatisConfig.class,UserController.class})
public class AppConfig {
}
在该配置类中使用
@Import
注解将MvcConfig
、MybatisConfig
和UserController
三个类导入到该配置类中进行管理。通过这种方式,我们告诉Spring容器在启动时创建并管理这些类的实例,从而可以在其他地方通过依赖注入的方式使用它们。这个配置类可以用于配置Spring MVC框架、MyBatis框架以及UserController
类等相关的Bean。
3)、测试
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserController bean = context.getBean(UserController.class);
bean.add();
}
}
运行结果
3、 使用 @Import 注解实现选择性导入(即按照指定的逻辑来导入相关的类)
要实现选择性导入,可以使用@Import
注解配合Condition
接口来定义逻辑。
首先,创建一个实现Condition
接口的自定义条件类,例如MyCondition
:
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 在这里编写自定义的逻辑判断条件
// 返回true表示满足条件,需要导入相关类;返回false表示不满足条件,不导入相关类
// 可根据实际需求进行逻辑的判断与处理 return true;
} }
然后,在@Import
注解中使用自定义条件类:
@Configuration
@Import(value = {MvcConfig.class, UserController.class, MyConfiguration.class})
public class AppConfig {
// ...
}
在上述代码中,我们将MvcConfig
、UserController
和MyConfiguration
类作为参数传递给@Import
注解。对于需要选择性导入的类,可以根据自定义的条件类来决定是否导入。
最后,将自定义条件类注册到Spring容器中:
@Configuration
public class MyConfiguration {
@Bean
public MyCondition myCondition() {
return new MyCondition();
}
}
这样,当MyCondition
条件满足时,相关类会被导入到AppConfig
配置类中进行管理,否则不会被导入。通过编写自定义的条件类,我们可以根据实际需求灵活地实现选择性导入。
三、使用 @Import 的好处
使用@Import
注解的好处包括:
简化配置:通过
@Import
注解,可以将多个类一次性导入到配置类中进行管理,避免了在配置类中逐个声明依赖的繁琐过程,使得配置更加简洁、清晰。组织代码结构:
@Import
注解可以帮助将相关的类组织在一起,提高代码的可读性和可维护性。通过将相关的类一起导入到配置类中,可以更好地表示它们之间的关联。提供依赖注入支持:导入的类会交给Spring容器进行管理,可以通过依赖注入的方式在应用程序的其他地方使用。这样可以方便地使用这些类的实例,而无需手动创建和管理它们。
可选择性导入:
@Import
注解可以与自定义条件类(实现Condition
接口)结合使用,根据特定的条件来决定是否导入相关的类。这种灵活性可以根据实际需求进行选择性导入,提高系统的可配置性和扩展性。模块化开发:
@Import
注解可以帮助将不同模块的配置类组合在一起,实现模块化开发。通过导入其他模块的配置类,可以在一个配置类中同时配置多个模块,提供更好的代码组织和模块可复用性。
总之,@Import
注解是一个强大的工具,可以简化配置、提供依赖注入支持,并且具有选择性导入和模块化开发的优势。它使得应用程序的配置更加灵活、简洁和可读,提高开发效率和代码质量。
四、总结
本章节主要讲了 @Import 注解的三种使用:
1、使用 @Import 注解导入(装配)普通的 bean
例如:@Import(UserController.class)
2、使用 @Import 注解导入其他的配置类(常用)
例如:在项目中可以模块化配置类,包括 MVC 的配置类
mybatis 配置类,Redis 配置类、Rabbit MQ 配置类等等,
那么可以在一个总配置类中导入其他这些配置类进行合并,
这样维护性扩展性更强
例如:@Import({MvcConfig.class,MybatisConfig.class})
3、使用 @Import 注解实现选择性导入(即按照指定的逻辑来导入相关的类)
这种方式需要自定义一个导入选择器交给 spring 执行
五、gitee 案例
案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git