spring是如何获得容器中管理的类的
拿到applicationContext,就可以调用getBean方法来获得Spring的bean对象了
public class SpringContextUtil implements ApplicationContextAware {
// Spring应用上下文环境
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的回调方法,设置上下文环境
*
* @param applicationContext
*/
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtil.applicationContext = applicationContext;
}
/**
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 获取对象
*
* @param name
* @return Object
* @throws BeansException
*/
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
}
dubbo扩展点的IOC
前文中,大致有提到一些有关IOC
- 第一点 在讲解ExtensionLoader源码的构造函数的时候,我们说过,每一个ExtensionLoader实例都有一个 objectFactory 属性,他是实现Ioc的关键;
- 第二点 相比较于JDK的SPI机制,dubbo的SPI机制支持扩展通过setter的方式来注入其他扩展点。
- 第三点 在调用ExtensionLoader的getExtension方法时,在获取了相应的class并创建了instance之后,通过injectExtension(intance)方法来通过setter的方式来注入其他扩展点。
- 第四点 loadFile函数解析SPI配置时,假如这个类带@Adaptive注解,缓存到cachedAdaptiveClass。
如何实现IOC -> ExtensionLoader的injectExtension方法源码
关键说明,
- 获取instance的所有方法,并解析以set方法开头的方法,例如setXxyy(Xxyy xxyy)。
- 拿到set方法的入参类型Xxyy、属性名xxyy。
- 执行objectFactory.getExtension(pt, property)拿到Xxyy对应的实例。
- 通过反射执行set方法,注入Xxyy对象。
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
通过上面的方法,就可以将属性注入到instance中,实现自动装配(IOC)。下面我们来看一下 objectFactory.getExtension(pt, property)是如何工作的。
objectFactory属性
上篇文章中,提到在获取Container扩展点接口对应的ExtensionLoader的时候,会执行私有ExtensionLoader构造函数。
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
因为此时type是Container.class,即objectFactory = ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension();
当type为ExtensionFactory.class时,即 objectFactory = null.
我们可以看出,所有非ExtensionFactory.class扩展点接口都会执行ExtensionFactory对应的ExtensionLoader实例的getAdaptiveExtension()方法返回一个ExtensionFactory实例,即objectFactory对象。否则,objectFactory对象为null。
核心方法 -> ExtensionLoader的getAdaptiveExtension方法源码
-
getAdaptiveExtension 获取带有Adaptive注解的扩展实现类
-
createAdaptiveExtension()创建实例
-
injectExtension() 自动注入IOC
-
getAdaptiveExtensionClass() ---执行cachedAdaptiveClass对象的构造函数
-
getExtensionClasses() ---解析所有的扩展点实现
-
loadExtensionClasses() ---加载扩展类
- loadFile() --- 从固定的文件路径,解析加载对应的扩展点实现【上一篇已经说过,这个地方会加载几种情形的扩展实现类,包括拿到cachedAdaptiveClass对象】
-
- 返回cachedAdaptiveClass --- 返回loadFile()方法中构造的cachedAdaptiveClass对象
-
- 执行 cachedAdaptiveClass.newInstance() ---执行AdaptiveExtensionFactory的构造函数
-
-
-
ExtensionFactory的实现类AdaptiveExtensionFactory带有Adaptive标签,另外两个实现类SpiExtensionFactory、SpringExtensionFactory就是正常的实现类,也是我们见的最多的那种扩展点实现类。
### AdaptiveExtensionFactory源码
关键说明,
1. factories属性,所有的非@Adaptive类的ExtensionFactory实例的集合,以后所有与ExtensionFactory打交道的操作都交给AdaptiveExtensionFactory,
2. injectExtension方法中,调用的 Object object = objectFactory.getExtension(pt, property);分别调用SpiExtensionFactory、SpringExtensionFactory两个实际的实现类。
/**
* AdaptiveExtensionFactory
*
* @author william.liangf
*/
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
//所有的非@Adaptive类的ExtensionFactory实例的集合
private final List<ExtensionFactory> factories;
//因为ExtensionFactory对应的ExtensionLoader实例中缓存字段已经初始化好了,所以的ExtensionLoader的操作大都是从缓存中获取的数据
public AdaptiveExtensionFactory() {
//从缓存的static变量EXTENSION_LOADERS中拿到ExtensionFactory对应的ExtensionLoader实例
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
//拿到loader中加载的普通的SPI扩展接口实现类的名称,spring与spi
// adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
// spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
for (String name : loader.getSupportedExtensions()) {
//根据名称创建对应的ExtensionFactory实例
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
SpringExtensionFactory源码
public class SpringExtensionFactory implements ExtensionFactory {
private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
public static void addApplicationContext(ApplicationContext context) {
contexts.add(context);
}
public static void removeApplicationContext(ApplicationContext context) {
contexts.remove(context);
}
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
}
}
是不是有一点熟悉的味道了啊,这也算是一个首尾呼应吧~
这一篇到时很快就写完了~ 下篇文章会讲解扩展点是如何实现AOP的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。