Best practice to hide a service implementation

非 Y 不嫁゛ 提交于 2020-01-14 09:44:47

问题


I want to hide the implementation (concrete class) of a service (interface) from the API user. The implementation is provided to the user by a factory which uses the Java API ServiceLoader mechanism. This Loader requires the implementation class to have public visibility. This is OK as long as the implementation is hidden in a different JAR (apart from the API JAR) the user is not directly depending on.

However, for easy distribution the content of the JAR with the default implementation is packed into the API JAR. So effectively the user depends on this prepacked JAR where the default implementation class is available with public visibility. Nothing keeps people from directly instantiating the implementation. I don't want that to be possible.

My bad ideas:

  • implement an own version of ServiceLoader which allows to load package private implementations (btw, why does the Java API ServiceLoader doesn't allow this?)
  • ship separate API and implementation JARs

What do you think is the right way? Any compromise?

Using OSGi or other heavy machinery is out of question.


回答1:


Disappointing maybe but:

  • Make a separate jar and put that with the other third party jars.
  • Let the installer/the deployment process handle nice packaging of all.
  • Do not make this jar available during compile time; maven: <scope>runtime</scope>.

The only other way would be the have @Deprecated in the javadoc, with as comment how to use the corresponding class using the java service API.




回答2:


In C# you can create an internal interface that is visible only to relevant friend assemblies, and then explicitly implement the interface. I'm not sure how you would do this in Java, but conceptually this is how I've been able to work around this problem in the .NET world.

EDIT I just looked it up, from what I can tell Java doesn't have explicit implementation for interfaces. As an FYI, an explicit implementation of an interface requires you to make a function call through an interface member, you can't call it as a member of the implementing class. This is why my technique works for me, at least in the .NET world.

Alternatively, I would suggest putting the interface in another JAR, and don't distribute it with the API




回答3:


You can't easily prevent people from instantiating/accessing any shipped class.

As such I would perhaps simply wrap the ServiceLoader mechanism that you're using and provide the instantiated class referenced through a Java interface (rather than as a concrete implementation reference).




回答4:


I prefer your first approach, making the implementation class package private, and using a ServiceLoctor to retrieve a specific service. In my project, the package structure is like this:

-package
   |-ServiceInterface(public)
   |-ServiceImplementation(default,package private)
   |-ServiceLocator(public)

The serviceLocator is like this:

public class ServiceLocator{
    private static final Map<String,Service> services;

    static {
         services=new HashMap<String,Service>();
         services.put("default",new ServiceImplementation());//hide implementation
    }
    public Service getService(String name){
         return services.get(name);
    } 

    public registerService(Service service, String name){
         services.put(name,service)
    }
}

The end user does not have access to the implementation class, and in later time, you can easily change to use a different implementation class.



来源:https://stackoverflow.com/questions/16437697/best-practice-to-hide-a-service-implementation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!