文章目录
- 1、@SpringBootApplication启动
- 1.1、@SpringBootApplication组成部分
- 2、@SpringBootConfiguration组成
- 3、@EnableAutoConfiguration开启自动化配置
- 3.1、@EnableAutoConfiguration组成部分
- 3.1.1、@Import注解
- 3.1.2、@Import(AutoConfigurationImportSelector.class)
- 3.2、@AutoConfigurationPackage组成部分
- 3.2.1、@Import(AutoConfigurationPackages.Registrar.class)
- 4、@ComponentScan包扫描
1、@SpringBootApplication启动
1.1、@SpringBootApplication组成部分
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
- @Target(ElementType.TYPE)
注解的作用目标
(ElementType.TYPE)——接口、类、枚举、注解 - @Retention(RetentionPolicy.RUNTIME)
注解的保留位置
这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用 - @Documented
说明该注解将被包含在javadoc中 - @Inherited
说明子类可以继承父类中的该注解
以上四个注解非常熟悉就不再赘述,下面就重点说一下后面非常重要的三个注解
2、@SpringBootConfiguration组成
//@SpringBootConfiguration组成
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
其中最重要的是@Configuration 注解,就这个注解来详细解释,当然我们继续深入进去
//Configuration组成
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
我们知道Spring容器在启动的时候会默认加载一些PostProcessor(后置处理器),其中有一个处理器叫ConfigurationClassPostProcessor,这个处理器就是专门处理带有Configuration注解的类,里面有一个方法如下图:
我们进入这个方法中,查看源代码
在第二个循环中通过enhance()方法对所有能够找到的带Configuration注解的类进行加强,实际上替换看原来的Beanclass使用了代理类。编写代码测试一下
@Configuration
public class Myconfig {
@Bean
Autor getAutor(){
return new Autor();
}
@Bean
Book getBook(){
return new Book(getAutor());
}
}
@SpringBootTest
class Demo01ApplicationTests {
@Autowired
Myconfig myconfig;
@Test
void contextLoads() {
System.out.println("myconfig = " + myconfig);
}
}
结果可以得到一个CGLIB代理类
然后我们再通过一段测试代码说明@Configuration和@Component区别
public class Book {
private Autor autor;
public Book() {
}
public Book(Autor autor) {
this.autor = autor;
}
public Autor getAutor() {
return autor;
}
public void setAutor(Autor autor) {
this.autor = autor;
}
}
public class Autor {
}
@Configuration
public class Myconfig {
@Bean
Autor getAutor(){
return new Autor();
}
@Bean
Book getBook(){
return new Book(getAutor());
}
}
//测试方法
@SpringBootTest
class Demo01ApplicationTests {
@Autowired
Autor autor;
@Autowired
Myconfig myconfig;
@Autowired
Book book;
@Test
void contextLoads() {
System.out.println("myconfig = " + myconfig);
System.out.println("book.getAutor() = " + (autor == book.getAutor()));
}
}
测试结果:
接着我们将@Configuration注解替换为@Component
@Configuration
public class Myconfig {
@Bean
Autor getAutor(){
return new Autor();
}
@Bean
Book getBook(){
return new Book(getAutor());
}
}
我们看结果:
对比两次结果发现BOOK类第一拿到的Autor类就是我们注入容器中的那个类,而第二次拿到的类是由getAutor方法创建的新类,是因为带有@Configuration注解被替换成了CGLB代理类,内部得到进一步加强,主要加入了Bean的拦截器intercept,拦截所有带@Bean注解的方法,所以这个拦截器就会查找容器中是否存在Autor类,如果存在就不会调用getAutor方法去创建的新类,如果不存在才会创建新类。而@Component就不会去扫描容器中是否会存在Autor类,就会直接调用getAutor方法去创建的新类。
方法isCurrentlyInvokedFactoryMethod是判断Bean中getAutor方法到底是在@Bean getAutor()中还是在@Bean getBook()中,第一次是会进入if中调用cglibMethodProxy.invokeSuper()方法调用 getAutor()方法去创建,第二次进入是调用cglibMethodProxy.invokeSuper()方法调用 getBook()方法去创建,第三次进入是不会进入if中会直接调用resolveBeanReference方法在beanFactory中去寻找,因为 getBook()方法中的getAutor()方法不是在当前Bean中的方法,已经在第一次的Bean中创建成功了
3、@EnableAutoConfiguration开启自动化配置
3.1、@EnableAutoConfiguration组成部分
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
3.1.1、@Import注解
在原生的Spring Framework中,组件装配有三个阶段:
- Spring2.5+ @Component
- Spring3.0+ 使用@Configuration和+@Bean
- Spring3.1+ @Enablexxx+@Import
例子:
public class Apple {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Banana {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class FruitImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{Apple.class.getName(), Banana.class.getName()};//返回字符串数组装着Bean的名字
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
//1.@Import({Apple.class, Banana.class})
//2.可以直接导入配置类
//3.@Import(FruitImportSelector.class)
//4.@Import(FruitImportDefinitionRegistar.class)
public @interface EableFruit {
}
@SpringBootApplication
@EableFruit
public class Demo04Application {
public static void main(String[] args) {
SpringApplication.run(Demo04Application.class, args);
}
}
3.1.2、@Import(AutoConfigurationImportSelector.class)
public class FruitImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{Apple.class.getName(), Banana.class.getName()};//返回字符串数组装着Bean的名字
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(FruitImportSelector.class)
public @interface EableFruit {
}
@SpringBootApplication
@EableFruit
public class Demo04Application {
public static void main(String[] args) {
SpringApplication.run(Demo04Application.class, args);
}
}
作用:加载资源文件(找到资源目录)
META-INF/spring.factories目录中配置了启动类的位置
3.2、@AutoConfigurationPackage组成部分
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
3.2.1、@Import(AutoConfigurationPackages.Registrar.class)
public class FruitImportDefinitionRegistar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("apple", new RootBeanDefinition(Apple.class));
registry.registerBeanDefinition("banana", new RootBeanDefinition(Banana.class));
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(FruitImportDefinitionRegistar.class)
public @interface EableFruit {
}
@SpringBootApplication
@EableFruit
public class Demo04Application {
public static void main(String[] args) {
SpringApplication.run(Demo04Application.class, args);
}
}
4、@ComponentScan包扫描
只扫描启动类所在包下的东西
//包扫描
@ComponentScan(excludeFilters//除去某些不扫描的类的过滤器 = {
@Filter(type = FilterType.CUSTOM,
classes = TypeExcludeFilter.class),//自定义过滤器
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class)//不扫描自动化配置类
//之前的@EnableAutoConfiguration已经扫描过
})
@Service
public class HelloService {
}
public class MyTypeExcludeFilter extends TypeExcludeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return HelloService.class.getName().equals(metadataReader.getClassMetadata().getClassName());
}
}
public class MyAppInit implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override//后置处理器
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new MyTypeExcludeFilterPostProcessor());
}
private static class MyTypeExcludeFilterPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
beanDefinitionRegistry.registerBeanDefinition(MyTypeExcludeFilter.class.getName(),new RootBeanDefinition(MyTypeExcludeFilter.class));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public int getOrder() {//优先级
return HIGHEST_PRECEDENCE;
}
}
}
org.springframework.context.ApplicationContextInitializer=com.dong.demo04.Config.MyAppInit
这样就会用自定义的过滤器过滤掉HelloService类,后置处理器将MyTypeExcludeFilterPostProcessor加载进来
而MyTypeExcludeFilterPostProcessor将MyTypeExcludeFilter注册到Bean中,这样就完成了对自定义的过滤器