# dubbo-simple **Repository Path**: lanicc/dubbo-simple ## Basic Information - **Project Name**: dubbo-simple - **Description**: dubbo是如何与Spring整合的呢? - **Primary Language**: Java - **License**: WTFPL - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-05-15 - **Last Updated**: 2021-07-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README dubbo的service和reference是怎么实现的 # dubbo是如何实现Service和Reference的? 使用dubbo,你是否想过dubbo是如何通过Service和Reference注解实现调用的呢? ## Service实现猜想 如果大致想想,感觉dubbo对Service的处理似乎不需要很复杂,只需要在需要调用时能够找得到这个bean就可以了,完全可以使用Spring的Service注解,或者是自定义一个继承了Spring Service的注解,就可以完成被标注的类,既可以作为Spring Bean又可以被dubbo作为服务引用。 我以为dubbo的Service注解是这样的 ```java @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @org.springframework.stereotype.Service public @interface Service { } ``` 可是点进去看了一下dubbo的Service源码,却是这样的 ```java @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Inherited public @interface Service { Class interfaceClass() default void.class; String interfaceName() default ""; String version() default ""; ... } ``` 很明显dubbo并不是通过继承spring的Service实现的。 那dubbo是怎样把使用了Service注解的类注册到Spring容器呢? ## Reference实现猜想 Refrence是怎么实现的呢,一般来说被Reference注解标注的都是接口,dubbo是怎么注入Reference的呢?扫描Spring Bean然后再遍历BeanClass的Field判断有没有被Reference注解标注,如果被标注了,再注入?这种想法我们还有待验证。 但如果是这样,那何时注入呢?我对Spring的理解不是很深刻,当时第一反应想到的就是通过实现Lifecycle或者是CommandLineRunner接口都可以实现在Spring启动后扫描Spring的Bean,然后再实现我上面的那个想法。 ```java @Reference private HelloService helloService; ``` 比如上面这个helloService,当我们调用其方法的时候,dubbo其实是帮我们做了远程调用,调用的是别的服务,这个又是怎么实现的呢。 # 解惑 ## 官方文档 去看看官方文档 [官方文档]: http://dubbo.apache.org/zh-cn/docs/dev/implementation.html 怎么说的吧 ![image-20200514205910603](dubbo.assets/image-20200514205910603.png) 点击[链接](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/xsd-configuration.html)看一下 ![image-20200515184828571](dubbo.assets/image-20200515184828571.png) 一脸英文,不过大致看看,这一章节的主要内容也就是在介绍基于xml的配置,我觉得其实重点不在这一章节,而在下一节[Extensible XML authoring](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/xml-custom.html),大概意思就是可拓展的xml编写。 ![image-20200515185442626](dubbo.assets/image-20200515185442626.png) 看懂这段,这段是重点。 大致意思就是说,从2.0版开始,Spring引入了一种机制,该机制可对基于Spring的基本XML格式进行基于架构的扩展,以定义和配置bean。本节专门介绍如何编写自己的自定义XML bean定义解析器并将这些解析器集成到Spring IoC容器中。 怎么使用这个基于XML定义和配置bean的机制呢?文档给出了使用步骤。 - 编写XML schema - 创建一个NamespaceHandler的实现类 - 创建一个或多个BeanDefinitionParser的实现类 - 注册到Spring 其实如果继续看dubbo的官方文档,也有提到NamespaceHandler ![image-1](dubbo.assets/image-20200514200050955.png) 为了方便,去github上弄一份源码下来,打开dubbo项目, ![image-20200514210546052](dubbo.assets/image-20200514210546052.png) 打开org.apache.dubbo.config.spring.schema.DubboNamespaceHandler ![image-20200514203739234](dubbo.assets/image-20200514203739234.png) 猛地一看不知道该怎么分析,因为根本就不知道这个类是干嘛的?就是为了解析dubbo命名空间的标签的。 ```java //就是注册一个provider标签()的解析器 registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true)); ``` DubboBeanDefinitionParser的parse方法就是具体的解析过程 ![image-20200514211739626](dubbo.assets/image-20200514211739626.png) ## 造轮子 ### 解析标签 我又新建了一个项目,准备按照dubbo的启动过程自己手写一个简单的实现 直接使用Spring Initializer创建一个Spring Boot项目,拷贝dubbo项目的META-INF文件夹到resources目录下,项目结构如下图 ![image-20200514212119209](dubbo.assets/image-20200514212119209.png) pom.xml如下 ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.7.RELEASE org.lanettiesso dubbo-simple 0.0.1-SNAPSHOT dubbo-simple simple dubbo by me 1.8 org.springframework.boot spring-boot-starter-web org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine ``` 我自己定义了一个NamespaceHanlder,如下 ```java package org.lanettiesso.dubbo.simple.schema; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class SimpleDubboNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { } } ``` 在resources目录下,新建一个application-context.xml,内容如下 ```xml ``` 我准备先实现这三个简单的标签解析。 新建这三个标签对应的类,以便让Spring注入生成对应的Bean ```java package org.lanettiesso.dubbo.simple.bean; import lombok.Data; import lombok.ToString; @Data @ToString public class Application { private String name; } package org.lanettiesso.dubbo.simple.bean; import lombok.Data; import lombok.ToString; @Data @ToString public class Registry { private String address; } package org.lanettiesso.dubbo.simple.bean; import lombok.Data; import lombok.ToString; @Data @ToString public class Protocol { private String name; private int port; } ``` 在application-context.xml中加入我刚刚定义的SimpleDubboNamespaceHandler,能够让Spring扫描到。 ```xml ``` 把resources/META-INF/spring.handlers修改为 ```properties http\://dubbo.apache.org/schema/dubbo=org.lanettiesso.dubbo.simple.schema.SimpleDubboNamespaceHandler http\://code.alibabatech.com/schema/dubbo=org.lanettiesso.dubbo.simple.schema.SimpleDubboNamespaceHandler ``` 新建一个BeanDefinitionParser的实现类SimpleDubboBeanDefinitionParser ```java package org.lanettiesso.dubbo.simple.schema; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class SimpleDubboBeanDefinitionParser implements BeanDefinitionParser { private Class clazz; public SimpleDubboBeanDefinitionParser(Class clazz) { this.clazz = clazz; } @Override public BeanDefinition parse(Element element, ParserContext parserContext) { RootBeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClass(clazz); beanDefinition.setLazyInit(false); parserContext.getRegistry().registerBeanDefinition(clazz.getSimpleName(), beanDefinition); String tagName = element.getLocalName(); switch (tagName) { case "application": String appName = element.getAttribute("name"); beanDefinition.getPropertyValues().add("name", appName); break; case "protocol": String protocolName = element.getAttribute("name"); String port = element.getAttribute("port"); beanDefinition.getPropertyValues().add("name", protocolName); beanDefinition.getPropertyValues().add("port", port); break; case "registry": String address = element.getAttribute("address"); beanDefinition.getPropertyValues().add("address", address); break; } return beanDefinition; } } ``` 修改SimpleDubboNamespaceHandler如下 ```java package org.lanettiesso.dubbo.simple.schema; import org.lanettiesso.dubbo.simple.bean.Application; import org.lanettiesso.dubbo.simple.bean.Protocol; import org.lanettiesso.dubbo.simple.bean.Registry; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class SimpleDubboNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("application", new SimpleDubboBeanDefinitionParser(Application.class)); registerBeanDefinitionParser("registry", new SimpleDubboBeanDefinitionParser(Registry.class)); registerBeanDefinitionParser("protocol", new SimpleDubboBeanDefinitionParser(Protocol.class)); } } ``` 新建一个Spring的启动类 ```java import org.lanettiesso.dubbo.simple.bean.Application; import org.lanettiesso.dubbo.simple.bean.Protocol; import org.lanettiesso.dubbo.simple.bean.Registry; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRunner { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); context.start(); System.out.println(context.getBean(Application.class)); System.out.println(context.getBean(Registry.class)); System.out.println(context.getBean(Protocol.class)); } } ``` 启动,运行结果如下 ![image-20200514215647392](dubbo.assets/image-20200514215647392.png) 看来标签解析已经成功了 ### 扫描Service注解 首先新建Service注解,如下 ```java package org.lanettiesso.dubbo.simple.annotation; import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Inherited public @interface Service { } ``` 如何扫描加了Service注解的类呢?如果把扫描到的类注册到Spring呢? 哈哈哈,偷偷看一眼dubbo的源码 新建一个ClassPathBeanDefinitionScanner的子类 ```java package org.lanettiesso.dubbo.simple.beans.factory.annotation; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import java.util.Set; public class SimpleDubboClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner { private Set beanDefinitionHolders; public SimpleDubboClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) { super(registry); } @Override public int scan(String... basePackages) { beanDefinitionHolders = super.doScan(basePackages); return beanDefinitionHolders.size(); } public Set getBeanDefinitionHolders() { return beanDefinitionHolders; } } ``` 新建一个BeanDefinitionRegistryPostProcessor的实现类 ```java package org.lanettiesso.dubbo.simple.beans.factory.annotation; import lombok.extern.slf4j.Slf4j; import org.lanettiesso.dubbo.simple.annotation.Service; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.core.type.filter.AnnotationTypeFilter; import java.util.Set; @Slf4j public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { String basePackage = "org.lanettiesso.dubbo.simple"; SimpleDubboClassPathBeanDefinitionScanner scanner = new SimpleDubboClassPathBeanDefinitionScanner(registry); scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class)); scanner.scan(basePackage); Set beanDefinitionHolders = scanner.getBeanDefinitionHolders(); System.out.println(basePackage); for (BeanDefinitionHolder definitionHolder : beanDefinitionHolders) { registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition()); log.info("registry bean: " + definitionHolder.getBeanName()); } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } } ``` 在application-context.xml中增加配置 ```xml ``` 定义一个接口 ```java package org.lanettiesso.dubbo.simple.service; public interface HelloService { void sayHello(String name); String getTime(); } ``` 定义一个实现类作为服务提供者 ```java package org.lanettiesso.dubbo.simple.service.provider; import lombok.extern.slf4j.Slf4j; import org.lanettiesso.dubbo.simple.annotation.Service; import org.lanettiesso.dubbo.simple.service.HelloService; import java.text.SimpleDateFormat; import java.util.Date; @Slf4j @Service public class HelloServiceImpl implements HelloService { @Override public void sayHello(String name) { log.info("Hello {}", name); } @Override public String getTime() { return new SimpleDateFormat("yyyy-MM-dd").format(new Date()); } } ``` 修改启动类 ```java import org.lanettiesso.dubbo.simple.bean.Application; import org.lanettiesso.dubbo.simple.bean.Protocol; import org.lanettiesso.dubbo.simple.bean.Registry; import org.lanettiesso.dubbo.simple.service.HelloService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringRunner { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); context.start(); System.out.println(context.getBean(Application.class)); System.out.println(context.getBean(Registry.class)); System.out.println(context.getBean(Protocol.class)); HelloService helloService = context.getBean(HelloService.class); helloService.sayHello("lanettiesso"); System.out.println(helloService.getTime()); } } ``` 运行结果如下 ![image-20200514223740945](dubbo.assets/image-20200514223740945.png) 说明已经实现了通过自定义注解扫描类,并注册到Spring容器 ### 注入Reference 新建Reference注解 ```java package org.lanettiesso.dubbo.simple.annotation; import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) @Inherited public @interface Reference { } ``` 新建一个Controller ```java package org.lanettiesso.dubbo.simple.consumer.controller; import org.lanettiesso.dubbo.simple.annotation.Reference; import org.lanettiesso.dubbo.simple.service.HelloService; import org.springframework.web.bind.annotation.RequestMapping; public class HelloController { @Reference private HelloService helloService; @RequestMapping("/hello") public Object sayHello(String name) { helloService.sayHello(name); return "ok"; } @RequestMapping("/time") public Object getTime() { return helloService.getTime(); } } ``` 在application-context.xml中加入配置 ```xml ``` 如何注入helloController里的helloService呢? 引入依赖 ```xml cglib cglib 3.3.0 ``` 新建BeanPostProcessor的实现类SimpleDubboBeanPostProcessor ```java package org.lanettiesso.dubbo.simple.beans.factory.config; import lombok.extern.slf4j.Slf4j; import org.lanettiesso.dubbo.simple.annotation.Reference; import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import java.lang.reflect.Field; @Slf4j public class SimpleDubboBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class objClz; if (AopUtils.isAopProxy(bean)) { objClz = AopUtils.getTargetClass(bean); } else { objClz = bean.getClass(); } try { for (Field field : objClz.getDeclaredFields()) { //判断该属性是否有 Reference 注解 Reference reference = field.getAnnotation(Reference.class); if (reference != null) { Class fieldType = field.getType(); Enhancer enhancer = new Enhancer(); //继承被代理类 enhancer.setSuperclass(fieldType); enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> { log.info("before---------------------------------------------------"); log.info("invoke my method"); log.info("after------------------------------------------------------"); return null; }); //设置代理类对象 Object o = enhancer.create(); field.setAccessible(true); //注入 field.set(bean, o); } } } catch (Exception e) { throw new RuntimeException("Injection dubbo bean error.", e); } return bean; } } ``` 在provider.xml中加入 ```xml ``` 新建一个MemoryRegistryCenter模拟注册中心 ```java package org.lanettiesso.dubbo.simple.registry; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MemoryRegistryCenter { private final static List> CONSUMERS = new ArrayList<>(); private final static Map, Object> CLAZZ_BEAN_MAP = new HashMap<>(); public static void registryConsumerClazz(Class clazz) { CONSUMERS.add(clazz); } public static void registryProvider(Class clazz, Object o) { for (Class clz : CONSUMERS) { Class[] interfaces = clazz.getInterfaces(); for (Class anInterface : interfaces) { if (anInterface.equals(clz)) { CLAZZ_BEAN_MAP.put(clz, o); return; } } } } public static Object invoke(Class clazz, String methodName, Object... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Method method; if (args == null) { method = clazz.getDeclaredMethod(methodName); } else { Class[] classes = new Class[args.length]; for (int i = 0, classesLength = classes.length; i < classesLength; i++) { classes[i] = args[i].getClass(); } method = clazz.getDeclaredMethod(methodName, classes); } return method.invoke(CLAZZ_BEAN_MAP.get(clazz), args); } } ``` 修改SimpleDubboBeanPostProcessor为 ```java package org.lanettiesso.dubbo.simple.beans.factory.config; import lombok.extern.slf4j.Slf4j; import org.lanettiesso.dubbo.simple.annotation.Reference; import org.lanettiesso.dubbo.simple.registry.MemoryRegistryCenter; import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import java.lang.reflect.Field; @Slf4j public class SimpleDubboBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class objClz; if (AopUtils.isAopProxy(bean)) { objClz = AopUtils.getTargetClass(bean); } else { objClz = bean.getClass(); } try { for (Field field : objClz.getDeclaredFields()) { //判断该属性是否有 Reference 注解 Reference reference = field.getAnnotation(Reference.class); if (reference != null) { Class fieldType = field.getType(); Enhancer enhancer = new Enhancer(); //继承被代理类 enhancer.setSuperclass(fieldType); enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> { log.info("before---------------------------------------------------"); //模拟远程调动服务 Object result = MemoryRegistryCenter.invoke(fieldType, method.getName(), objects); log.info("after------------------------------------------------------"); return result; }); //设置代理类对象 Object o = enhancer.create(); field.setAccessible(true); //注入 field.set(bean, o); //注册到注册中心 MemoryRegistryCenter.registryConsumerClazz(fieldType); } } } catch (Exception e) { throw new RuntimeException("Injection dubbo bean error.", e); } return bean; } } ``` 修改启动类 ```java import lombok.extern.slf4j.Slf4j; import org.lanettiesso.dubbo.simple.annotation.Service; import org.lanettiesso.dubbo.simple.consumer.controller.HelloController; import org.lanettiesso.dubbo.simple.registry.MemoryRegistryCenter; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Map; @Slf4j public class SpringRunner { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml"); context.start(); Map dubboServiceMap = context.getBeansWithAnnotation(Service.class); dubboServiceMap.forEach((beanName, service) -> { MemoryRegistryCenter.registryProvider(service.getClass(), service); log.info("register provider: " + beanName); }); HelloController helloController = context.getBean(HelloController.class); System.out.println(helloController.getTime()); System.out.println(helloController.sayHello("lan")); } } ``` 运行 ![image-20200514232927702](dubbo.assets/image-20200514232927702.png) 哈哈哈,实现了一个简单的调用 ## [Spring拓展点](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/beans.html#beans-factory-extension) 之前看Spring的源码都觉得特别枯燥,而且看了好像也没什么用,知道这次结合dubbo一起研究了下,突然就觉得Spring的设计很强大,正是因为它设计中的拓展点,才能够很好的整合其他的框架。来看一下上面用到的拓展点,以及每个拓展点的执行时机。 ### NamespaceHandler 这个类是用来处理XML中的标签的,我们通过实现这个类,可以处理一些自定义的标签。但是实际的解析标签的操作不是这个类完成的,而是BeanDefinitionParser完成的。NamespaceHandler的功能主要是注册BeanDefinitionParser,调用BeanDefinitionParser的完成具体的解析工作。 自定义的NamespaceHandler的加载与调用是在BeanDefinitionParserDelegate.parseCustomElement方法中进行的,可以通过debug查看调用栈。 在DefaultNamespaceHandlerResolver.resolve方法中实例化NamespaceHandler Bean,调用NamespaceHandler.init方法,并把实例化后的NamespaceHandler放入DefaultNamespaceHandlerResolver.Map handlerMappings,key是NamepaceURI,value是NamespaceHandler。 最后调用handler.parse来解析自定义标签 ### BeanPostProcessor 可以参考官方文档,文档上说的很详细。我的理解就是,BeanPostProcessor是Spring给我们留的一个拓展接口,我们实现这个接口并注册到Spring容器之后,Spring容器就会在后续调用。具体是什么时候调用的呢,看看源码。 Spring主要的启动流程就在org.springframework.context.support.AbstractApplicationContext类的refresh()方法中 ```java @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //注册bean processors 拦截bean的创建 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } } ``` 在上面的代码中,我们从代码注释可以看到,BeanPostProcessor的处理和registerBeanPostProcessors方法有关系,看一下这个方法 ```java /** * Instantiate and register all BeanPostProcessor beans, * respecting explicit order if given. *

Must be called before any instantiation of application beans. */ protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); } ``` 实例化并注册所有的BeanPostProcessor Bean,看一下具体实现 ``` public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, and the rest. // 把实现了PriorityOrdered, Ordered等等的BeanPostProcessors分开 List priorityOrderedPostProcessors = new ArrayList<>(); List internalPostProcessors = new ArrayList<>(); List orderedPostProcessorNames = new ArrayList<>(); List nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, register the BeanPostProcessors that implement PriorityOrdered. // 注册实现了PriorityOrdered的BeanPostProcessors sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered. List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular BeanPostProcessors. List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors. sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); // Re-register post-processor for detecting inner beans as ApplicationListeners, // moving it to the end of the processor chain (for picking up proxies etc). beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); } ``` 这个方法,把BeanPostProcessors先进行分类,然后注册。那它是在何时开始执行的呢,如果直接看代码,可能不是很方便的看到是如何调用的,先运行一次代码,打个断点 ![image-20200516103752153](dubbo.assets/image-20200516103752153.png) 可以看到方法的调用栈,嵌套的很多,不过可以看到是从AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory)开始调用的,点击左边的栈帧,可以定位到对应的方法,看个比较重要的 AbstractAutowireCapableBeanFactory.InitializationBean方法 ![image-20200516104504606](dubbo.assets/image-20200516104504606.png) 从下图中可以看到在调用Bean的初始化方法前后分别调用了BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法 #### 例子 前面我们都没有使用过bean的init-method功能,测试一下 新建一个类User ```java package org.lanettiesso.dubbo.example.bean.postprocessor; import lombok.Data; import lombok.extern.slf4j.Slf4j; @Data @Slf4j public class UserBean { public void init() { log.info("----------------------- User init ---------------------"); } } ``` 创建一个BeanPostProcessor的实现类Example1BeanPostProcessor ```java package org.lanettiesso.dubbo.example.bean.postprocessor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; @Slf4j public class Example1BeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.info("------------------------- BeanPostProcessor before init ------------------------------"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { log.info("------------------------- BeanPostProcessor after init ------------------------------"); return bean; } } ``` 创建一个application-context-example1.xml ```xml ``` 创建一个启动类 ```java package org.lanettiesso.dubbo.example; import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ExampleTest { @Test public void testBeanPostProcessor() { start("example/application-context-example1.xml"); } private void start(String xmlPath) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath); context.start(); } } ``` 运行结果如下 ![image-20200516111442454](dubbo.assets/image-20200516111442454.png) 正如我们在源码中看到的过程一样 #### 总结 - 通过实现BeanPostProcessor接口并注册到Spring容器,我们可以在实现类中对Bean进行操作,例如dubbo-simple中,我们就对Bean进行了动态代理,然后返回给Spring容器的是我们代理后的对象,之后在使用bean的时候需要做什么事,我们都可以在动态代理中做自己的定义 - BeanPostProcessor是在AbstractApplicationContext.registerBeanPostProcessors方法中注册,在AbstractApplicationContext.finishBeanFactoryInitialization方法中调用,具体的调用过程在AbstractAutowireCapableBeanFactory.InitializationBean方法中,调用流程是先执行BeanPostProcessor.postProcessBeforeInitialization然后执行Bean的init-method,最后执行BeanPostProcessor.postProcessAfterInitialization ### BeanDefinitionRegistryPostProcessor ## 动态代理 JDK动态代理和Cglib的比较 ``` 由于Cglib代理是利用ASM字节码生成框架在内存中生成一个需要被代理类的子类完成代理,而JDK动态代理是利用反射原理完成动态代理,所以Cglib创建的动态代理对象性能比JDk动态代理动态创建出来的代理对象新能要好的多,但是对象创建的速度比JDk动态代理要慢,所以,当Spring使用的是单例情况下可以选用Cglib代理,反之使用JDK动态代理更加合适。同时还有一个问题,被final修饰的类只能使用JDK动态代理,因为被final修饰的类不能被继承,而Cglib则是利用的继承原理实现代理的。 ```