SpringBoot原理——Bean花式装配——Day02
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
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 {
@Override
public 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 {
@Override
public 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 {
@Override
public 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 {
@Override
public void check() {
System.out.println("书籍是人类进步的阶梯");
}
}
import yi.beans.BookService;
public class BookServiceImpl2 implements BookService {
@Override
public void check() {
System.out.println("书籍是人类进步的阶梯");
}
}
import yi.beans.BookService;
public class BookServiceImpl3 implements BookService {
@Override
public 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 {
@Override
public 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 {
@Override
public 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 {
@Override
public 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 {
@Override
public 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 {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition("bookService",beanDefinition);
}
@Override
public 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的源码你读起来就不会那么费劲了。