springBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而底层原理是使用@Import注解导入一些配置类,实现Bean的动态加载
然后我们思考一个问题,springBoot工程是否可以直接获取jar包中定义的Bean呢?
我们可以自己来验证一把。
首先,这需要两个项目工程,一个用来定义Bean,另一个用来获取Bean。
新建一个工程,叫做 java-springBoot-main
我们在工程中先获取一个Bean(这个我们规定为项目1),暂且定义为person,一会儿我们会在另外一个工程中定义这个Bean
Object person = context.getBean("person");
System.out.println(person);
然后我们新建一个工程,工程名叫做 java-springBoot-other
, 写一下person这个Bean(这个我们叫项目2)
先在domain的文件夹新建一个Person这个类,里边什么也不写
package com.example.domain;
public class Person {
}
package com.example.domain;
public class Person {
}
然后再写个配置类,在config文件夹下新建PersonConfig这个配置类
package com.example.config;
import com.example.domain.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PersonConfig {
@Bean
public Person person () {
return new Person();
}
}
然后我们运行一下项目1,看看能否获取person这个Bean
可以看到控制台上报错了,提示不能获取这个Bean
为什么呢? 我们可以看一下启动类上有一个注解 SpringBootApplication
, 点进这个注解可以看一下这里边有一个注解叫 ComponentScan
, 这个注解有一个作用,它其实是起扫描作用的,他的扫描范围是当前引导类所在包及其子包,项目1的包名是com.example.javaspringbootmain
, 项目2这个Bean的包名是 com.example.config
, 既不是这个类下的包,也不是他的子包,因此我们就不能获取这个Bean了
其实想要获取这个Bean还是有很多方法的:
使用@ComponentScan扫描
com.example.config
想要获取这个包,我们需要先导入包的坐标,在项目1的pom.xml中写一个项目2的坐标:
<dependency>
<groupId>com.example</groupId>
<artifactId>java-springBoot-other</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
在项目1的引导类上添加一个注解
@SpringBootApplication
@ComponentScan("com.example.config")
public class JavaSpringBootMainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(JavaSpringBootMainApplication.class, args);
Object person = context.getBean("person");
System.out.println(person);
}
}
重新运行一下项目1,可以看到打印出了Bean
但是我们仔细想想,这么做多少有些不太优雅,因为如果要获取很多Bean,就要写很多个 ComponentScan
注解,况且我们不一定知道他们的包名,有没有别的方式呢?
答案肯定是有
第二种方法就是使用 import
注解,来加载类,原理就是使用import导入的类都会被spring创建,并放入IOC容器中
所以项目1的代码变成了如下:
@SpringBootApplication
@Import(PersonConfig.class)
public class JavaSpringBootMainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(JavaSpringBootMainApplication.class, args);
Object person = context.getBean("person");
System.out.println(person);
}
}
重启项目1,也是可以获取到person这个Bean的
但是这个方法虽然比第一种好些,但还是不太优雅,我们需要记住很多类名
所以有了第三种方案
第三种方案就是我们可以对Import注解进行封装
在项目2中新建一个注解,名字叫做 EnablePerson
, 把我们刚才导入的类写在里边,然后点到import注解把他的三个注解也加上
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(PersonConfig.class)
public @interface EnablePerson {
}
然后我们修改一下项目1, 直接使用这个注解就行了
@SpringBootApplication
@EnablePerson
public class JavaSpringBootMainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(JavaSpringBootMainApplication.class, args);
Object person = context.getBean("person");
System.out.println(person);
}
}
重启项目1就可以获取Bean了
所以归根结底,是 import注解起的作用,下一节我们就详细了解一下import注解