目录
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的作用吧。
一、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来获取到指定对象,通过注入的对象添加一些需要的业务代码。
转载:https://blog.csdn.net/qq_33036061/article/details/127783110