background

There is such a scenario, for the same business, for end users and B end C merchants or management personnel, and side a and B and C using interface ability is different, for example, for the landscape of the electricity market FAQ, maintenance updates by merchants or management personnel, and C end users only see the demand and capacity, and C end user and the manager is not in the same area, the user can In Europe, business and management in domestic, so if the same code in two area deployment, of course, I’ll solve the problem of network latency, but also poses a waste of resources, for the deployment of open service for users in Europe, management relevant interface can never be called to the side, for deployment in the domestic side of service oriented business and management, C end interface is basic We all know that service interfaces and implementations are hosted in the application container, most directly resulting in a waste of resources that deplets memory.

Technical solution

Aimed at the problem of the scenario above, we can put the application of subdivision, distinguish between side a and B and C to solve application way, of course, if in the case of a shortage of manpower and time nervous, we have another plan, do extension based on the ability of the spring framework layer, use the same code on side a and B and C presents different service ability.

1. The packet path distinguishes between interfaces on the C end and interfaces on the B end

When writing interface implementation, according to its service to the user or regional, will end interface C and B end interface and implementation in different package path, such as the FAQ scenarios, C end users only query scenario, we will read and write simple interface separation, query interface in C C end end interface path, B side interface path query and update the interface on the B end, for the cache and The business flow implementation decides whether it needs to be shared as needed.

2. Apply startup scan to distinguish environments and paths

Machines of different room, we can get the room and cluster information, our recognition to the room information in the application startup, and then identify the room the mapping relationship and user groups, scanning and registered interface and the implementation realization of engine room, such as cross-border electricity market, European room C end user oriented, then we will in application startup recognition to the computer room Information, scanning and only register C end users to use the interface and implementation into the container, the side of the interface directly to management oversight, only scan and vice versa for domestic room registration management side of the interface and implementation related to the container, so that you can realize the effective utilization of resources and the ability to give necessary interface controls, can also solve the side a and B and C service you capacity deployment problems such as wrong, such as C The service has high requirements on performance and responsiveness, and the most direct embodiment is the machine performance and node number. The management interface is not sensitive to these indicators, so you can reduce the machine configuration and node number as required.

Another thing, in addition to the engine room registered we also mentioned points environment, so to speak, in addition to the production, development, testing, and gray level (also called pretest) environment is our own in use, it is not necessary to do so complex cluster and room deployment, in most cases are single room with a single machine to deploy, so you need not distinguish room registration services, the same service instance is C Service is also b-side service, that is, when the application is started, we identify the machine room information as well as the environment information. For the non-production environment, we do not distinguish the machine room, and do full scan and registration for the C-side and B-side interface services.

Code implementation

See a property from the ComponentScan annotation:


	/**
	 * Specifies which types are not eligible for component scanning.
	 * @see #resourcePattern
	 */
	Filter[] excludeFilters() default {};
Copy the code

If it is identified from the equipment room and environment information that the API service does not need to be registered in full, the customized Filter is directly used to Filter out the corresponding package path.

1. Customize a packet path filter
@Slf4j
public class CustomScanPackageExcludeFilter implements TypeFilter.EnvironmentAware {

    private static final int idcId = MapUtils.getIntValue(ServerFileUtil.getServerInfo(), "idc_id".0);


    private CurrentEnv currentEnv;

    private boolean shouldNotFilter;

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        if(this.shouldNotFilter) {
            // If the current environment parameters are not injected or not in production environment, do not filter
            return false;
        }
        IdcEnum idcEnum = IdcEnum.getByIdcId(idcId);
        if(null == idcEnum) {
            return false;
        }
        String className = metadataReader.getClassMetadata().getClassName();
        boolean result = idcEnum.getFilter().filter(className);
        log.info("|||||||||||| filter class name={},shouldFilter={}",className,result);
        return result;
    }

    @Override
    public void setEnvironment(Environment environment) {
        String env =  environment.getActiveProfiles()[0];
        log.info("CustomScanPackageExcludeFilter.setEnvironment current env is {}",env);
        this.currentEnv = CurrentEnv.of(env.toLowerCase());
        this.shouldNotFilter = (null== currentEnv || currentEnv.getValue() < CurrentEnv.PROD.getValue()); }}Copy the code

The priority of environment variables is higher than that of equipment rooms. If non-production environments are identified, scan and register them in full. If production environments are identified, register corresponding service capabilities based on equipment room information. Path mapping between the equipment room and the package and filtering

@Getter
@AllArgsConstructor
public enum IdcEnum {
    EU_FILTER_COD_CONSUMER(Arrays.asList(1.2.3),(c) -> c.startsWith("xxx.consumer.api")),
    LOCAL(Arrays.asList(0),(c) -> c.startsWith("xxx.manager.api"));private List<Integer> idcList;

    private IFilter filter;

    private static final Map<Integer,IdcEnum> map = new HashMap<>();

    static {
        for (IdcEnum idcEnum : IdcEnum.values()) {
            for(Integer idcId : idcEnum.getIdcList()) { map.put(idcId,idcEnum); }}}public static final IdcEnum getByIdcId(Integer idcId) {
        returnmap.get(idcId); }}@FunctionalInterface
interface IFilter {

    boolean filter(String className);
}
Copy the code

Note :IdcEnum maintains the equipment room information. The equipment room information is basically unchanged. If it is changed, the information can be changed to dynamic configuration.

2. Enable the user-defined packet filtering capability

Adjust the @ComponentScan configuration item on the startup class:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ComponentScan(basePackages = {"xxx"},excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,classes = CustomScanPackageExcludeFilter.class)})
@Slf4j
public class Application {
    public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

By looking at the production and non-production startup logs, we can see if the corresponding package path is filtered. In addition, if it is filtered, BeanDefinition and instantiation will not be registered, and we can also try to call the interface after startup to verify whether the modification is effective.

conclusion

, of course, we can use a more simple and crude way to replace the transformation, such as C and B end service segment, side interface capability of convergence to C and C applications, B side reserve management ability, the premise is a human resource and time, if you want to transform the relatively small, described this scheme also can yet be regarded as a temporary solution, elegant and the cost is relatively small, only Be familiar with the function principle of @ComponentScan, including filtering and discharging filtering, and the understanding and information extraction of computer room information and application environment information. And this transformation can bring the following benefits:

  1. Save manpower and time resources, do not need to do special c-end and B-end service separation transformation
  2. Solve the problem of unequal machine configuration and node number caused by unequal traffic between TERMINALS C and B
  3. To a certain extent, memory resources are saved. If there are dozens or hundreds of interface services at the C end and THE B end, then the extension room scanning and registration services can save considerable memory resources. For the machine RAM with a lot of land, it is a great benefit