目录
5. ApplicationEventPublisherAware
现在很多同行做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的作用吧。
获取到该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:
获取到加载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类后获取到指定对象:
获取到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;
- }
- }
打印结果:
新建一个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获取到启动入参。
这个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());
- }
- }
- }
-
-
- }
打印结果:
以上的所有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
ExtensionAccessorAware是为了SPI 扩展而设计的一个类,该了的作用提供方法实现类的ExtensionAccessor, 通过ExtensionAccessor可以获取到指定的SPI实现类。
- /**
- * 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来获取到指定对象,通过注入的对象添加一些需要的业务代码。