`

ServiceLoader

 
阅读更多
package ycl.learn.effective.java;

public interface ServiceAPI {

	/**
	 * translate context to appropriate language.
	 * 
	 * @param content
	 * @return
	 */
	public String translate(String content);
	 
}



package ycl.learn.effective.java;

public class ChineseServiceSPI  implements ServiceAPI{

	public String translate(String content) {
		String trans = content.equals("Ch")?"Chinese":null;
		return trans;
	} 
	
}



package ycl.learn.effective.java;

public class EnglishServiceSPI  implements ServiceAPI{

	public String translate(String content) { 
		String trans = content.equals("En")?"Englis":null;
		return trans;
	}

}



package ycl.learn.effective.java;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ServiceLoader;
 
  
public class BaseServiceSPI{
 
	private ServiceLoader<ServiceAPI> sl;
	
	public BaseServiceSPI(ServiceLoader<ServiceAPI> sl){
		this.sl = sl;
	}
	
	/**
	 * just find first one implement.
	 * 
	 * @param clazz
	 * @return
	 * @throws Exception
	 */
    public static Object findServiceProvider(Class clazz) throws Exception  
    {
    	String factoryId =clazz.getName();
        String serviceId = "META-INF/services/" + factoryId;
        InputStream is = null;
        
        // First try the Context ClassLoader
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl != null) {
            is = cl.getResourceAsStream(serviceId);
        } else {
            // No Context ClassLoader, try the current ClassLoader
            cl = BaseServiceSPI.class.getClassLoader();
            is = cl.getResourceAsStream(serviceId);
        }
        
        if (is == null) {
            // No provider found
            return null;
        }
         
        
        BufferedReader rd;
        try {
            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        } 
        catch (java.io.UnsupportedEncodingException e) {
            rd = new BufferedReader(new InputStreamReader(is));
        }
        
        String factoryClassName = null;
        try {
            // XXX Does not handle all possible input as specified by the
            // Jar Service Provider specification
            factoryClassName = rd.readLine();
            rd.close();
        } catch (IOException x) {
            // No provider found
            return null;
        }
        
        if (factoryClassName != null && !"".equals(factoryClassName)) { 
            
            // Note: here we do not want to fall back to the current
            // ClassLoader because we want to avoid the case where the
            // resource file was found using one ClassLoader and the
            // provider class was instantiated using a different one.
        	Object p = clazz.cast(Class.forName(factoryClassName, true, cl)
 				   .newInstance());
            return p;
        }
        
        // No provider found
        return null;
    }
    
	
	/**
	 * auto match method
	 * 1. if that is multiple implements, and you just want to auto choose.
	 * 
	 * rule
	 *  *. sub class method is return null, if this params is not match of this process.
	 *  *. sub class method will be return not null, if this params is match of this process.
	 * 
	 * @param content
	 * @return
	 */
	public String translate(String content) {
		for(ServiceAPI serviceAPI: sl){
			String trans = serviceAPI.translate(content);
			if(trans != null){
				return trans;
			}
		}
		return null;
	}
 

}



package ycl.learn.effective.java;

import java.util.ServiceLoader;

public class TestServiceLoader {

	public static void main(String args[]) throws Exception{
		ServiceLoader<ServiceAPI> sl = ServiceLoader.load(ServiceAPI.class);
		BaseServiceSPI bs = new BaseServiceSPI(sl);
		//auto choose implements.
		//in this situation , you can add more and more implements.
		//as like add Languages.
		
		//also the JDK components use Service Loader to implements.
		//you can read javax.xml.parsers.FactoryFinder
		//             javax.xml.parsers.SAXParserFactory
		//             javax.xml.parsers.DocumentBuilderFactory
		// 1. System property
		// 2. jdk-dir/lib/jaxp.properties set default implements
		//javax.xml.parsers.DocumentBuilderFactory javax.xml.parsers.SAXParserFactory
		// 3. META-INF/services/javax.xml.parsers.DocumentBuilderFactory ==> org.apache.crimson.jaxp.DocumentBuilderFactoryImpl
		// 4. if haven't find,user Crimson。ClassNotFound
		// summary, so you know what's xml parser you shoud be to use.
		//  "javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
		//  "javax.xml.parsers.DocumentBuilderFactory" "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"
		// you can have multiple implements at one time, but you just choose one implement is ok.
		 System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl");
		 
		System.out.println(bs.translate("Ch"));
		System.out.println("===");
		System.out.println(bs.translate("En")); 
		
		// that's right, you can just get one implements as below. 
		// you also can get all impements use rules to choose right one.
		ServiceAPI serviceAPI = (ServiceAPI) BaseServiceSPI.findServiceProvider(ServiceAPI.class);
		System.out.println(serviceAPI.translate("Ch"));
		System.out.println("hahaah");
		System.out.println(serviceAPI.translate("En")); 
		 
	}
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics