您的位置:首页 > 编程语言 > Java开发

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

2016-08-26 08:44 776 查看


 

【视频&交流平台】

à SpringBoot视频
http://study.163.com/course/introduction.htm?courseId=1004329008&utm_campaign=commission&utm_source=400000000155061&utm_medium=share
à SpringCloud视频
http://study.163.com/course/introduction.htm?courseId=1004638001&utm_campaign=commission&utm_source=400000000155061&utm_medium=share
à Spring
Boot源码
https://gitee.com/happyangellxq520/spring-boot
à Spring
Boot交流平台
http://412887952-qq-com.iteye.com/blog/2321532
 

 
 
  
已经好久没有讲一些基础的知识了,这一小节来点简单的,这也是为下节的在Spring多数Boot中使用多数据源做准备。

从Spring 3.0开始,增加了一种新的途径来配置Bean Definition,这就是通过Java Code配置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);
        }
    }
 
}
 

【Spring Boot 系列视频】

视频&交流平台:

à Spring Boot网易云课堂视频
http://study.163.com/course/introduction.htm?courseId=1004329008
à Spring Boot交流平台
http://412887952-qq-com.iteye.com/blog/2321532
 

网易云课堂视频最新更新

第十一章 Spring Boot 日志

1、spring boot日志—理论

2、Spring Boot日志-logback

3、Spring Boot日志-log4j2

第十二章 Spring Boot 知识点2

1、spring boot 服务配置和部署

2、Spring Boot 定制URL匹配规则

 
 
历史章节:

 

第一章 快速开始

1、Spring Boot之Hello World

2、Spring Boot之Hello World访问404

 

第二章 Spring Boot之JSON

1、spring boot返回json数据

2、Spring Boot完美使用FastJson解析JSON数据

 

第三章 Spring Boot热部署

1、Spring Boot热部署(springloader)

2、springboot + devtools(热部署)

 

第四章 Spring Boot数据库

1、Spring Boot JPA/Hibernate/Spring Data概念

2、Spring Boot JPA-Hibernate

3、Spring Boot Spring Data JPA介绍

4、Spring Boot JdbcTemplate

5、Spring Boot集成MyBatis

 

第五章 web开发

1、全局异常捕捉

2、配置server信息

3、spring boot使用thymeleaf

4、Spring Boot 使用freemarker

5、Spring Boot添加JSP支持

 

第六章 定时任务

1、Spring Boot定时任务

2、Spring Boot 定时任务升级篇(动态修改cron参数)

3、Spring Boot 定时任务升级篇(动态添加修改删除定时任务)

4、Spring Boot 定时任务升级篇(集群/分布式下的定时任务说明)

5、Spring Boot Quartz介绍

6、Spring Boot Quartz在Java Project中使用

7、Spring Boot 集成Quartz普通使用

8、Spring Boot 集成Quartz升级版

9、Spring Boot 集成Quartz二次升级版

10、Spring Boot 集成Quartz-Job如何自动注入Spring容器托管的对象

 

第七章 Spring Boot MyBatis升级篇

1、Spring Boot MyBatis升级篇-注解

2、Spring Boot MyBatis升级篇-注解-自增ID

3、Spring Boot MyBatis升级篇-注解-增删改查

4、Spring Boot MyBatis升级篇-注解-分页查询

5、Spring Boot MyBatis升级篇-注解-分页PageHelper不生效

6、Spring Boot MyBatis升级篇-注解- mybatic insert异常:BindingException: Parameter 'name' not found

7、Spring Boot MyBatis升级篇-注解- #和$符号特别篇

8、Spring Boot MyBatis升级篇-注解-@Result

9、Spring Boot MyBatis升级篇-注解-动态SQL(if test)-方案一:<script>

10、Spring Boot MyBatis升级篇-注解-动态SQL(if test)-方案二:@Provider

11、Spring Boot MyBatis升级篇-注解-动态SQL-参数问题

12、Spring Boot MyBatis升级篇-注解-特别篇:@MapperScan和@Mapper

13、Spring Boot MyBatis升级篇-XML

14、Spring Boot MyBatis升级篇-XML-自增ID

15、Spring Boot MyBatis升级篇-XML-增删改查

16、Spring Boot MyBatis升级篇-XML-分页查询

17、Spring Boot MyBatis升级篇-XML-分页PageHelper不生效

18、Spring Boot MyBatis升级篇-XML-动态SQL(if test)

19、Spring Boot MyBatis升级篇-XML-注解-初尝试

20、Spring Boot MyBatis升级篇- pagehelper替换为pagehelper-spring-boot-starter

 

第八章 Spring Boot 知识点1

1、Spring Boot 拦截器HandlerInterceptor

2、Spring Boot启动加载数据CommandLineRunner

3、Spring Boot环境变量读取和属性对象的绑定

4、Spring Boot使用自定义的properties

5、Spring Boot使用自定义的properties

6、Spring Boot使用@SpringBootApplication

7、Spring Boot 监控和管理生产环境

 

第十章 Spring Boot 打包部署

1、Spring Boot打包部署((提供Linux的sh文件))

 

第十一章 Spring Boot 日志

1、spring boot日志—理论

2、Spring Boot日志-logback

 
3、Spring Boot日志-log4j2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐