ARouter source code analysis

arouter-api version : 1.4.1

preface

So far, ARouter has not resolved the final dependency injection, so today we will explore its implementation principle.

PS: because the principle of dependency injection is relatively simple, this article will be short.

@Autowired parsing

To implement dependency injection with ARouter, you need to add

ARouter.getInstance().inject(this);
copy

Then our code becomes the entry point for our analysis.

public void inject(Object thiz) {
    _ARouter.inject(thiz);
}
copy

ARouter is still called internally_ The inject method of ARouter.

static void inject(Object thiz) {
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
    // If autowiredService is not empty, complete dependency injection
    if (null != autowiredService) {
        autowiredService.autowire(thiz);
    }
}
copy

It is found that dependency injection is very similar to interceptors, which are completed by using service components. The service component of dependency injection is called AutowiredService. Tracing shows that its implementation class is AutowiredServiceImpl.

@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
    private LruCache<String, ISyringe> classCache;
    private List<String> blackList;

    @Override
    public void init(Context context) {
        classCache = new LruCache<>(66);
        blackList = new ArrayList<>();
    }

    @Override
    public void autowire(Object instance) {
        String className = instance.getClass().getName();
        try {
            // If the instance class is blacklisted, dependency injection will not be completed
            if (!blackList.contains(className)) {
                // Get from cache first
                ISyringe autowiredHelper = classCache.get(className);
                // Create object without cache
                if (null == autowiredHelper) {  // No cache.
                    autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                }
                // Complete dependency injection
                autowiredHelper.inject(instance);
                // Put in cache
                classCache.put(className, autowiredHelper);
            }
        } catch (Exception ex) {
            // Add to the blacklist if there is an error
            blackList.add(className);    // This instance need not autowired.
        }
    }
}
copy

ISyringe is the interface extracted by dependency injection,

public interface ISyringe {
    void inject(Object target);
}
copy

So who is the implementation class of ISyringe? The answer is the class XXXX automatically generated at compile time

ARouter

Autowired, let's find the Test1Activity generated in the demo

ARouter

Autowired take a look

public class Test1Activity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    Test1Activity substitute = (Test1Activity)target;
    substitute.name = substitute.getIntent().getStringExtra("name");
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
    substitute.height = substitute.getIntent().getIntExtra("height", substitute.height);
    substitute.girl = substitute.getIntent().getBooleanExtra("boy", substitute.girl);
    substitute.ch = substitute.getIntent().getCharExtra("ch", substitute.ch);
    substitute.fl = substitute.getIntent().getFloatExtra("fl", substitute.fl);
    substitute.dou = substitute.getIntent().getDoubleExtra("dou", substitute.dou);
    substitute.ser = (com.alibaba.android.arouter.demo.testinject.TestSerializable) substitute.getIntent().getSerializableExtra("ser");
    substitute.pac = substitute.getIntent().getParcelableExtra("pac");
    if (null != serializationService) {
      substitute.obj = serializationService.parseObject(substitute.getIntent().getStringExtra("obj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null != serializationService) {
      substitute.objList = serializationService.parseObject(substitute.getIntent().getStringExtra("objList"), new com.alibaba.android.arouter.facade.model.TypeWrapper<List<TestObj>>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'objList' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null != serializationService) {
      substitute.map = serializationService.parseObject(substitute.getIntent().getStringExtra("map"), new com.alibaba.android.arouter.facade.model.TypeWrapper<Map<String, List<TestObj>>>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'map' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    substitute.url = substitute.getIntent().getStringExtra("url");
    substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
  }
}
copy

From the automatically generated code above, we can see that dependency injection actually uses getintent internally Getxxxextra (similarly, Fragment uses getarguments () getXxx() ). It should be noted that the field modified by @Autowired cannot be private, otherwise an error will be reported when automatically generating code.

In addition, what is a SerializationService used for in the above code? In fact, SerializationService is used for json serialization. In the demo, an implementation class JsonServiceImpl is officially given, and Alibaba's fastjson is used internally. If you need to customize children's shoes, you can refer to JsonServiceImpl to implement it yourself.

end

Seeing this, basically, we have finished talking about ARouter dependency injection.

In this series, the process of ARouter code level is almost the same. The remaining two parts are gradle plugin and compiler, which have not been parsed yet. I will tell you later.

bye bye

Posted by bh on Mon, 01 Aug 2022 22:55:46 +0530