SpringBoot Bean花式注解方法示例下篇
作者:零维展开智子
1.容器初始化完成后注入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对象罢了。
2.导入源的编程式处理
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也是可以的。
3.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()); } }
4.最终裁定
基于第七种方式,我们要是就是想要加载某个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的源码你读起来就不会那么费劲了。
到此这篇关于SpringBoot Bean花式注解方法示例下篇的文章就介绍到这了,更多相关SpringBoot Bean注解方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!