将bean交给Spring容器管理的几种方式Spring核心Spring核心是IOC和AOP。所谓IoC,对于spring框架来说,就是spring负责控制对象的生命周期和对象之间的关系。至于更详细的描述,或者深入理解Spring的两大核心,不是本文的目的,暂且不赘述。在我们的Spring项目中,需要把Bean交给Spring容器,也就是IOC管理,这样就可以使用注解进行依赖注入了。包扫描+组件注解是自己给类写的。这种方式是我们日常开发中最常用的。Spring在容器中的springIOC的扫描路径下添加@Component、@Controller、@Service、@Repository注解的类。如果你用过MybatisPlus,那么这个和他的包扫描注入是一样的。那么我们的ComponentScan注解就有了三种配置。配置项basePackages用于定义扫描包的路径。@ComponentScan(basePackages="com.timemail.bootmp")例如,它扫描整个com.timemail.bootmp包下的类,将上面指定的注解放入IOC中。我在另一篇文章中找到了一个完整的例子:@ComponentpublicclassPerson{privateStringname;publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}@OverridepublicStringtoString(){return"Person{"+"name='"+name+'\''+'}';}}@ComponentScan(basePackages="com.springboot.initbean.*")publicclassDemo1{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(Demo1.class);Personbean=applicationContext.getBean(Person.class);System.out.println(bean);}}//resultPerson{name='null'}这意味着上面代码中的Person类已经被IOC容器管理了。配置项2includeFilters包含规则Filter注解。使用FilterType.CUSTOM自定义扫描规则。您需要实现TypeFilter接口来实现match方法。参数为MetadataReader当前类的信息(注解、类路径、类原始信息...)MetadataReaderFactoryMetadataReader的工厂类。配置项三excludeFilters去除规则同包含规则。后两个配置项我用的不多,不是很熟悉,详细使用请参考相关资料。@Configuration+@Bean@Configuration+@Bean也是我们常见的放入容器的方式。@Configuration用于声明一个配置类@Bean用于声明一个Bean@ConfigurationpublicclassDemo{@BeanpublicPersonperson(){Personperson=newPerson();person.setAge(10);归还人;}}像这样。那么我们知道,在SSM中,我们一般都是在xml中配置bean。@ConfigurationpublicclassConfigBean{}那么我们的@Configuration注解就相当于一个Bean的xml配置。/beans中的属性>Bean注解我们的@Bean注解有很多可以配置的属性。我们可以查看其源码:@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})//@1@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceBean{@AliasFor("name")String[]value()默认{};@AliasFor("value")String[]name()default{};@DeprecatedAutowireautowire()defaultAutowire.NO;布尔autowireCandidate()默认为真;StringinitMethod()默认"";StringdestroyMethod()defaultAbstractBeanDefinition.INFER_METHOD;}值和名称相同。设置时,这两个参数只能选择一个。原因是@AliasFor造成的值:一个字符串数组,第一个值作为bean的名字,其他值作为Bean的别名autowire:这个参数被@Deprecated标记,说明已经过期了,不建议使用autowireCandidate:注入其他对象时是否为候选bean。initMethod:bean初始化的方法,与生命周期相关。DestroyMethod:bean销毁的方法也跟生命周期有关。后面会详细讲解@Configuration修饰的类。spring容器会通过cglib代理为这个类创建一个类,代理会拦截所有被@Bean修饰的方法。默认情况下(bean是单例),保证这些方法只被调用一次,从而保证这些bean是同一个bean,即单例。@Import注解导入先看源码:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceImport{/***用来导入一个class文件*{@linkConfiguration@Configuration},{@linkImportSelector}、*{@linkImportBeanDefinitionRegistrar}或要导入的常规组件类。*/类>[]值();}@Import只能用于类注解。这里我直接搬运公众号:小哈学习Java的内容。他的解释非常详细。前两种方法大家可能用的比较多,平时开发中一定要知道。@Import注解可能用的不多,但是也很重要。在进行Spring扩展时经常使用它。它经常与自定义注解一起使用,然后将一个配置文件导入到容器中。关于@Import注解,我再介绍一下,它有四种使用方式。这是@Import注解的源码,也就是说只能放在类上。@Import直接导入类publicclassPerson{privateStringname;publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}@OverridepublicStringtoString(){return"Person{"+"name='"+name+'\''+'}';}}/***直接使用@Import导入person类,然后尝试从applicationContext中获取,成功获取**/@Import(Person.class)publicclassDemo1{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(Demo1.class);Personbean=applicationContext.getBean(Person.class);System.out.println(bean);}}上面的代码直接使用@Import导入了一个类,然后自动放到IOC容器中。注意:我们的Person类不需要任何注解,直接导入即可。@Import+ImportSelector在@Import注解的源码中其实写的很清楚。有兴趣的可以看看我们实现了一个ImportSelector接口,然后实现里面的方法进行导入。@Import(MyImportSelector.class)publicclassDemo1{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(Demo1.class);Personbean=applicationContext.getBean(Person.class);System.out.println(bean);}}classMyImportSelectorimplementsImportSelector{@OverridepublicString[]selectImports(AnnotationMetadataimportingClassMetadata){returnnewString[]{"com.springboot.pojo.Person"};}}我自定义了一个MyImportSelector实现ImportSelector接口,重写selectImports方法,然后在里面写上我们要导入的类的全限定名,实现起来很简单。@Import+ImportBeanDefinitionRegistrar该方法同样需要我们实现ImportBeanDefinitionRegistrar接口中的方法,具体代码如下:@Import(MyImportBeanDefinitionRegistrar.class)publicclassDemo1{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=新的AnnotationConfigDe1ApplicationContext(.class);Personbean=applicationContext.getBean(Person.class);System.out.println(bean);}}classMyImportBeanDefinitionRegistrarimplementsImportBeanDefinitionRegistrar{@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanfinitionbeRegistrar{//buildaregistry),后面会介绍beanDefinition,可以简单理解为bean定义。AbstractBeanDefinitionbeanDefinition=BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();//将beanDefinition注册到Ioc容器中。registry.registerBeanDefinition("person",beanDefinition);}}上面的实现其实就是Import的第二个两种方法几乎一样,都是需要实现接口,然后导入。接触到一个新概念,BeanDefinition,可以简单理解为一个bean的定义(bean元数据),同样需要在IOC容器中进行管理。首先有bean的Metadata,applicationContext再根据bean的元数据创建Bean。@Import+DeferredImportSelector也需要我们实现接口。其实和@Import的第二种方法类似。DeferredImportSelector是ImportSelector的一个子接口,所以实现方法同第二种方法。只是Spring的处理方式不同。与SpringBoot中自动导入配置文件的延迟导入有关,非常重要。用法如下:@Import(MyDeferredImportSelector.class)publicclassDemo1{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(Demo1.class);Personbean=applicationContext.getBean(Person.class);系统.out.println(bean);}}classMyDeferredImportSelectorimplementsDeferredImportSelector{@OverridepublicString[]selectImports(AnnotationMetadataimportingClassMetadata){//同样直接把Person的完全限定名放在returnnewString[]{Person.class.getName()};}}关于@Import注解的使用,大概有以上三种。当然也可以配合@Configuration注解来导入一个配置类。FactoryBean接口说到FactoryBean,我们很多初学开发者很容易把他和BeanFactory混淆。BeanFactory是所有SpringBeans的容器根接口。它为Spring容器定义了一套规范,为IOC容器提供了一套完整的规范,比如我们经常使用的getBean方法。也就是我们常说的Bean工厂。而我们的FactoryBean,它其实就是一个Bean,Factory就是他的名字,顾名思义。@ConfigurationpublicclassDemo1{@BeanpublicPersonFactoryBeanpersonFactoryBean(){返回新的PersonFactoryBean();}publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(Demo1.class);。班级);System.out.println(bean);}}类PersonFactoryBean实现FactoryBean{@OverridepublicPersongetObject()throwsException{returnnewPerson();}@OverridepublicClass>getObjectType(){returnPerson.class;}}在这里,我们可以先看看FactoryBean中的方法:他是一个接口类。那么我们需要一个类来继承这个接口并重写这个方法。这里,我们把需要注册的bean类放到FactoryBean的泛型中。getObject方法用于直接返回创建的对象。getObjectType直接返回类的类。那么其实还是需要使用@Bean注解来返回继承接口的类对象。然后Configuration注解,把这个类改成springboot的配置类,相当于springmvc中的xml文件。我们可以通过AnnotationConfigApplicationContext的getBean方法来查看是否被IOC管理。运行后可以看到输出了对象地址。描述成功。在使用BeanDefinitionRegistryPostProcessor写这篇文章的时候,也查了网上很多大佬的资料。有一种我不熟悉的方法。于是...开始照抄原文...其实这个方法也是用到了BeanDefinitionRegistry。当Spring容器启动时,会执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法。大概意思就是beanDefinition加载完成后,beanDefinition是Post-processing的,可以在这里调整IOC容器中的beanDefinition,从而干扰后续bean的初始化。公共类Demo1{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext();MyBeanDefinitionRegistryPostProcessorbeanDefinitionRegistryPostProcessor=newMyBeanDefinitionRegistryPostProcessor();applicationContext.addBeanFactoryPostProcessor(beanDefinitionRegistryPostProcessor);applicationContext.refresh();Personbean=applicationContext.getBean(Person.class);System.out.println(bean);}}类MyBeanDefinitionRegistryPostProcessor实现BeanDefinitionRegistryPostProcessor{@OverridepublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry)throwsBeansException{AbstractBeanDefinitionbeanDefinition=BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();registry.registerBeanDefinition("person",beanDefinition);}@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{}}在上面的代码中,我们在beanDefinitionRegistry中手动注册了person的BeanDefinition,最终成功的将person添加到了applicationContext中。