SpringBoot原理——Bean花式装配——Day02

news/2024/11/23 0:48:27/

目录

Five——容器初始化完成后注入bean

那么同一个实体类被加载多次会怎么样呢?

 

Six——导入源的编程式处理

Seven——bean裁定

拓展

Eight——最终裁定


Five——容器初始化完成后注入bean

import lombok.Data;
import org.springframework.stereotype.Component;@Component("miao")
@Data
public class Cat {
}

被注入的JavaBean

import org.springframework.context.annotation.Configuration;@Configuration
public class Config5 {
}

被加载的配置类

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;public class App2 {public static void main(String[] args) {AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);context.registerBean(Cat.class);String[] names = context.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
}

在加载配置类的时候,普通的ApplicationContext不具备该功能。

可以看到其还具有扫描JavaBean注解的功能,直接把名字装配了,没有自定义名字的话就是类名首字母小写。

那么同一个实体类被加载多次会怎么样呢?

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;@Component("miao")
@Data
@NoArgsConstructor
public class Cat {String shout;public Cat(String shout) {this.shout = shout;}
}

 

import org.springframework.context.annotation.Configuration;@Configuration
public class Config5 {
}

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;public class App2 {public static void main(String[] args) {AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);context.registerBean(Cat.class,"1");context.registerBean(Cat.class,"2");context.registerBean(Cat.class,"3");Cat miao = context.getBean("miao",Cat.class);System.out.println(miao.getShout());}
}

可以看到如果被加载多次的话,后面会覆盖前面的。

这个和我们在配置yml文件属性时有异曲同工之妙,配置了就是你的配置,没有配置就是默认的,你的配置会覆盖默认的配置,其中那些配置背后就是一个一个的bean对象罢了。 

Six——导入源的编程式处理

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;@Component("miao")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {String shout;
}
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {return new String[]{"yi.beans.Cat"};}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import yi.beans.MyImportSelector;@Configuration
@Import(MyImportSelector.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.config.Config5;public class App2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);String[] names = context.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
}

 可以看到注册了bean,并且还识别到了注解的value值。

不过这种方式还仅不于此,还可以做很多判定。

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {boolean b = annotationMetadata.hasAnnotation("org.springframework.context.annotation.Configuration");if (b){     //判断是否包含这个注解return new String[]{"yi.beans.Cat"};}else {return new String[]{"yi.beans.Dog"};}}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import yi.beans.MyImportSelector;//@Configuration
@Import(MyImportSelector.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;public class App2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);String[] names = context.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
}

可以看到,我们通过API可以达到多种多样的效果,不仅有查看注解是否存在啊,还能获取注解的所有参数等等。 

@Configuration注解如果不被@ComponentScan扫描的话,直接被容器加载。是可以省略的,所以后面我是用@Import也是可以的。

Seven——bean裁定

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;@Component("miao")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {String shout;
}

实体类我通过注解给它的bean赋了名字。

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(Cat.class).getBeanDefinition();registry.registerBeanDefinition("mao",beanDefinition);}
}

AnnotationMetadata这个属性我忽略了,因为这就是上一个定义bean的方式,可以通过元数据对其条件判断,你可以结合到一块。下面是定义了bean的名字,不过还有许多ApI你可以慢慢看有空的时候。


import org.springframework.context.annotation.Import;
import yi.beans.MyImportBeanDefinitionRegistrar;@Import(MyImportBeanDefinitionRegistrar.class)
public class Config5 {
}

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.config.Config5;public class App2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);String[] names = context.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
}

 

可以看到这里注解的value值被覆盖了,在之前的方法中,一直都获取的是注解的value值为bean的名字,由此说明,这种方式的权限也开放了不少。

拓展

那么如果我使用这种方式加载同一个bean加载了多次,是哪个生效呢?我来用接口模拟。可以发现是最后一个被加载的在生效。可能有人会疑问,为什么bean名字一样,编译时不报异常呢?

因为一个项目是分布式的情况下,一个配置bean可能会被多个人修改,需要确保这些bean能够覆盖达到刷新的效果,我猜的,不一定对。


public interface BookService {void check();
}
import yi.beans.BookService;public class BookServiceImpl1 implements BookService {@Overridepublic void check() {System.out.println("书籍是人类进步的阶梯");}
}
import yi.beans.BookService;public class BookServiceImpl2 implements BookService {@Overridepublic void check() {System.out.println("书籍是人类进步的阶梯");}
}
import yi.beans.BookService;public class BookServiceImpl3 implements BookService {@Overridepublic void check() {System.out.println("书籍是人类进步的阶梯");}
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import yi.beans.impl.BookServiceImpl1;public class MyImportBeanDefinitionRegistrar1 implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl1.class).getBeanDefinition();registry.registerBeanDefinition("bookService",beanDefinition);}
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import yi.beans.impl.BookServiceImpl2;public class MyImportBeanDefinitionRegistrar2 implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();registry.registerBeanDefinition("bookService",beanDefinition);}
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import yi.beans.impl.BookServiceImpl3;public class MyImportBeanDefinitionRegistrar3 implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();registry.registerBeanDefinition("bookService",beanDefinition);}
}
import org.springframework.context.annotation.Import;
import yi.beans.*;@Import({MyImportBeanDefinitionRegistrar1.class, MyImportBeanDefinitionRegistrar2.class, MyImportBeanDefinitionRegistrar3.class})
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.BookService;
import yi.config.Config5;public class App2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);String[] names = context.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}BookService bookService = context.getBean("bookService", BookService.class);System.out.println(bookService.getClass());}
}

 

Eight——最终裁定

基于第七种方式,我们要是就是想要加载某个bean,又不想被其他人的覆盖该怎么办呢?也就是说我们这个类无论加载到哪个位置,都不会被覆盖。请看第八种方式。

在第七种拓展的基础上,我们再加如下:

import yi.beans.BookService;public class BookServiceImpl4 implements BookService {@Overridepublic void check() {System.out.println("书籍是人类进步的阶梯");}
}

再加一个实现类。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import yi.beans.impl.BookServiceImpl4;public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();beanDefinitionRegistry.registerBeanDefinition("bookService",beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}
}

通过BeanDefinition的注册器实名bean,实现对bean的最终裁定。

import org.springframework.context.annotation.Import;
import yi.beans.*;@Import({MyImportBeanDefinitionRegistrar1.class, MyImportBeanDefinitionRegistrar2.class, MyPostProcessor.class, MyImportBeanDefinitionRegistrar3.class,})
public class Config5 {
}

可以看到,我将该类没有放到最后。

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.BookService;
import yi.config.Config5;public class App2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);String[] names = context.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}BookService bookService = context.getBean("bookService", BookService.class);System.out.println(bookService.getClass());}
}

 该类注册的bean没有被覆盖耶。权限是不是更开放了。bean的加载就到此为止。了解这些,springboot的源码你读起来就不会那么费劲了。


http://www.ppmy.cn/news/22752.html

相关文章

mysql 慢sql 分析工具pt-query-digest

mysql 慢sql 分析工具pt-query-digest1.简介2.安装2.1源码安装2.2 安装问题3.工具用法简介3.1 慢查询日志分析统计3.2 服务器摘要3.3 服务器磁盘监测3.4 mysql服务状态摘要3.5 pt-query-digest 慢SQL分析3.5.1 pt-query-digest语法及重要选项3.5.2 分析pt-query-digest输出结果…

JAVA-Spring Bean的生命周期

目录 基本概念 生命周期 Spring Bean的生命周期有哪些? 实例 目录结构 文件内容 MyBeanPostProcess文件 PersonBean文件 spring-config.xml文件 Test2文件 实例运行结果 如果本篇博客对您有一定的帮助,大家记得留言点赞收藏哦。 我们了解一个对…

Android SVG认知误区?

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/128907538 本文出自【赵彦军的博客】 文章目录前言为什么svg 在编译期间,会自动生成多份图片?优化建议前言 为了更好的视觉效果,经常在项目中使用了 svg &…

Mysql从入门到精通—14标识列

#标识列 /* 又称为自增长列 含义:可以不用手动的插入值,系统提供默认的序列值 特点: 1、标识列必须和主键搭配吗?不一定,但要求是一个key 2、一个表可以有几个标识列?至多一个! 3、标识列的类型…

加油站会员管理小程序实战开发教程08-低代码中调用模型方法

我们上一篇介绍了地图API的创建以及在低码中如何调用数据源的方法。本篇我们继续我们的开发。 上一篇中我们介绍了如何传参调用数据源方法的问题,本篇我们讲解一下如何理解数据源的出参。 我们先看一下我们上一篇调用数据源的返回结果 我们再看一下数据源方法的出参 查询列表…

智能指针——C++

文章目录1. 为什么需要智能指针?2. 内存泄漏2.1 什么是内存泄漏,内存泄漏的危害2.2 内存泄漏分类(了解)2.3如何避免内存泄漏3.智能指针的使用及原理3.1 RAII3.2 智能指针的原理3.3 std::auto_ptr3.4 std::unique_ptr3.5 std::shar…

Python的热门冷知识,还不赶紧记好

目录 这里写自定义目录标题 一、注释 二、行与缩进 三、Python中特有的交换两个变量的值的方法 四、循环的巧应用(列表解析) 五、eval()函数与str()函数 六、条件表达式的紧凑形式 七、try-except语句的应用…

docker 制作镜像-基于commit命令创建(为ubuntu18.04版本添加SSH服务)

Docker提供了docker commit命令,支持用户提交自己对制定容器的修改,并生成新的镜像。 格式: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] Options 参数 -a,作者(例如,“along alongalong.com”…