Dubbo源码 与Spring一起学习Dubbo里的Aware

Posted Dream_it_possible!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo源码 与Spring一起学习Dubbo里的Aware相关的知识,希望对你有一定的参考价值。

目录

一、Spring

1.BeanNameAware

2. BeanClassLoaderAware

3. ApplicationContextAware

4. EnvironmentAware

5. ApplicationEventPublisherAware

6. aware注入时机

二、Dubbo

1. ExtensionAccessorAware

三、小结


        现在很多同行做java开发几年了,被迫停留在curd的层面上"拧螺丝",对SpringAware可能只停留在怎么用的层面上,那我们用Spring时可以通过Aware能获取到容器工厂、应用上下文、Bean的类加载器等。

        那Spring 开发者为什么要设计这些Aware呢?那跟着这篇文章去一探究竟吧!      

        Spring 常见的一些Aware有 BeanNameAware、BeanClassLoaderAware、ApplicationContextAware、EnvironmentAware、ApplicationEventPublisherAware等。

        我在前文里写到Dubbo里的一些设计思想借鉴了Spring , 同样Dubbo 3.0里使用到了ScopeModelAware、ExtensionAccessorAware等,在初始化Extension Bean时设置了ExtensionAccessorAware, 让我们一起来看下aware的作用吧。

一、Spring

1.BeanNameAware

        获取到该Bean的name

@DubboService
public class DemoServiceImpl implements DemoService, BeanNameAware 

    @Override
    public String sayHello(String name) 
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello " + name;
    


    @Override
    public void setBeanName(String beanName) 
        System.out.println("获取到BeanName=" + beanName);
    

         在启动的时候获取到beanName: 

2. BeanClassLoaderAware

        获取到加载Bean的类加载器,可用该加载器写业务代码。

package org.apache.dubbo.springboot.demo.provider;


import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.springboot.demo.DemoService;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;

@DubboService
public class DemoServiceImpl implements DemoService, BeanNameAware, BeanClassLoaderAware 

    private ClassLoader classLoader;

    @Override
    public String sayHello(String name) 
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());

        try 
            Class<?> clazz = classLoader.loadClass("org.apache.dubbo.springboot.demo.provider.Test01");
            Test01 test01 = (Test01) clazz.newInstance();
            test01.say();
         catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) 
            e.printStackTrace();
        
        return "Hello " + name;
    


    @Override
    public void setBeanName(String beanName) 
        System.out.println("获取到BeanName=" + beanName);
    

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) 
        this.classLoader = classLoader;
    

        获取到ClassLoader, 加载到Test01类后获取到指定对象:

3. ApplicationContextAware

        获取到Spring应用的上下文applicationContext, 可以根据applicationContext去拿到某个bean。

        比如我新建一个Test02, 用@Component注解标记,表示交给spring 管理。


package org.apache.dubbo.springboot.demo.provider;


import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.springboot.demo.DemoService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

@DubboService
public class DemoServiceImpl implements DemoService, BeanNameAware, BeanClassLoaderAware, ApplicationContextAware 

    private ClassLoader classLoader;


    private ApplicationContext applicationContext;

    @Override
    public String sayHello(String name) 
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());

        try 
            Class<?> clazz = classLoader.loadClass("org.apache.dubbo.springboot.demo.provider.Test01");
            Test01 test01 = (Test01) clazz.newInstance();
            test01.say();
            Test02 test02 = applicationContext.getBean(Test02.class);
            test02.say();
         catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) 
            e.printStackTrace();
        
        return "Hello " + name;
    


    @Override
    public void setBeanName(String beanName) 
        System.out.println("获取到BeanName=" + beanName);
    

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) 
        this.classLoader = classLoader;
    

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
        this.applicationContext = applicationContext;
    

打印结果:

4. EnvironmentAware

        新建一个EnvironmentAwareConfig类实现EnvironmentAware接口, 实现类需要是Bean, 即被Spring 容器管理的类。

        添加一个参数: -Dtest=testEnvironmentAware:

        我们可以在业务代码里根据environment对象获取到配置的参数。 

package org.apache.dubbo.springboot.demo.provider;

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;


@Component
public class EnvironmentConfig implements EnvironmentAware 
    @Override
    public void setEnvironment(Environment environment) 
        System.out.println("获取到属性: " + environment.getProperty("test", "nothing"));
    

        实际开发中,可以使用environment获取到启动入参。 

5. ApplicationEventPublisherAware

        这个Aware是用来获取事件发布订阅的类ApplicationEventPublisher,利用applicationEventPublisher发布Spring 事件。

package org.apache.dubbo.springboot.demo.provider.publish;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;


@Component
public class EventPublisher implements ApplicationEventPublisherAware 
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) 
        applicationEventPublisher.publishEvent(new EventTest("test"));
    

    public static class EventTest extends ApplicationEvent 
        public EventTest(Object source) 
            super(source);
        
    

    @Component
    public static class EventListener implements ApplicationListener 
        @Override
        public void onApplicationEvent(ApplicationEvent applicationEvent) 
            if (applicationEvent instanceof EventTest) 
                System.out.println("接收到事件====" + applicationEvent.getSource());
            
        
    



打印结果: 

6. aware注入时机

        以上的所有Aware都是Spring 提供给开发者使用的工具类,那他们是在Spring 什么时候注入的呢?

        看一下Spring 5.2+的代码, 他们其实是在postProccessBeforeInitialization()方法里注入的。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.context.support;

import java.security.AccessControlContext;
import java.security.AccessController;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;

class ApplicationContextAwareProcessor implements BeanPostProcessor 
    private final ConfigurableApplicationContext applicationContext;
    private final StringValueResolver embeddedValueResolver;

    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) 
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    

    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
        if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware)) 
            return bean;
         else 
            AccessControlContext acc = null;
            if (System.getSecurityManager() != null) 
                acc = this.applicationContext.getBeanFactory().getAccessControlContext();
            

            if (acc != null) 
                AccessController.doPrivileged(() -> 
                    this.invokeAwareInterfaces(bean);
                    return null;
                , acc);
             else 
                this.invokeAwareInterfaces(bean);
            

            return bean;
        
    

// 注入Aware
    private void invokeAwareInterfaces(Object bean) 
        if (bean instanceof EnvironmentAware) 
            ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
        

        if (bean instanceof EmbeddedValueResolverAware) 
            ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        

        if (bean instanceof ResourceLoaderAware) 
            ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
        

        if (bean instanceof ApplicationEventPublisherAware) 
            ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
        

        if (bean instanceof MessageSourceAware) 
            ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
        

        if (bean instanceof ApplicationContextAware) 
            ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
        

    

 从invokeAwareInterfaces方法里得知aware的加载顺序:

EnvironmentAware>ResourceLoaderAware>ApplicationEvenetPublisherAware>ApplicationContextAware 

二、Dubbo

        ExtensionAccessorAware是为了SPI 扩展而设计的一个类,该了的作用提供方法实现类的ExtensionAccessor, 通过ExtensionAccessor可以获取到指定的SPI实现类。

1. ExtensionAccessorAware

/**
 * SPI extension can implement this aware interface to obtain appropriate @link ExtensionAccessor instance.
 */
public interface ExtensionAccessorAware 

    void setExtensionAccessor(final ExtensionAccessor extensionAccessor);


        该方法的调用时机是在Extension实例注入完成后执行。 

        方式一: 在ScopeBeanFactory注册Bean实例注入完成后,会执行PostProcessAfterInitialization()方法来初始化实例。 


    private void initializeBean(String name, Object bean) 
        checkDestroyed();
        try 
            // 设置一系列的aware
            if (bean instanceof ExtensionAccessorAware) 
                ((ExtensionAccessorAware) bean).setExtensionAccessor(extensionAccessor);
            
            // 执行postProcessAfterInitialization(bean,name);
            for (ExtensionPostProcessor processor : extensionPostProcessors) 
                processor.postProcessAfterInitialization(bean, name);
            
         catch (Exception e) 
            throw new ScopeBeanException("register bean failed! name=" + name + ", type=" + bean.getClass().getName(), e);
        
    

        方式二: 在ExtensionLoader里执行InjectExtension(instance)方法后执行。

   @SuppressWarnings("unchecked")
    private T createExtension(String name, boolean wrap) 
        // 根据实现类名去加载所有的Spi,然后将实现类放入到内存里,然后返回实现类的Class
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null || unacceptableExceptions.contains(name)) 
            throw findException(name);
        
        try 
            T instance = (T) extensionInstances.get(clazz);
            if (instance == null) 
                extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
                instance = (T) extensionInstances.get(clazz);
                // 初始化之前
                instance = postProcessBeforeInitialization(instance, name);
                // 注入extension
                injectExtension(instance);
                // 初始化之后
                instance = postProcessAfterInitialization(instance, name);
            
        
// ...

        如果是ExensionAccessorAware那么就设置ExtensionAccessor。 

    @SuppressWarnings("unchecked")
    private T postProcessAfterInitialization(T instance, String name) throws Exception 
        //设置Aware
        if (instance instanceof ExtensionAccessorAware) 
            ((ExtensionAccessorAware) instance).setExtensionAccessor(extensionDirector);
        
        if (extensionPostProcessors != null) 
            for (ExtensionPostProcessor processor : extensionPostProcessors) 
                instance = (T) processor.postProcessAfterInitialization(instance, name);
            
        
        return instance;
    

       从代码里发现,Dubbo的ExtensionAccessorAware接口的设置在postProccessAfterInitialization方法之前,可以理解为Bean的初始化之前,我感觉此处的aware 初始化的时机设计类似于 Spring的aware。

三、小结

        Aware的设计的初衷在于将应用的底层设计与业务剥离,开发者可以根据需求使用Aware来获取到指定对象,通过注入的对象添加一些需要的业务代码。

以上是关于Dubbo源码 与Spring一起学习Dubbo里的Aware的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo源码 与Spring一起学习Dubbo里的Aware

Dubbo源码学习ScopeBeanFactory对比Spring 的BeanFactory

Dubbo源码学习ScopeBeanFactory对比Spring 的BeanFactory

Dubbo源码学习ScopeBeanFactory对比Spring 的BeanFactory

dubbo源码学习 : spring 自定义标签

Dubbo 源码解析08_Dubbo与Spring结合