关键词:
欢迎访问我的GitHub
- 本章是《spring4.1.8扩展实战》系列的第六篇,目标是学习如何通过自己写代码的方式,向spring容器中注册bean;
关于注册bean到容器
- 我们开发的类,如果想注册到spring容器,让spring来完成实例化,常用方式如下:
- xml中通过bean节点来配置;
- 使用@Service、@Controller、@Conponent等注解;
- 其实,除了以上方式,spring还支持我们通过代码来将指定的类注册到spring容器中,也就是今天我们要实践的主要内容,接下来就从spring源码开始,先学习源码再动手实战;
本章概要
- 本章由以下几部分组成:
- 了解BeanDefinitionRegistryPostProcessor接口;
- 分析spring容器如何使用BeanDefinitionRegistryPostProcessor接口;
- 实战,开发BeanDefinitionRegistryPostProcessor接口的实现类,验证通过代码注册bean的功能;
了解BeanDefinitionRegistryPostProcessor接口
-
实现注册bean功能的关键是BeanDefinitionRegistryPostProcessor接口,来看看这接口的继承关系,如下图:
- BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,关于BeanFactoryPostProcessor我们在上一章《spring4.1.8扩展实战之五:改变bean的定义(BeanFactoryPostProcessor接口)》已做了详细的分析和实战,知道BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:
-
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:
该方法的实现中,主要用来对bean定义做一些改变,这些在上一章《spring4.1.8扩展实战之五:改变bean的定义(BeanFactoryPostProcessor接口)》有详细说明; -
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:
该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,看看这个参数能带给我们什么能力: - 从上图可以看到,为了能让我们通过代码将bean注册到spring环境,BeanDefinitionRegistry提供了丰富的方法来操作bean定义,判断、注册、反注册等方法都准备好了,我们在编写postProcessBeanDefinitionRegistry方法的内容时,就能直接使用入参registry的这些方法来完成判断和注册、反注册等操作;
分析spring容器如何使用BeanDefinitionRegistryPostProcessor接口
- 来看看BeanDefinitionRegistryPostProcessor接口的实现类,是在哪里被spring容器使用的:
- 如下图所示,红框中的invokeBeanFactoryPostProcessors方法用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义:
- 打开invokeBeanFactoryPostProcessors方法,如下所示,实际操作是委托PostProcessorRegistrationDelegate去完成的:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
- 继续看PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法,该方法内容太丰富,我们只看重点,第一个重点如下图红框所示,==当前的beanFactory是否实现了接口BeanDefinitionRegistry==:
- 为了搞清楚这个问题,我们应该看看当前beanFactory的继承和实现,以springboot中的应用为例,当前beanFactory的类型是DefaultListableBeanFactory,来看看它的类图:
- 从上图红框可见,beanFactory实现了BeanDefinitionRegistry接口,因此我们的关注点是if条件满足后的执行逻辑;
- 继续看PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法,以下片段就是操作BeanDefinitionRegistryPostProcessor的核心逻辑:
boolean reiterate = true;
while (reiterate)
reiterate = false;
//查出所有实现了BeanDefinitionRegistryPostProcessor接口的bean名称
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames)
//前面的逻辑中,已经对实现了PriorityOrdered和Ordered的bean都处理过了,因此通过processedBeans过滤,processedBeans中没有的才会在此处理
if (!processedBeans.contains(ppName))
//根据名称和类型获取bean
BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
//把已经调用过postProcessBeanDefinitionRegistry方法的bean全部放在registryPostProcessors中
registryPostProcessors.add(pp);
//把已经调用过postProcessBeanDefinitionRegistry方法的bean的名称全部放在processedBeans中
processedBeans.add(ppName);
//执行此bean的postProcessBeanDefinitionRegistry方法
pp.postProcessBeanDefinitionRegistry(registry);
//改变退出while的条件
reiterate = true;
//registryPostProcessors中保存了所有执行过postProcessBeanDefinitionRegistry方法的bean,
//现在再来执行这些bean的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
//regularPostProcessors中保存的是所有入参中带来的BeanFactoryPostProcessor实现类,并且这里面已经剔除了BeanDefinitionRegistryPostProcessor的实现类,现在要让这些bean执行postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
-
如上述代码所示,所有实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都会调用,然后再调用其postProcessBeanFactory方法,这样一来,我们如果自定义了BeanDefinitionRegistryPostProcessor接口的实现类,那么我们开发的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都会被执行一次;
- 到这里,我们的源码学习部分就完成了,接下来看开始实战吧;
实战,开发BeanDefinitionRegistryPostProcessor接口的实现类
- 本次实战的内容是创建一个springboot工程,在里面自定义一个BeanDefinitionRegistryPostProcessor接口的实现类,如果您不想敲代码,也可以去github下载源码,地址和链接信息如下表所示:
名称 | 链接 | 备注 |
---|---|---|
项目主页 | https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 |
git仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https协议 |
git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |
- 这个git项目中有多个文件夹,本章源码在文件夹customizebeandefinitionregistrypostprocessor下,如下图红框所示:
- 接下来开始实战吧:
- 基于maven创建一个springboot的web工程,名为customizebeandefinitionregistrypostprocessor,pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bolingcavalry</groupId>
<artifactId>customizebeandefinitionregistrypostprocessor</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>customizebeandefinitionregistrypostprocessor</name>
<description>Demo project for customize BeanDefinitionRegistryPostProcessor</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.15.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 定义一个服务接口CalculateService:
package com.bolingcavalry.customizebeandefinitionregistrypostprocessor.service;
public interface CalculateService
/**
* 整数加法
* @param a
* @param b
* @return
*/
int add(int a, int b);
/**
* 返回当前实现类的描述信息
* @return
*/
String getServiceDesc();
- 创建CalculateService接口的实现类CalculateServiceImpl,==注意,不要将其声明为spring的bean==:
package com.bolingcavalry.customizebeandefinitionregistrypostprocessor.service.impl;
import com.bolingcavalry.customizebeandefinitionregistrypostprocessor.service.CalculateService;
public class CalculateServiceImpl implements CalculateService
private String desc = "desc from class";
public void setDesc(String desc)
this.desc = desc;
@Override
public int add(int a, int b)
return a + b;
@Override
public String getServiceDesc()
return desc;
- 创建工具类Utils,里面是些工具方法,例如在日志中打印出当前线程的执行堆栈:
package com.bolingcavalry.customizebeandefinitionregistrypostprocessor.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description : 提供一些常用的工具方法
* @Author : zq2599@gmail.com
* @Date : 2018-08-14 05:51
*/
public class Utils
private static final Logger logger = LoggerFactory.getLogger(Utils.class);
/**
* 打印当前线程堆栈信息
* @param prefix
*/
public static void printTrack(String prefix)
StackTraceElement[] st = Thread.currentThread().getStackTrace();
if(null==st)
logger.info("invalid stack");
return;
StringBuffer sbf =new StringBuffer();
for(StackTraceElement e:st)
if(sbf.length()>0)
sbf.append(" <- ");
sbf.append(System.getProperty("line.separator"));
sbf.append(java.text.MessageFormat.format("0.1() 2"
,e.getClassName()
,e.getMethodName()
,e.getLineNumber()));
logger.info(prefix
+ "\\n************************************************************\\n"
+ sbf.toString()
+ "\\n************************************************************");
- 创建Controller类,用于验证我们通过代码注册的bean,==注意要给成员变量calculateService添加注解@Autowired(required = false),否则有的IDEAL上会有红叉提示==:
package com.bolingcavalry.customizebeandefinitionregistrypostprocessor.controller;
import com.bolingcavalry.customizebeandefinitionregistrypostprocessor.service.CalculateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController
@Autowired(required = false)
CalculateService calculateService;
@GetMapping("/add/a/b")
public String add(@PathVariable("a") int a, @PathVariable("b") int b)
return "add result : " + calculateService.add(a, b) + ", from [" + calculateService.getServiceDesc() + "]";
- 创建BeanDefinitionRegistryPostProcessor的实现类CustomizeBeanDefinitionRegistryPostProcessor:
@Component
public class CustomizeBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException
//打印当前堆栈信息
Utils.printTrack("execute postProcessBeanDefinitionRegistry");
//创建一个bean的定义类的对象,bean类型是CalculateServiceImpl
RootBeanDefinition helloBean = new RootBeanDefinition(CalculateServiceImpl.class);
//bean的定义注册到spring环境
beanDefinitionRegistry.registerBeanDefinition("calculateService", helloBean);
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException
//打印当前堆栈信息
Utils.printTrack("execute postProcessBeanFactory");
-
上面CustomizeBeanDefinitionRegistryPostProcessor就是我们扩展出来的BeanDefinitionRegistryPostProcessor实现类,用来将CalculateServiceImpl注册到spring容器,名称为calculateService;
- 启动类CustomizebeandefinitionregistrypostprocessorApplication:
package com.bolingcavalry.customizebeandefinitionregistrypostprocessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomizebeandefinitionregistrypostprocessorApplication
public static void main(String[] args)
SpringApplication.run(CustomizebeandefinitionregistrypostprocessorApplication.class, args);
- 启动应用,在启动日志中可以看到CustomizeBeanDefinitionRegistryPostProcessor的方法被调用时的堆栈情况:
2018-08-30 18:55:40.323 INFO 14880 --- [ main] c.b.c.util.Utils : execute postProcessBeanDefinitionRegistry
************************************************************
java.lang.Thread.getStackTrace() 1,556 <-
com.bolingcavalry.customizebeandefinitionregistrypostprocessor.util.Utils.printTrack() 20 <-
com.bolingcavalry.customizebeandefinitionregistrypostprocessor.registrypostprocessor.CustomizeBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry() 21 <-
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors() 272 <-
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 122 <-
org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors() 687 <-
org.springframework.context.support.AbstractApplicationContext.refresh() 525 <-
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh() 122 <-
org.springframework.boot.SpringApplication.refresh() 693 <-
org.springframework.boot.SpringApplication.refreshContext() 360 <-
org.springframework.boot.SpringApplication.run() 303 <-
org.springframework.boot.SpringApplication.run() 1,118 <-
org.springframework.boot.SpringApplication.run() 1,107 <-
com.bolingcavalry.customizebeandefinitionregistrypostprocessor.CustomizebeandefinitionregistrypostprocessorApplication.main() 10
************************************************************
2018-08-30 18:55:40.542 INFO 14880 --- [ main] c.b.c.util.Utils : execute postProcessBeanFactory
************************************************************
java.lang.Thread.getStackTrace() 1,556 <-
com.bolingcavalry.customizebeandefinitionregistrypostprocessor.util.Utils.printTrack() 20 <-
com.bolingcavalry.customizebeandefinitionregistrypostprocessor.registrypostprocessor.CustomizeBeanDefinitionRegistryPostProcessor.postProcessBeanFactory() 31 <-
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 283 <-
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 127 <-
org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors() 687 <-
org.springframework.context.support.AbstractApplicationContext.refresh() 525 <-
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh() 122 <-
org.springframework.boot.SpringApplication.refresh() 693 <-
org.springframework.boot.SpringApplication.refreshContext() 360 <-
org.springframework.boot.SpringApplication.run() 303 <-
org.springframework.boot.SpringApplication.run() 1,118 <-
org.springframework.boot.SpringApplication.run() 1,107 <-
com.bolingcavalry.customizebeandefinitionregistrypostprocessor.CustomizebeandefinitionregistrypostprocessorApplication.main() 10
************************************************************
- 去掉CustomizeBeanDefinitionRegistryPostProcessor的注释@Component,重启应用,再去访问http://localhost:8080/add/1/2,可以看到网页提示错误如下图:
- 看后台日志,是因为calculateService这个bean为空,导致HelloController在响应请求的时候出现了空指针异常,这也再次证明了CustomizeBeanDefinitionRegistryPostProcessor的注册操作是有效的:
2018-08-30 19:00:01.186 ERROR 2760 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at com.bolingcavalry.customizebeandefinitionregistrypostprocessor.controller.HelloController.add(HelloController.java:18) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471) [tomcat-embed-core-8.5.32.jar:8.5.32]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.32.jar:8.5.32]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.32.jar:8.5.32]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]
- 至此,自定义bean注册的实战就结束了,其实除了注册bean,我们还能利用BeanDefinitionRegistry这个入参做些其他事情,例如查找bean,反注册bean等,帮助我们实现一些bean操作的业务需求;
欢迎关注51CTO博客:程序员欣宸
spring4.1.8扩展实战之八:import注解(代码片段)
欢迎访问我的GitHub在spring框架下做开发时,@Import是常见的注解,可以用来动态创建bean,今天我们先从源码分析原理,再用实战来验证Import的作用;文章概览本章由以下几部分组成:从Enable前缀的注解谈起,揭示常见的Enable注解... 查看详情
spring4.1.8扩展实战之四:感知spring容器变化(smartlifecycle接口)(代码片段)
欢迎访问我的GitHub本篇概览本章是《spring4.1.8扩展实战》的第四篇,如果业务上需要在spring容器启动和关闭的时候做一些操作,可以自定义SmartLifecycle接口的实现类来扩展,本章我们通过先分析再实战的方法,来掌握这种扩展方... 查看详情
spring4.1.8扩展实战之三:广播与监听
欢迎访问我的GitHub提到广播与监听,我们常常会想到RabbitMQ、Kafka等消息中间件,这些常用于分布式系统中多个应用之间,有时候应用自身内部也有广播和监听的需求(例如某个核心数据发生变化后,有些业务模块希望立即被感... 查看详情
spring4.1.8扩展实战之一:自定义环境变量验证
欢迎访问我的GitHub关于扩展在之前学习spring环境初始化源码的过程中,见到有些地方能通过子类来实现自定义扩展,从本章开始,我们来逐个实践这些扩展,除了加深对spring的理解,有的扩展也能解决一些通用的问题;文中涉及... 查看详情
spring-beandefinitionregistrypostprocessor扩展接口动态注册bean(代码片段)
文章目录Preorg.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor接口的继承关系BeanDefinitionRegistryPostProcessor在Spring中的应用示例注册Bean多数据源实现PreSpringBoot-扩展接口一览org.springframework.beans.fac 查看详情
spring-beandefinitionregistrypostprocessor扩展接口动态注册bean(代码片段)
...cessor在Spring中的应用示例注册Bean多数据源实现PreSpringBoot-扩展接口一览org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessorpackageorg.springframework.beans.factory.support;importorg.springframework.beans.BeansException;importorg.springframework.beans.fa... 查看详情
client-go实战之六:时隔两年,刷新版本继续实战(代码片段)
...码):https://github.com/zq2599/blog_demos系列文章链接client-go实战之一:准备工作client-go实战之二:RESTClientclient-go实战之三:Clientsetclient-go实战之四:dynamicClientcli 查看详情
java与es8实战之六:用json创建请求对象(比builderpattern更加直观简洁)(代码片段)
...ff1a;https://github.com/zq2599/blog_demos本篇概览本文是《java与es8实战》系列的第六篇,经过前面的实战,咱们初步掌握了一些Java对ES的基本操作,通过发送请求对象(例如CreateIndexResponse)到ES服务端, 查看详情
java与es8实战之六:用json创建请求对象(比builderpattern更加直观简洁)(代码片段)
...ff1a;https://github.com/zq2599/blog_demos本篇概览本文是《java与es8实战》系列的第六篇,经过前面的实战,咱们初步掌握了一些Java对ES的基本操作,通过发送请求对象(例如CreateIndexResponse)到ES服务端, 查看详情
bert-多标签文本分类实战之六——数据加载与模型代码(代码片段)
·请参考本系列目录:【BERT-多标签文本分类实战】之一——实战项目总览·下载本实战项目资源:>=点击此处=< 前5篇文章中,介绍了实战项目的前置知识,下面正式介绍项目的代码。本项目主要分为... 查看详情
bert-多标签文本分类实战之六——数据加载与模型代码(代码片段)
·请参考本系列目录:【BERT-多标签文本分类实战】之一——实战项目总览·下载本实战项目资源:>=点击此处=< 前5篇文章中,介绍了实战项目的前置知识,下面正式介绍项目的代码。本项目主要分为... 查看详情
bert-多标签文本分类实战之六——数据加载与模型代码(代码片段)
·请参考本系列目录:【BERT-多标签文本分类实战】之一——实战项目总览·下载本实战项目资源:>=点击此处=< 前5篇文章中,介绍了实战项目的前置知识,下面正式介绍项目的代码。本项目主要分为... 查看详情
springbean生命周期----来自spring实战总结
1、Spring对bean进行实例化2、Spring将值和bean的引用注入到bean对应的属性中(比如说注入到被依赖的bean的方法中或属性里)3、如果bean实现了BeanNameAware接口,将会将bean的Id传入setBeanName()方法中4、如果bean实现了BeanFactoryAware接口,将会设... 查看详情
javasocket实战之六使用nio包实现socket通信(代码片段)
...地址:http://blog.csdn.net/kongxx/article/details/7288896JavaSocket实战之一单线程通信JavaSocket实战之二多线程通信JavaSocket实战之三传输对象JavaSocket实战之四传输压缩对象JavaSocket实战之五使用加密协议传输对象前面几篇文章介绍了使用ja... 查看详情
java扩展nginx之六:两大filter
...):https://github.com/zq2599/blog_demos本篇概览本文是《Java扩展Nginx》系列的第六篇,前文的五大handler形成了nginx-clojure开发的基本框架,初步评估已经可以支撑简单的需求开发了,但nginx-clojure并未止步于 查看详情
<spring实战>3:最小化springxml配置
1自动装配Bean属性1.14种类型的自动装配byName:把与Bean的属性具有相同名字或ID的其他Bean自动装配到Bean的对应属性中byType:把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中constructor:把与Bean的构造器入参具有相... 查看详情
vmware后台下citrixxendesktop7.6实战篇之六ddc服务安装站点配置
1、 Xendesktop7.6服務安裝1.1插入XenDesktop7_6光盘并点击确定安裝.net3.5650)this.width=650;"src="http://s5.51cto.com/wyfs02/M00/87/6E/wKiom1ffioSScxNOAAAmZamG9Gc108.jpg-wh 查看详情
dl4j实战之六:图形化展示训练过程(代码片段)
...):https://github.com/zq2599/blog_demos本篇概览本篇是《DL4J实战》系列的第六篇,咱们继续夯实基本功,这次学习的是如何更加形象完整的展示训练过程:图形化页面,效果如下图所示:接下来选择一个已有的子... 查看详情