41. Spring Boot 使用Java代码创建Bean并注册到Spring中【从零开始学Spring Boot】

来源:互联网 发布:32位与62位的区别 知乎 编辑:程序博客网 时间:2024/05/24 07:24
 已经好久没有讲一些基础的知识了,这一小节来点简单的,这也是为下节的在spring多数Boot中使用多数据源做准备。

从Spring 3.0开始,增加了一种新的途径来配置Bean Definition,这就是通过JavaCode配置Bean Definition。

       与XML和Annotation两种配置方式不同点在于:

       前两种方式XML和Annotation的配置方式为预定义方式,即开发人员通过XML文件或者Annotation预定义配置Bean的各种属性后,启动Spring容器,Spring容器会首先解析这些配置属性,生成对应的Bean Definition,装入到DefaultListtableBeanFactory对象的属性容器中,以此同时,Spring框架也会定义内部使用的Bean定义,如Bean名为:org.springframework.context.annotation.internalConfigurationAnnotationProcessor”的 ConfigurationClassPostProcessor 定义。而后此刻不会做任何Bean Definition的解析动作,Spring框架会根据前两种配置,过滤出BeanDefinitionRegistryPostProcessor 类型的Bean定义,并通过Spring框架生成对应的Bean对象(如 ConfigurationClassPostProcessor 实例)。。结合Spring 上下文源码可知这个对象是一个 processor 类型工具类,Spring 容器会在实例化开发人员所定义的 Bean 前先调用该 processor 的 postProcessBeanDefinitionRegistry(…) 方法。此处实现基于 Java Code 配置Bean Definition的处理。

基于 Java Code 解析 Bean 的顺序图

  

       基于 Java Code的配置方式,其执行原理不同于前两种。它是在 Spring 框架已经解析了基于 XML 和 Annotation 配置后,通过加入BeanDefinitionRegistryPostProcessor 类型的 processor 来处理配置信息,让开发人员通过 Java 编程方式定义一个 Java 对象。其优点在于可以将配置信息集中在一定数量的 Java 对象中,同时通过 Java 编程方式,比基于 Annotation 方式具有更高的灵活性。并且该配置方式给开发人员提供了一种非常好的范例来增加用户自定义的解析工具类。其主要缺点在于与 Java 代码结合紧密,配置信息的改变需要重新编译 Java 代码,另外这是一种新引入的解析方式,需要一定的学习成本。

 

提及一点的就是,Spring框架有3个主要的Hook类,分别是:

org.springframework.context.ApplicationContextAware 
它的setApplicationContext 方法将在Spring启动之前第一个被调用。我们用来同时启动Jdon框架。

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor 
它的postProcessBeanDefinitionRegistry 和 postProcessBeanFactory 方法是第二和第三被调用,它们在Bean初始化创建之前启动,如果Spring的bean需要的其他第三方中的组件,我们在这里将其注入给Spring。

org.springframework.context.ApplicationListener 
用于在初始化完成后做一些事情,当Spring所有XML或元注解的Bean都启动被创建成功了,这时会调用它的唯一方法onApplicationEvent。

 

下面我们来完成一个,自己通过java代码创建bean,并注册为Spring管理。 

本例中,我们创建一个接口,然后创建该接口的2个实现类,分别命名不同的名字,然后在需要注入的地方使用@Qualifier 指定注入对应的实例。

 

接口com.kfit.demo.Shanhy.java

package com.kfit.demo;

 

publicinterface Shanhy {

    

     publicvoid dispaly();

    

}

 

实现类com.kfit.demo.ShanhyA.java

package com.kfit.demo;

 

publicclassShanhyA implements Shanhy{

 

     @Override

     publicvoid dispaly() {

         System.out.println("ShanhyA.dispaly()");

     }

}

 

 

实现类com.kfit.ShanhyB.java

package com.kfit.demo;

 

publicclass ShanhyBimplements Shanhy {

 

     @Override

     publicvoid dispaly() {

         System.out.println("ShanhyB.dispaly()");

     }

 

}

 

 

定义接口BeanDefinitionRegistryPostProcessor的实现:

com.kfit.config.

package com.kfit.config;

 

importorg.springframework.beans.BeansException;

importorg.springframework.beans.MutablePropertyValues;

importorg.springframework.beans.factory.annotation.AnnotatedBeanDefinition;

importorg.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;

importorg.springframework.beans.factory.config.BeanDefinition;

importorg.springframework.beans.factory.config.BeanDefinitionHolder;

importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;

importorg.springframework.beans.factory.support.BeanDefinitionRegistry;

importorg.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

import org.springframework.beans.factory.support.BeanNameGenerator;

importorg.springframework.context.annotation.AnnotationBeanNameGenerator;

importorg.springframework.context.annotation.Configuration;

 

import com.kfit.demo.ShanhyA;

import com.kfit.demo.ShanhyB;

 

/**

 *实现自己实例化bean并注册为Spring管理

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@Configuration

publicclassMyBeanDefinitionRegistryPostProcessorimplementsBeanDefinitionRegistryPostProcessor {

      

       //bean 的名称生成器.

        private BeanNameGeneratorbeanNameGenerator =newAnnotationBeanNameGenerator();

 

      

       @Override

       publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throws BeansException {

              System.out.println("MyBeanDefinitionRegistryPostProcessor.postProcessBeanFactory()");

             

                           

       }

 

       /**

        *先执行:postProcessBeanDefinitionRegistry()方法,

        *在执行:postProcessBeanFactory()方法。

        *

        */

       @Override

       publicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry)throws BeansException{

              System.out.println("MyBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()");

             

              /*

               *在这里可以注入bean.

               */

              registerBean(registry,"shanyA", ShanhyA.class);

              registerBean(registry,"shanyB", ShanhyB.class);

       }

      

       /**

        *提供公共的注册方法。

        *@param beanDefinitionRegistry

        *@param name

        *@param beanClass

        */

       privatevoidregisterBean(BeanDefinitionRegistryregistry,Stringname,Class<?>beanClass){

              AnnotatedBeanDefinitionannotatedBeanDefinition  =new AnnotatedGenericBeanDefinition(beanClass);

                //可以自动生成name

              StringbeanName = (name !=null?name:this.beanNameGenerator.generateBeanName(annotatedBeanDefinition,registry));

              //bean注册的holer类.

              BeanDefinitionHolderbeanDefinitionHolder =newBeanDefinitionHolder(annotatedBeanDefinition,beanName);

              //使用bean注册工具类进行注册.

              BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder,registry);

       }

      

}

这个类里的代码比较多,在这里简单的介绍下:方法postProcessBeanDefinitionRegistry()是用来注册bean的;而具体注册的代码比较是通用的,我们定义一个私有的方法进行注册。

postProcessBeanFactory()是bean配置的工厂方法,在这个方法中可以获取到我们所有在postProcessBeanDefinitionRegistry方法中注册的所有bean,在这里我们可以进行属性的设置等操作。

//这里可以设置属性,例如

              BeanDefinitionbeanDefinition =beanFactory.getBeanDefinition("dataSourceA");

              MutablePropertyValuesmutablePropertyValues =beanDefinition.getPropertyValues();

              //加入属性.

              mutablePropertyValues.addPropertyValue("driverClassName","com.MySQL.jdbc.Driver");

              mutablePropertyValues.addPropertyValue("url","jdbc:mysql://localhost:3306/test");

              mutablePropertyValues.addPropertyValue("username","root");

              mutablePropertyValues.addPropertyValue("password","123456");

 

 

 

测试代码:

以直接注入我们的对象,对于同样接口的我们需要指定name

package com.kfit.config;

 

import org.kfit.service.HelloService;

importorg.springframework.beans.factory.annotation.Qualifier;

importorg.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

 

import com.kfit.demo.Shanhy;

 

@Configuration

publicclass MyConfig {

      

       /**

        * 这里只是测试使用,没有实际的意义.

        */

       @Bean(name="testHelloService")

       public HelloServicefilterRegistrationBean(@Qualifier("shanhyB") Shanhyshanhy){

              HelloServicehelloService =new HelloService();

        shanhy.display();

        // 其它处理代码.

        returnhelloService;

       }

      

}

 

使用@Resource 或者 @Autowired并指定@Qualifier 也可以:

 

 

package com.kfit.controller;

 

import javax.annotation.Resource;

 

import org.springframework.beans.factory.annotation.Autowired;

importorg.springframework.beans.factory.annotation.Qualifier;

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RestController;

 

import com.kfit.demo.Shanhy;

 

/**

 *

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@RestController

publicclass HelloController {

 

       @Resource(name = "shanhyA")

       private ShanhyshanhyA;

 

       @Autowired

       @Qualifier("shanhyB")

       private ShanhyshanhyB;

 

       @RequestMapping("/test")

       public String test(){

              shanhyA.display();

              shanhyB.display();

              return"test";

       }

}

访问:http://127.0.0.1:8080/test查看控制台的打印信息。

在源代码中由于代码有此系列教程别的章节的代码,请自行忽略阅读,给大家造成的不变请谅解。

 

这里有点经验要说一下,在 @Configuration 中,不能使用注入属性的方式注入,只能通过参数的方式注入,其原因就是@Configuration的类一开始便被加载,此时你想进行属性注入,需要注入的bean对象都还不存在。

 

下面的代码片段也可以注册Bean,比较简单:

@Configuration

@Import(Registrar.class)

publicclassTestConfig {

 

}

 

classRegistrarimplementsImportBeanDefinitionRegistrar {

 

   privatestaticfinal String BEAN_NAME ="myTestBean";

 

    @Override

   publicvoid registerBeanDefinitions(AnnotationMetadataimportingClassMetadata, BeanDefinitionRegistry registry) {

 

       if(!registry.containsBeanDefinition(BEAN_NAME)) {

           GenericBeanDefinition beanDefinition =newGenericBeanDefinition();

           beanDefinition.setBeanClass(ExamplePostProcessor.class);

           beanDefinition.setSynthetic(true);

           registry.registerBeanDefinition(BEAN_NAME, beanDefinition);

        }

    }

 

}

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 征信大数据黑了怎么办 楼层之间有洞怎么办 跨大类商品疑点怎么办? 出口跨大类商品怎么办 淘宝开店显示已有店怎么办 店铺被恶意骚扰怎么办 淘宝红包过期了怎么办 手机微信被盗怎么办 手机不支持支付宝计步怎么办 学付宝fid未启用怎么办 被恶意冒名举报怎么办 淘宝鞋子发重复怎么办 爆款不小心下架怎么办 淘宝店铺没订单怎么办 总是重复看东西怎么办 运费付重复了怎么办 广州羊城通坏了怎么办 商家搞虚假活动怎么办 网购联系不上卖怎么办 发快递没有单号怎么办 健身房卡丢了怎么办 健身房合同丢了怎么办 精子数量不达标怎么办 vivo黑屏振动怎么办呀! vivox5开机定屏怎么办 wlan小米手机打不开怎么办 手机wifi开不了怎么办 厨房橱柜坏了怎么办 二手房东转三手办营业执照怎么办 手机不能计步怎么办 媒体储存删除了怎么办 设备储存器空间不足怎么办 华为铃声删除了怎么办 华为手机内存小怎么办 手机电话没声音怎么办 oppo媒体声音小怎么办 手机视频音量小怎么办 苹果6内存不够怎么办 wiwox7忘记密码了怎么办 wiwo手机声音小怎么办 海信手机声音小怎么办