国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java Service Provider Interface

jaysun / 2714人閱讀

摘要:之前的作用范圍其中驅動通常使用來引入所需要的驅動。在編譯期間不用引入具體的具體實現類不管還是等。所以包的應該設置為。用于從中找到接口的實現類。文件中有兩個驅動名。而不是通過來找實現類的。是通過找一個固定包下的固定類類而是找固定文件下的內容。

之前

maven 的runtime作用范圍

其中JDBC驅動通常使用Class.forName("com.mysql.jdbc.Driver");來引入所需要的驅動。在編譯期間不用引入具體jdbc的具體實現類(不管mysql還是oracle等)。所以JDBC包的scope應該設置為runtime。


    mysql
    mysql-connector-java
    ${mysql.driver.version}
    runtime

JDBC4之后使用SPI技術 也不用寫Class.forName了

Service Provider Interface

Java API提供的使用ServiceLoader來實現的控制反轉工具類。用于從classpath中找到接口的實現類。

先定義一個接口

package ch.frankel.blog.serviceloader;

public interface Foo {
}

再定義兩個實現類(實現類可能是其他工程中定義的)

package ch.frankel.blog.serviceloader;

public class FooImpl1 implements Foo {
}

public class FooImpl2 implements Foo {
}

然后在Resources/META-INF下的service中新建一個與接口名對應的文件ch.frankel.blog.serviceloader.Foo

ch.frankel.blog.serviceloader.FooImpl1
ch.frankel.blog.serviceloader.FooImpl2

serviceLoader會從該文件中找到要加載的類。

public class JavaServiceLoaderTest {

    @Test
    public void java_service_loader_should_load_correct_implementations() {
        //Service.load會從ch.frankel.blog.serviceloader.Foo中找到要加載的類,然后加載。
        ServiceLoader loader = ServiceLoader.load(Foo.class);
        List foos = new ArrayList<>();
        loader.iterator().forEachRemaining(foos::add);
        assertThat(foos)
                .isNotNull()
                .isNotEmpty()
                .hasSize(2);
    }
}
Spring 集成 ServiceLoader

首先需要配置對應的factoryBean

@Configuration
public class ServiceConfiguration {
    @Bean
    public ServiceListFactoryBean serviceListFactoryBean() {
        ServiceListFactoryBean serviceListFactoryBean = new ServiceListFactoryBean();
        serviceListFactoryBean.setServiceType(Foo.class);
        return serviceListFactoryBean;
    }
}

然后通過ServiceListFactoryBean就可以找到接口對應的實現類。

@ContextConfiguration(classes = ServiceConfiguration.class)
public class ServiceLoaderWithSpringTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private ServiceListFactoryBean serviceListFactoryBean;

    @Test
    public void spring_service_loader_integration_should_load_correct_implementations() throws Exception {
        Object object = serviceListFactoryBean.getObject();
        Assertions.assertThat(object)
                .isNotNull()
                .asList()
                .isNotEmpty()
                .hasSize(2);
    }
}
Spring Facotories Loader

spring 自己也提供了類似的工具類。使用起來更方便。

首先在META-INF下建立一個spring.factories文件。

ch.frankel.blog.serviceloader.Foo=ch.frankel.blog.serviceloader.FooImpl1,ch.frankel.blog.serviceloader.FooImpl2

直接指定接口對應的實現類。

然后通過Spring提供的靜態方法SpringFactoriesLoader就可以直接使用了。

public class SpringFactoriesTest {

    @Test
    public void spring_factories_should_load_correct_implementations() {
        List foos = SpringFactoriesLoader.loadFactories(Foo.class, null);
        assertThat(foos)
                .isNotNull()
                .isNotEmpty()
                .hasSize(2);
    }
}
Service Provider Interface的應用 JDBC SPI

查看jdbc的代碼

//java.sql.DriverManager
public class DriverManager {
    /**
     * Load the initial JDBC drivers by checking the System property
     * jdbc.properties and then use the {@code ServiceLoader} mechanism
     */
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    
    private static void loadInitialDrivers() {
        String drivers;
        try {
            drivers = AccessController.doPrivileged(new PrivilegedAction() {
                public String run() {
                    //從系統變量中獲取jdbc.drivers
                    //System.getProperty 可以在vm arguments中設置。java -Djdbc.drivers=xxxx
                    return System.getProperty("jdbc.drivers");
                }
            });
        } catch (Exception ex) {
            drivers = null;
        }
        // If the driver is packaged as a Service Provider, load it.
        // Get all the drivers through the classloader
        // exposed as a java.sql.Driver.class service.
        // ServiceLoader.load() replaces the sun.misc.Providers()

        AccessController.doPrivileged(new PrivilegedAction() {
            public Void run() {

                ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator driversIterator = loadedDrivers.iterator();

                /* Load these drivers, so that they can be instantiated.
                 * It may be the case that the driver class may not be there
                 * i.e. there may be a packaged driver with the service class
                 * as implementation of java.sql.Driver but the actual class
                 * may be missing. In that case a java.util.ServiceConfigurationError
                 * will be thrown at runtime by the VM trying to locate
                 * and load the service.
                 *
                 * Adding a try catch block to catch those runtime errors
                 * if driver not available in classpath but it"s
                 * packaged as service and that service is there in classpath.
                 */
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });

        println("DriverManager.initialize: jdbc.drivers = " + drivers);

        if (drivers == null || drivers.equals("")) {
            return;
        }
        //多個drivers?
        String[] driversList = drivers.split(":");
        println("number of Drivers:" + driversList.length);
        for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                //還是使用Class.forName來加載驅動
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }
    }

}

在jdbc的實現包中META-INF下有java.sql.Driver文件。

com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver

文件中有兩個驅動名。

其實jdbc可以同時管理多個驅動,(jdbc詳解:2、DriverManager管理多個數據庫驅動)

Commons-Logging
//org.apache.commons.logging.LogFactory#getFactory
public static LogFactory getFactory() throws LogConfigurationException {
    
        ...

        // Second, try to find a service by using the JDK1.3 class
        // discovery mechanism, which involves putting a file with the name
        // of an interface class in the META-INF/services directory, where the
        // contents of the file is a single line specifying a concrete class 
        // that implements the desired interface.

        if (factory == null) {
            if (isDiagnosticsEnabled()) {
                logDiagnostic(
                        "[LOOKUP] Looking for a resource file of name [" + SERVICE_ID
                        + "] to define the LogFactory subclass to use...");
            }
            try {
                InputStream is = getResourceAsStream(contextClassLoader,
                                                     SERVICE_ID);

                if( is != null ) {
                    // This code is needed by EBCDIC and other strange systems.
                    // It"s a fix for bugs reported in xerces
                    BufferedReader rd;
                    try {
                        rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                    } catch (java.io.UnsupportedEncodingException e) {
                        rd = new BufferedReader(new InputStreamReader(is));
                    }

                    String factoryClassName = rd.readLine();
                    rd.close();

                    if (factoryClassName != null &&
                        ! "".equals(factoryClassName)) {
                        if (isDiagnosticsEnabled()) {
                            logDiagnostic(
                                    "[LOOKUP]  Creating an instance of LogFactory class " + factoryClassName
                                    + " as specified by file "" + SERVICE_ID 
                                    + "" which was present in the path of the context"
                                    + " classloader.");
                        }
                        factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader );
                    }
                } else {
                    // is == null
                    if (isDiagnosticsEnabled()) {
                        logDiagnostic(
                            "[LOOKUP] No resource file with name "" + SERVICE_ID
                            + "" found.");
                    }
                }
            } catch( Exception ex ) {
                // note: if the specified LogFactory class wasn"t compatible with LogFactory
                // for some reason, a ClassCastException will be caught here, and attempts will
                // continue to find a compatible class.
                if (isDiagnosticsEnabled()) {
                    logDiagnostic(
                        "[LOOKUP] A security exception occurred while trying to create an"
                        + " instance of the custom factory class"
                        + ": [" + ex.getMessage().trim()
                        + "]. Trying alternative implementations...");
                }
                ; // ignore
            }
        }
    
    ...
}

其中也使用到SPI。從 META-INF/services/org.apache.commons.logging.LogFactory中找要加載的實現類(Apache Commons Logging 是如何決定使用哪個日志實現類的)。

slf4j

而slf4j不是通過SPI來找實現類的。slf4j 1.7是通過找一個固定包下的固定類StaticLoggerBinder類(而SPI是找固定文件下的內容)。這個類定義在各個實現包中。

貌似slf4j 1.8 開始使用SPI了,如下圖。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71203.html

相關文章

  • SpringCloud(第 041 篇)鏈接Mysql數據庫,通過JdbcTemplate編寫數據庫

    摘要:通過注解引入對象。添加一個使用接收請求添加賬號訪問層添加微服務啟動類鏈接數據庫通過編寫數據庫訪問。 SpringCloud(第 041 篇)鏈接Mysql數據庫,通過JdbcTemplate編寫數據庫訪問 - 一、大致介紹 1、前面章節提到了JPA操作訪問數據庫,本章節我們講解一下如何用JdbcTemplate操作訪問數據庫; 2、使用JdbcTemplate是一個相對更底層的操作,可...

    Eirunye 評論0 收藏0
  • 【Effective Java】創建和銷毀對象

    摘要:一考慮用靜態工廠方法代替構造器構造器是創建一個對象實例的最基本最常用的方法。開發者在使用某個類的時候,通常會使用一個構造器來實現,其實也有其他方式可以實現的,如利用發射機制。 一、考慮用靜態工廠方法代替構造器 構造器是創建一個對象實例的最基本最常用的方法。開發者在使用某個類的時候,通常會使用new一個構造器來實現,其實也有其他方式可以實現的,如利用發射機制。這里主要說的是通過靜態類工...

    Hwg 評論0 收藏0
  • SpringCloud(第 044 篇)鏈接Mysql數據庫簡單的集成Mybatis框架采用Mapp

    摘要:添加用戶接口類實現類簡單用戶鏈接數據庫微服務通過注解標注該類為持久化操作對象。添加一個使用接收請求添加微服務啟動類鏈接數據庫簡單的集成框架采用訪問數據庫。 SpringCloud(第 044 篇)鏈接Mysql數據庫簡單的集成Mybatis框架采用MapperXml訪問數據庫 - 一、大致介紹 1、前面章節講解的是在方法上面添加sql語句操作,雖然說僅僅只是一種簡單的操作,在測試期間可...

    smartlion 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<