Service provider framework + class.forname completes data componentization

background

When a project reaches a certain level, the increase of developers and the increase of functional system will be the problems faced by the development. The idea of componentization solves a series of problems for everyone. For the componentization of the project (Figure 2), the generally used design mode is the contraction of the layered architecture (Figure 1).

Figure 1(Schematic diagram of hierarchical architecture)

Figure 2(Componentization diagram)

One, the purpose of componentization

The purpose of componentalization is to decouple the project, so that the development can develop multiple modules synchronously and maximize the reuse of independent functions. We hope that the componentalized project can achieve:

  1. Supports the access of a large number of rich services, while maintaining clear boundaries between services, each can continue to iterate flexibly.
  2. Use a batch of unified middleware to support the underlying functions of various businesses and keep the overall reuse of middleware code;
  3. Can keep the system as low intrusion as possible, respect the original operation mechanism to reduce the later maintenance cost;
  4. As far as possible on the user device to reflect the characteristics of a simple client, at the same time specific service functions on demand, keep the volume controllable;

Any of the above points can be a strong argument. Today, for article 2, we will use a batch of unified middleware to support the underlying functions of various businesses and maintain the comprehensive reuse of the middleware code. Make an elaboration.

2. Middleware the common data in each business

Me the purpose of this article is combined with the use of the data management service provider framework, making it independent of the various modules of components, the hope can be initialized at the appointed place (componentization of the overall project life cycle of the control is also a live technical), interact in various business components and its operations are done by the component. ,

Purpose: The same management general data component, each end calls the corresponding method to complete the required function, so that the data is componentized and runs separately

Service provider framework

Before introducing the service provider framework, let’s look at a few concepts:

3.1 Class. Class.forname ()

Returns a Class object for a given Class or interface. If no classloader is given, the root classloader is used. If the initalize argument is passed true, then a given Class will be initialized if it has not been initialized before. We use it in reflection to get a Class object, and we use it in this case to initialize an uninitialized Class. Why do we do that? We’ll use it later

3.2 Service provider framework

Definition: Multiple service providers to implement a service, the system provides multiple implementations for the client service providers and decouples them from the multiple implementations. After reading this definition, a lot of people are confused. It’s abstract and not very easy to understand. If you look at the diagram below, you have two parts in the middle, the service and the service provider. (Source network)

The service providing framework has four components, namely service interface, server provider interface, provider registration API, and service access API.

  • The service interface

Define some methods to provide specific services in the service interface. Suppose we want to provide a registered login service, UserService. There must be login(),register() methods in the service interface. Let’s create a concrete implementation class for the service interface to implement the login(),register() methods.

  • Service provider interface

In the service provider interface, it is the method to define what kind of service to provide. We created a service above that provides “sign in”. So here we must define a method to get the “registered login” service, let’s say getUserService(), return type UserService. GetUserService () then creates the concrete implementation class of the service provider interface. How do we do that? We just need to return a concrete implementation class of UserService.

  • Provider registration API

In fact, you register the API in the implementation class of the service provider interface, in the static initialization block of the class, because you have to register the API to enjoy the service. These registered services are managed by the ServiceManager in a centralized manner.

  • Service Access API

Now that the API has been registered, we can apply for a specific service from a ServiceManager, get an instance of the specific service, and invoke the methods in the service. Service access apis are “flexible static factories” that form the foundation of the service provider framework. Let’s look at an example (using a gift from the project)

3.2.1 The gift service interface is used to provide actionable methods to the outside world

In multi-terminal (multi-application) scenarios, data entities may be different. In this case, we can use the adapter mode to adapt data to ensure consistency between data operation entity and entity table of application database (mapping database, the same below), and separate entity of database. Make the database entity and business entity have single responsibilities

interface GiftService {
    fun saveGift(a)// Adapter mode provides unified entry to data
    fun deleteGift(a)
    fun clearGift(a)
    fun updateGift(a)
    fun getGift(a)
    fun selectGift(a)
}
Copy the code
3.2.2 Service concrete implementation classes exposed to consumers in service providers
class GiftServiceImpl: GiftService {
    override fun saveGift(a) {
        println("Save data")}override fun deleteGift(a){}override fun clearGift(a){}override fun updateGift(a){}override fun getGift(a) {
        println("Got all the gifts.")}override fun selectGift(a){}}Copy the code

The first half of the service provider is OK,

3.2.3 Service provider Interface
/** * Service provider */
interface GiftProvider {
    fun getGiftService(a): GiftService
}
Copy the code
3.2.4 Concrete implementation of service provider interface

In this Class, we will register a service to the service provider, which is written in the Companion Object, in the static code block, so when the Class is loaded with class.forname, the registration will be loaded.

class GiftProviderImpl: GiftProvider {
    override fun getGiftService(a): GiftService {
        return GiftServiceImpl()
    }
    companion object {
        init {
            //JDBC
            GiftManager.registerProvider(RealUSystem.GIFT_SERVICE_NAME, GiftProviderImpl())
        }
    }
}
Copy the code
3.2.5 Service Provider Management
object GiftManager {
    private val provides = ConcurrentHashMap<String, GiftProvider>()

    fun registerProvider(name: String, provider: GiftProvider) {
        provides[name] = provider
    }

    fun getService(name: String): GiftService {
        val provider = provides[name]
        if (provider == null) {
            throw IllegalArgumentException("No provider registered with name = $name")}return provider.getGiftService()
    }
}
Copy the code
3.2.5 use

Generally in Android development will be registered in the Application, other locations can be used

Initialize :(in Application)

Class.forName("com.kpa.system. GiftProviderImpl")
Copy the code

Use: Use the service provider management class to obtain the corresponding service and operate the corresponding method. We will unify its operation in the development

val giftService = GiftManager.getService(RealUSystem.GIFT_SERVICE_NAME)
giftService.saveGift()
giftService.getGift()
Copy the code

4. Data componentization scheme of general type

Using a service provider framework for unified encapsulation, all you really need to do is provide a unified service provider to manage individual data services

Manage individual data services, typically maintained by the developer responsible for data componentization (permission protection)**

  • Service provider
interface DHNServiceProvider {

    fun getGiftService(a): GiftService

    // The purpose for which component data can be reused, user level
    // Think of it as component
    fun getUserService(a): UserService

}
Copy the code
  • Service provider concrete implementation
class DHNServiceProviderImpl : DHNServiceProvider {
    override fun getGiftService(a): GiftService {
        return GiftServiceImpl()
    }

    override fun getUserService(a): UserService {
        return UserServiceImpl()
    }

    companion object {
        init {
            DHNServiceManager.registerProvider(DHNSystem.GIFT_SERVICE_NAME, DHNServiceProviderImpl())
            DHNServiceManager.registerProvider(DHNSystem.USER_SERVICE_NAME, DHNServiceProviderImpl())
        }
    }
}
Copy the code
  • Service manager
object DHNServiceManager {

    val providers = ConcurrentHashMap<String, DHNServiceProvider>()

    fun registerProvider(name: String, provider: DHNServiceProvider) {
        providers[name] = provider
    }

    fun <T> getServer(name: String): T? {
        val dhnServiceProvider = providers[name]
        if (dhnServiceProvider == null) {
            throw IllegalArgumentException("No provider registered with name = $name")}when (name) {
            DHNSystem.GIFT_SERVICE_NAME -> {
                return dhnServiceProvider.getGiftService() as T
            }
            DHNSystem.USER_SERVICE_NAME -> {
                return dhnServiceProvider.getUserService() as T
            }
        }

        return null}}Copy the code

At this point, the data is componentized using the service provider framework, and one might wonder:

  • Adding a data type that requires modifying the provider class is not easy to extend?

For data componentization, this operation is trivial, we have a clear division of labor in componentization development, responsible for data componentization developer maintenance

  • For some components that do not require all data types, registering all services is a waste of memory and increases compilation time.

This is just to show you how to componentize data using a service provider. You can configure it using the Builder pattern so that it is loaded and discarded.

conclusion

We componentize data into a reusable middleware, which can not only consolidate data management, but also solve reuse problems in different components, so data componentization is an essential componentization operation.

The Demo addressGithub.com/kongxiaoan/…