IOC
IOC
当我们调用createAdaptiveExtension或者getExtension->createExtension都会有IOC的操作,使用的injectExtension方法
分析下这句调用
MyProtocol myExt = ExtensionLoader.getExtensionLoader(MyProtocol.class).getExtension("myExt");
getExtension方法
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
// 持有当前扩展对象
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//创建扩展对象
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
createExtension方法
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 对目标对象进行IOC处理
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
// 对AOP扩展类进行IOC处理
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
...
}
}
injectExtension
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
// IOC处理的方法必须满足三个条件
// 1. set开头 2. 一个参数 3. public方法
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
// set方法上标有@DisableInject注解的跳过
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
try {
// 方法名length> 3, 例如setStudent 那么property = student
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
// 这里的objectFactory是AdaptiveExtensionFactory对象
//这个student就是扩展类的名称
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//从spring或者dubbo中获取到set方法的参数实例后设置给当前instance
method.invoke(instance, object);
}
} catch (Exception e) {
...
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
AdaptiveExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
//该方法用来初始化factories
public AdaptiveExtensionFactory() {
// 加载ExtensionFactory类型
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
//1. 获取除了@Adaptive修饰的类和AOP扩展类之外的所有扩展类的名字
for (String name : loader.getSupportedExtensions()) {
//2. 根据名字获取扩展类
list.add(loader.getExtension(name));
}
// 将除了@Adaptive修饰的类和AOP扩展类之外的所有扩展类封装在list中赋值给factories
factories = Collections.unmodifiableList(list);
}
@Override
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;
}
}
我们看到这个类上有个@Adaptive注解 那么调用getAdaptiveExtension方法时,就返回的它本身,在调用createAdaptiveExtension时,会创建该类的实例(调用构造方法)
1、将SpiExtensionFactory和SpringExtensionFactory方在了factories中
2、然后可以通过getExtension方法使用SpiExtensionFactory和SpringExtensionFactory分别获取dubbo扩展类和spring管理的类
SpiExtensionFactory
/**
* 从dubbo中获取扩展类,需要注入的方法参数为@SPI标识的接口, 同时有普通的扩展类
* 获取的扩展类是动态类型
* SpiExtensionFactory
*/
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
// 注入的类型必须是接口,同时要被@SPI标识
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension();
}
}
return null;
}
}
上面说的普通的扩展类是指除了AOP类型(一般名字以Wrapper结尾),@Adaptive标识的类之外的其它所有类.
我们发现上面获取的扩展类是getAdaptiveExtension动态生成的,那么就要求要么该类是被@Adaptive标识,
要么就有个方法被@Adaptive标识,而且被@Adaptive标识的方法的参数有个限制条件
1、必须有一个URL参数
2、或者参数中有个对象包含pubilc URL getXXX();这种签名的方法;
? 该方法满足:1. public, 2.不带static, 3. get方法,4.没有参数,5. get方法的XXX不能为空
那么在我们了解到IOC的原理后,自己写一个测试。
自定义IOC应用
接着AOP的demo继续写
- 自定义一个协议
// 设置默认扩展类型
@SPI(value = MyExtProtocol.NAME)
public interface MyProtocol {
String getName();
}
- 默认扩展类(目标执行的扩展类)
public class MyExtProtocol implements MyProtocol {
public static final String NAME = "myExt";
@Override
public String getName() {
System.out.println("MyExtProtocol.getName" + "目标方法被调用");
return "MyExtProtocol.getName";
}
}
- AOP类型
/**
* MyProtocol类型的AOP扩展类
* 与目标扩展类实现同一个接口
*/
public class MyProtocolWrapper implements MyProtocol {
/**
* AOP链式调用中的一节,这里我们只有一个AOP扩展类,故这个就是目标扩展类
*/
private MyProtocol myProtocol;
/**
* 使用SpiExtensionFactory注入的dubbo扩展对象
*/
private MySpringIOC mySpringIOC;
/**
* 使用SpringExtensionFactory注入的spring中的对象
*/
private DubboIOC dubboIOC;
public MyProtocolWrapper(MyProtocol myProtocol) {
this.myProtocol = myProtocol;
}
@Override
public String getName() {
System.out.println("MyProtocolWrapper.getName === " + "前置方法被调用");
String name = myProtocol.getName();
System.out.println("MyProtocolWrapper.getName === " + "后置方法被调用");
iocInvoke();
return name;
}
/**
* dubboIOC是通过IOC注入的,它会是个动态扩展类,调用dubboIOC.sayHello(url);时会从URL中获取
* 扩展类的名称,然后通过这个名称获取到扩展类实例, 调用目标扩展类的sayHello方法
*/
public void iocInvoke() {
mySpringIOC.say();
URL url = URL.valueOf("registry://192.168.1.7:9090/com.alibaba.service1?param1=value1&param2=value2&defaultIOC=myDubboIOC");
dubboIOC.sayHello(url);
}
public MySpringIOC getMySpringIOC() {
return mySpringIOC;
}
public void setMySpringIOC(MySpringIOC mySpringIOC) {
this.mySpringIOC = mySpringIOC;
}
public DubboIOC getDubboIOC() {
return dubboIOC;
}
public void setDubboIOC(DubboIOC dubboIOC) {
this.dubboIOC = dubboIOC;
}
}
? 将IOC需要注入的参数写在了AOP扩展类中(当然你也可以写在目标类中)
- IOC注入的类型
@SPI
public interface DubboIOC {
@Adaptive(value = "defaultIOC")
void sayHello(URL url);
}
满足了 1.注入的类型接口被@SPI标识, 2,接口被@Adaptive标识或者接口中有方法被@Adaptive标识
@Adaptive中的value是文件中配置的扩展类配置的别名在URL中的kye
比如: URL = "registry://192.168.1.7:9090/com.alibaba.service1?defaultIOC=myDubboIOC"
那么value应该为defaultIOC,然后会调用动态类中同名函数的如下语句
String extName = url.getParameter("defaultIOC"); //获得扩展类的别名
ExtensionLoader.getExtensionLoader(DubboIOC.class).getExtension(extName); //通过扩展类别名获取扩展类
? 3.如果是方法被@Adaptive标识, 该方法中有个参数为URL或参数的返回值是url的方法
5. 扩展实现类
public class MyDubboIOC implements DubboIOC {
@Override
public void sayHello(URL url) {
System.out.println(url+ "==================");
System.out.println("MyDubboIOC.sayHello ...........hello");
}
}
public class MySpringIOC {
public void say() {
System.out.println("MySpringIOC.say=======");
}
}
- 扩展类配置文件
per.qiao.myprotocol.MyProtocol
# 目标扩展类
myExt=per.qiao.myprotocol.impl.MyExtProtocol
# AOP类型
myWrapper=per.qiao.myprotocol.wrapper.MyProtocolWrapper
per.qiao.myprotocol.DubboIOC
myDubboIOC=per.qiao.myprotocol.myioc.MyDubboIOC
然后在spring的配置文件中写通过SpringExtensionFactory注入
<bean id="mySpringIOC" class="per.qiao.myprotocol.myioc.MySpringIOC"/>
- 调用
MyProtocol myExt = ExtensionLoader.getExtensionLoader(MyProtocol.class).getExtension("myExt");
myExt.getName();
这样就写完了。
总结:
? 自定协议:接口需要@SPI标识
? 自定义IOC:得满足需要注入的参数是Spring中的Bean或者dubbo中的扩展类
? 1. 如果是扩展类, 那么方法名set的后面对应的就是扩展名的名字,比如注入的方法名为:setMyIOC,那么必须有个扩展类与之对应 配置文件中 myIOC = xxx.xxx.xxIOC
2. 扩展类要么被@Adaptive修饰,要么有方法被@Adaptive修饰,
? 如果@Adaptive有value值,那么它就是URL中的一个参数的key,通过这个key从URL中获取value,那么这个value就是目标扩展类配置的名字 通过
String extName = url.getParameter("@Adaptive中的value值"); //获得扩展类的别名
ExtensionLoader.getExtensionLoader(DubboIOC.class).getExtension(extName);
? 如果@Adaptive没有value值, 那么默认的value就为接口名首字母小写
关于@Adaptive注解,可以参考 关于@Adaptive注解