Architecture design - java spi realizes loose coupling between modules

 one. foreword

       In object-oriented design, it is generally recommended to program based on interfaces between modules, and no hard-coding of implementation classes is required between modules. Once a specific implementation class is involved in the code, the principle of pluggability is violated. If an implementation needs to be replaced, the source code needs to be modified, then recompiled and released.

 

        In order to realize that it can not be dynamically specified in the program when the module is assembled, a service discovery mechanism is needed. Java spi is to provide such a mechanism: a mechanism to find a service implementation for an interface. It is somewhat similar to the idea of ​​spring IOC, which is to move the control of the assembly outside the program. This mechanism is especially important in modular design.

 

Many open source projects use this mechanism.

 

      The specific convention of java spi is:

When the service provider provides an implementation of the service interface, a file named after the service interface is also created in the META-INF/services/ directory of the jar package. This file is the concrete implementation class that implements the service interface. When an external program assembles this module, it can find the specific implementation class name through the configuration file in the jar package META-INF/services/, and load and instantiate it to complete the injection of the module. Based on such a convention, the implementation class of the service interface can be found very well, and there is no need to formulate it in the code.

 This is how java.sql.Driver is implemented, and we can see how mysql extends it.

   

 Open the jdbc jar package of mysql, there is a java.sql.Drvier file under META-INF/services,


 

The contents of the file are as follows:

 

 

two. Example development

In the code, how to use java's spi mechanism, then we need to use java.util.ServiceLoader.

The development steps are as follows:

1. Write an interface

2. Write the implementation class of the interface

3. Create a new file under /src/META-INF/services, the file name is the package name of the interface + the interface name, if it is a maven build, it is in src/main/resources/META-INF/services

4. Write the full name of the implementation class in the file, one implementation class occupies one line.

 

 

package com.wxj.spi;

/**
 * save interface
 * @author wxj
 *
 */
public interface Store
{

	/**
	 * save data
	 * @param data data
	 * @return whether the save was successful
	 */
	public boolean store(Object data);
	
}

 

 

package com.wxj.spi;

/**
 * Save data with file
 * @author wxj
 *
 */
public class FileStore implements Store
{

	@Override
	public boolean store(Object data)
	{
		System.out.println("file store successfully");
		return true;
	}

}
 

 

 

package com.wxj.spi;

/**
 * Save data in database
 * @author wxj
 *
 */
public class DBStore implements Store
{

	@Override
	public boolean store(Object data)
	{
		System.out.println("db store successfully");
		return true;
	}

}
 

 

 File content of src/META-INF/services/com.wxj.spi.Store:

com.wxj.spi.FileStore
com.wxj.spi.DBStore
 

 

test class

 

package com.wxj.spi;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
 * test class
 * @author wxj
 *
 */
public class TestStore
{
	
	public static void main(String[] args)
	{
		ServiceLoader<Store> stores = ServiceLoader.load(Store.class);
		Iterator<Store> it = stores.iterator();
		Store s = null;
		String data = "datas";
		while(it.hasNext())
		{
			s = it.next();
			s.store(data);
		}
	}

}
测试结果:
file store successfully
db store successfully
  

 问题

问题1:为什么配置文件要放在META-INF/services下面?

问题2:java.util.ServiceLoader是如何找到这些实现类的?

 

三。java.util.ServiceLoader源码分析
 

 



 



 

看完这段代码,相信都明白是怎么回事了。

 

1. META-INF/services这个路径在ServiceLoader的源码中就写死了。

2. ServiceLoader通过懒加载的方式去读services路径下的文件内容,然后通过class.forName()反射的方式生成接口对应的实现类。

 

 四。API与SPI的区别与联系

1. API直接为你提供了功能,你使用API就能完成任务。
2. SPI是一种回调的思想,回调是指我们在使用api时,我们可以向api传入一个类或者方法,api在合适的时间调用类或者方法。
3. SPI是在一些通用的标准中,为标准的实现产商提供的扩展点。标准在上层提供API,API内部使用了SPI,当API被客户使用时,会动态得从当前运行的classpath中寻找该SPI的实现,然后使用该SPI的实现来完成API的功能。
 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326510725&siteId=291194637