Demand emerges of scenario
Some of you may have already encountered these two requirements in your daily development, but in order to let some of you who have not encountered these scenarios before, you can also read this article, so first mention it in the front
several BaseUrl of Demand scenarios
If the project is aggregated
App , compare Such as some news and information clients like, Possible data sources from multiple platforms, compare as said intimate knowledge ah, Douban, PRC social networking website ah, Today's headlines., So this would involve multiple BaseUrl
If the project makes usefulness To multiple triparty service providers, compare As the picture of Retrieval makes usefulness To a service provider, documents of storage also makes usefulness To another service provider, This one will also exist a
App There are multiple BaseUrl dynamic change BaseUrl of Demand scenarios
If the project of
BaseUrl will be in App At startup, the server is requested, and based on the results returned by the server, the final project BaseUrl , would involve a runtime dynamic switch BaseUrl
If one of the three service providers of the project is not fixed, maybe there will be a change, for example, the storage service is migrated from 7Niu to other cloud storage, then we will get the three service provider's information from the server in order to avoid re-packaging and re-releasing the code.
BaseUrl , and then dynamically change this at runtime BaseUrl solution
Actually, it's official.
Api Solutions have long been available to support multiple BaseUrl As well as dynamically changing the BaseUrl at runtime, there are also many popular solutions
Official Static solution
Retrofit developers should know @Get , @Post These are marked to each interface method of Annotations can not only pass relative paths, You can also pass the full path, This way we can do it differently interfaces Use different BaseUrl , thus achieving the goal of using multiple BaseUrl of need, But the note on the of The value can only be Final The constants cannot be changed dynamically, so I call this solution a static solution
Official Dynamic Solutions
Retrofit developers are equally aware of the @Url This is marked on each interface method parameter of explanatory note, It can pass the full path as a parameter into the interface as a per request of Url address, Each time the interface is requested, a different of Full path as a parameter, thus achieving support for multiple BaseUrl and dynamic changes at runtime BaseUrl So many interfaces requesting images and other resources are using this solution (eek, it looks like this official solution doesn't solve both of the problems I mentioned, don't worry, read later first!)
Common folk solutions
I've seen a lot of open source before of polymerization
App Source code, like some integration intimate knowledge , Douban, PRC social networking website , Gank of data from multiple platforms such as App , Because the respective platforms of Different domain names, So most of these types of App will create a separate Retrofit object, i.e., a different BaseUrl Use different Retrofit object to create the ApiService Make a request, This way simply adding a different of BaseUrl , that would need to recreate a new of Retrofit targets
This can also be done simultaneously, supporting multiple
BaseUrl and dynamic changes at runtime BaseUrl These two needs, But with a personal of viewpoint, Create multiple other configuration properties identical, merely BaseUrl different Retrofit targets, Too much of a waste of resources
The Folk Bull Solution
I stumbled across one earlier
Retrofit Defenders, Square The company's bull's solution , is used to solve the problem of dynamically changing the runtime BaseUrl It's actually a semi-official solution.
When it comes to this solution, I have to tell an interesting story, actually before
Retrofit default is to support dynamic changes at runtime BaseUrl of, There used to be a program called BaseUrl The interface of the Retrofit.Builder#baseUrl(BaseUrl) The method was then passed of The parameter is this BaseUrl , instead of the current HttpUrl , there is a method inside this interface that returns HttpUrl ,that's when it's time to just achieve BaseUrl back, Dynamically changing this method of return value, Dynamic changes can then be achieved BaseUrl
But this bull thinks so of Unsafe practices, So mention a
Pull Requests Delete this. BaseUrl interface, merge usefulness on top of of solution alternative, And dear. of JakeWharton Agreed with him. of viewpoint, and merged this PR That's how we got here. of Retrofit.Builder#baseUrl(HttpUrl) This can't be changed dynamically BaseUrl of Api
Retrofit For those of you who are old enough to know, there used to be one of these. Api, I mean, later. of Why is the version gone?, It was destroyed by this man.
This option is also the use of
Interceptor interceptors, dynamically changing each Request of Url thus enabling dynamic changes BaseUrl But he can't support this solution for more than BaseUrl As long as... host Set it until the next change. Host prior to, afterwards of all Request All must make usefulness the same Host There are some drawbacks that we will analyze later. Several programmes of right compare analysis with Phasing out of the system containing obvious defects of options
4 1 programme in, I'll start by eliminating of even
, It has been made clear earlier that I of viewpoint, Because I personally think creating multiple other configuration properties exactly the same, merely Common folk solutions BaseUrl different Retrofit targets, Too much of a waste of resources, So even if he could satisfy me. of All requirements, unless it's true of No better. of solution, I wouldn't have chosen it otherwise. of
Of the three remaining options ,
Can only solve, 2 of the requirements to support multiple Official Static solution BaseUrl , and for dynamic changes BaseUrl , Due to the annotation of Value It can only be a constant, so there is nothing that can be done about this requirement (both requirements are satisfied to make it feasible) Who is the best solution?
Actually, it was stated earlier
It is already possible to achieve multiple simultaneous Official Dynamic Solutions BaseUrl and runtime dynamic changes BaseUrl So why don't I just go with this option and continue the analysis?
The answer is also very simple, I think this program, although flexible, but flexible but it brings it to the use of cumbersome, each interface each call must be passed into the full path as a parameter, not only cumbersome and interface a number of bad management
Is it possible? But I already said earlier that this doesn't work, huh? The Folk Bull Solution
This solution can support dynamic switching at runtime though
BaseUrl But it is handled globally, and once used, it changes all the requested Url , so it doesn't support multiple BaseUrl
And scarier. of be, Not only does this option not support multiple
BaseUrl , but also affects harmony Official Static solution These two support multiple Official Dynamic Solutions BaseUrl solution, because no matter what full path you declare in the annotation, it's Interceptor interceptor, both force the request's Url Change it to this. of BaseUrl , so this option is destined for only one BaseUrl However, items that require dynamic change
Wouldn't that make all 4 solutions unfeasible? What's taking so long?
Total elimination of the programme? Meeting adjourned?
Wait, wait, wait., Although I stand in my of perspectives,
Pass clear-language in refer to of All existing of solution
But think about it., If perfection already exists online of solution, that What's the point of me still writing this article? It must not be to my satisfaction. of solution, I'm the one who's going to fix it and share it., After all, I am a reluctant writer of repetitive content of young people with promise As long as... I wrote it. of The content is sure to teach everyone different Knowledge III ✊, Or else you'll be ruining your own brand.
All right, enough teasing, let's go!
Don't worry, there's more!
Although there are already of solution proper in I didn't find anything that satisfied me. of, But in Problems encountered time, Calm analysis of existing solution It's necessary. of, Understanding those who came before us of It is only after thinking that the whole issue will be understood more thoroughly, me of Many articles are also based on the analysis of harmony Solution thinking is the main, give a man a fish and you feed him for a day; teach a man fish and you feed him for a lifetime, So I won't tell you the answer directly, First a wave of analysis, clarify the way of thinking
No, it's in the analysis.
The Folk Bull Solution time, Although in the end it turns out it's not what you want of solution, But as someone who thinks outside the box. of me, Another bright idea., With the help of the original solution A change like this above is not feasible You got it? How can the original programme be improved?
on top of of The analysis has spoken.
The Folk Bull Solution , can be found at Interceptor The interceptor sets a global Host(Host can be understood as BaseUrl) , the interceptor will force this Host is applied to all requests, changing the request's original Url , which results in the existence of only one simultaneous Host
So I was thinking., Will this only of
Host variable to a collection, to store multiple Host , In the case of bringing different of Host applied to different requests, it is possible to support multiple BaseUrl？ Practical ideas
do as one says, So I built a global one myself of Containers come storage several
Host ¶ so that I can be in ¶ App Runtime of any time, Add anywhere you want, revise, Delete Host Problems encountered
But here's the problem, I want to put different
Host applied to different requests, but how do I know what requests need what Host Every request always has to be marked so I know what he needs. Host bar (loanword) (serving drinks, or providing Internet access etc)
So I was thinking.
Retrofit What's the way? , can be found at Add a different to each request before requesting of String tag, So I'm natural of thought of it Header , Retrofit Just in time. @Headers This annotation, which can be added to each interface method to customize the Header Solving the hard part again
I give the need for a different
BaseUrl interface method to add a custom Header , to indicate the number of Host of Name ¶ And this ¶ Name corresponding of The value is Host , but the value is not in the @Headers in Is specified of, It can be changed dynamically of
Host The container for this is a Map , key, that's it. Name The value is... Host Each time an interceptor intercepts a request, it determines whether the request has this custom Header,
have of talk, Get this. Header in put a sign on sth explaining or calling attention to of Name , and then use this Name , go to (a place) that size storage Host of security situation Map in get(name) , get the corresponding Host And then applied to the request isn't that reaching support for multiple BaseUrl You got it?
If you want to dynamically change a
Host It's also easy to put a new Host alike of Name put(name) Into this global Map When the time comes for the interceptor, use this. Name get(name) Come out of value, it's already the latest in a long way since the change of Host , after putting this Host Apply to the request not to reach dynamic change BaseUrl You got it?
No, both needs are met at the same time!
This program is a two-step process that gives a different approach to what is needed.
BaseUrl The request settings for the Header (Want to use Retrofit default BaseUrl interface, or use the , Official Static solution (no need to set it), after managing the global container through the Official Dynamic Solutions BaseUrl
For the kind of people who only have a
BaseUrl However, for projects that require dynamic changes, the framework provides a GlobalDomain to optimize this scenario, without adding Header , just one step, to the global container put(GlobalDomain) You want to change. BaseUrl That'll do it.
It is much simpler to pass the full path to each interface as a parameter, Official Dynamic Solutions Destined for the kind of dynamic change that only one or two need Official Dynamic Solutions BaseUrl interfaces conclude
Above of solution, It has been optimized and encapsulated as a tripartite library and uploaded to
Jcenter , for your convenience.
This solution is mainly suitable for those who need to have multiple
BaseUrl and dynamic changes BaseUrl projects, Or just one BaseUrl But it needs to be changed dynamically BaseUrl projects
If for just a few more
BaseUrl No dynamic change required BaseUrl projects, In fact usefulness It is enough, but I still recommend using my solution, because the requirements are subject to change, if once you want to add dynamic changes Official Static solution BaseUrl of need, Dynamic switching is required Production environment harmony The development environment , that What to do then, Change each interface annotation one by one inside of Full path?
See the demo for details, remember Star !
Hello My name is Jessyan, if you like my articles, you can follow me on the following platforms
-- The end
1、6 Principles of Faceted Object Design 6 The Dimity Principle 2、Spring SpringBoot and TestNG Testing Guide TestPropertySource 3、JavaUsing annotations and reflection to implement aquot low versionquot of dependency injection 4、Database transactions and isolation levels
5、Python Security From SSRF to Command Execution Fiasco