preface
It took a long time, but cicada finally updated v2.0.0 with the help of a recent overnight rollout.
The reason why the larger version number is changed to 2 is indeed downward incompatible; The main performance is as follows:
- Fixed several feedbacks
bug
. - Flexible routing.
- Can pull out plug
IOC
Container selection.
The key is the latter two.
New routing mode
Let’s start with the first one: routing updates.
In previous versions, to write an interface you had to implement a WorkAction; And most troublesome is that an implementation class can only do one interface.
Therefore, some friends have mentioned this issue to me.
So the improved use mode is as follows:
A bit of deja vu 😊.
As shown in the figure above, there is no need to implement a specific interface; Just use different annotations.
It also supports custom POJOs, which cicada instantiates during invocation.
Taking the getUser interface as an example, these parameters are encapsulated in DemoReq when such requests are made.
http://127.0.0.1:5688/cicada-example/routeAction/getUser?id=1234&name=zhangsan
Get the response at the same time:
{"message":"hello =zhangsan"}
Copy the code
The implementation process is also very simple, we will find the source code; Here are some of the core steps.
- Scan all usage
@CicadaAction
Annotated classes. - Scan all usage
@CicadaRoute
Annotation method. - Store their mapping
Map
In the. - Upon request
URL
去Map
To find the relationship. - Reflect build parameters and method calls.
Scan classes and write mappings
Query the mapping on request
Reflection calls these methods
Whether an IOC container is required
I actually wrote all the above steps on a shuttle, but it got a little more interesting when I got to the implementation.
We all know that the reflection call method takes two important arguments:
obj
Method execution instance.args..
Nature is the parameter of the method.
The first time I wrote it, it went like this:
method.invoke(method.getDeclaringClass().newInstance(), object);
Copy the code
And then a test, no problem.
When I reviewed the code after I had written it, I found it was wrong: it created a newInstance each time, and reflection called newInstance() was not efficient.
At this time, I unconsciously thought of the IOC container in Spring, which is also very similar to the scene here.
All interfaces are instantiated and stored in the bean container during application initialization, and can only be retrieved from the container when needed.
This will only do a lot of loading at startup, but benefit future generations.
Pluggable IOC container
So I decided to implement such a bean container myself.
However, before implementing the feature, I thought of another feature:
It’s better to leave the implementation of the bean container up to the consumer to choose between using the bean container or creating a new instance each time, just like the Prototype scope in Spring.
You can even customize container implementations, such as storing beans in a database or Redis. Of course, most people don’t do that.
The mechanism is also somewhat similar to SPI.
To achieve the above requirements, there are roughly the following steps:
- A generic interface that contains methods for registering containers, getting instances from containers, and so on.
BeanManager
Class, which governs which one to useIOC
The container.
So first you define an interface; CicadaBeanFactory:
Contains interfaces for registering and getting instances.
There are two different container implementations.
Default implementation; CicadaDefaultBean:
That is, every time you create an instance; Since there is no bean container at all, there is no registry.
Next comes the real IOC container; CicadaIoc:
It stores all instances in a Map.
There’s also the CicadaBeanManager, which registers all instances with the bean container at application startup.
The highlight is the part of the picture marked in red:
- It needs to be instantiated according to the user’s choice
CicadaBeanFactory
Interface. - Register all instances with the CicadaBeanFactory interface.
It also provides a method to get an instance:
The CicadaBeanFactory interface method is called directly.
Then at the reflection call method mentioned above it becomes:
The instance is fetched from the bean container; This can be done by creating a new object each time, or by fetching the instance directly from the container. This doesn’t matter to the caller here.
So it does what the title says: pluggable.
To achieve this, I put the CicadaIoc implementation into a separate module, providing the implementation as a JAR package.
So if you want to get an instance using the IOC container, just add the jar package to your application.
<dependency>
<groupId>top.crossoverjie.opensource</groupId>
<artifactId>cicada-ioc</artifactId>
<version>2.0.0</version>
</dependency>
Copy the code
If not, it is the default CicadaDefaultBean implementation, which creates objects each time.
This has an advantage:
When you want to implement an IOC container yourself; Just implement the CicadaBeanFactory interface provided by Cicada and add only your JAR packages to your application.
All the rest of the code doesn’t need to change and can switch between different containers at will.
Of course, I recommend using the IOC container (which is essentially a singleton), and the performance gain is well worth the sacrifice of application startup time.
conclusion
Cicada pit is almost filled in, there will be some minor feature iterations.
Haven’t paid attention to friends quickly pay attention to a wave:
Github.com/TogetherOS/…
PS: Although I did not analyze the implementation of Spring IOC carefully, I believe that after reading this article, you should have some understanding of Spring IOC and SpringMVC.
Your likes and shares are the biggest support for me