# @Eable * 注解

SpringBoot 中提供了很多 Enable 开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理是使用 @Import 注解导入一些配置类,实现 Bean 的动态加载。

<span alt='solid'> 思考 </span>:

SpringBoot 工程是否可以直接获取 jar 包中定义的 Bean?

答案:不可以

如果不可以这个地方问题就非常严重了。比如说 redisTemplate 获取,是不是人家 jar 包里面定义的 Bean 啊。那为什么我的工程引入了 redis 的起步依赖我就直接可以获取到了呢 ?

首先演示不能获取第三方 jar 包里面定义的 Bean 的特点

创建一个父模块,两个同级子模块

image-20230911215125989

将 enable-other 模块导入到 enable 模块中使用

<dependency>
   <groupId>com.dkx</groupId>
   <artifactId>SpringBoot-enable-other</artifactId>
   <version>0.0.1-SNAPSHOT</version>
</dependency>

install,enable-other 模块否则报错找不到 XXX 类

image-20230912074640515

编写 enable 模块

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
// @ComponentScan 扫描范围:当前引导类所在包及其子包
// com/dkx1
// com/dkx 
// 1. 使用 @ComponentScan 扫描,com.dkx. 包
// 2. 可以使用 @Impoert 注解,加载类
@SpringBootApplication
public class SpringBootEnableApplication {
	public static void main(String[] args) {
		ConfigurableApplicationContext run = SpringApplication.run(SpringBootEnableApplication.class, args);
		Object user = run.getBean("user");
		System.out.println(user);
	}
}

项目结构:

image-20230911215325372

编写 enable-other 模块

config/UserConfig

@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

domain / User

public class User { }

项目结构:

image-20230911215345356

运行结果:

image-20230911215412559

# 第一种方式

报错找不到 user 这个 Bean,我们可以通过下面的方式来解决。

首先要知道这个问题其实很简单,规则是子模块中路面相同的话就不会报错了,可以理解为两个模块可以看做一个模块的目录来构建就不会报错了。

import com.dkx.config.UserConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
// @ComponentScan 扫描范围:当前引导类所在包及其子包
// com/dkx1
// com/dkx
// 1. 使用 @ComponentScan 扫描,com.dkx. 包
// 2. 可以使用 @Impoert 注解,加载类
@SpringBootApplication
@ComponentScan("com.dkx.config")
//@Import(UserConfig.class)
public class SpringBootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootEnableApplication.class, args);
        Object user = run.getBean("user");
        System.out.println(user);
    }
}

运行结果:

image-20230911220053181

# 第二种方式

使用自定义注解的方式在自定义注解类使用 Import 导入 UserConfig 类然后在启动类中添加该自定义注解 简化获取 User 对象的操作

User

public class User { }

UserConfig

@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

EnableUser

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}

启动类

// @ComponentScan 扫描范围:当前引导类所在包及其子包
// com/dkx1
// com/dkx
// 两个路径同级路径项目可以被扫描到
@SpringBootApplication
// 简化操作
@EnableUser
public class SpringBootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootEnableApplication.class, args);
        Object user = run.getBean("user");
        System.out.println(user);
    }
}

运行结果:

image-20230913085728841

# 第三种方式

还可以更下目录来解决问题

目录结构:

image-20230912073845767

启动类代码:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
// @ComponentScan 扫描范围:当前引导类所在包及其子包
// com/dkx
// com/dkx
// 两个路径同级路径项目可以被扫描到
@SpringBootApplication
public class SpringBootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootEnableApplication.class, args);
        Object user = run.getBean("user");
        System.out.println(user);
    }
}

运行结果:

image-20230912073932170