利用java spi技术结合map解耦应用,可作为cglib和jdk动态代理的补充

1.什么是spi?

spi全称为service provider interface 即服务提供接口,它是用来解耦应用的,常在框架中使用。方便后期开发加入新的实现而无需修改代码

2.本例使用spi技术实现了一个container容器,实现了按照类型注入,使用时按照约定传入类即可得到类的实例对象

3.代码实例:

创建一个项目spi,创建三个模块,分别对应接口定义模块spiinterfaces,版本一实现模块spiimplmodle_1和版本二实现模块spiimplmodle_2,以及一个使用方模块spiapp,项目结构如图:

项目需求:实现一个通过拖拽构建web项目的工具,解决项目构建一体化,此处实现拖拽选择前端框架选择,如extjs框架,bootstrap框架

 

 

 3.1 接口定义(spiinterfaces)

package spiinterfaces.scope;

public interface Selector {

    public void select();
    
    public void select(Object obj);
}

3.2 extjs框架集成接口实现模拟(spiimplmodle_1)

package spiimplmodle_1.scope;

import spiinterfaces.scope.Selector;

public class ExtJsSelector implements Selector{

    public void select() {
        System.out.println("from ExtJsSelector.select()");
    }

    public void select(Object obj) {
        System.out.println("from ExtJsSelector.select("+obj.toString()+")");
    }

}

3.3 在src/main/resources目录下新建文件夹META-INF,在META-INF文件夹下新建文件夹services,创建一个文件,命名为spiinterfaces.scope.Selector,内容:(spiimplmodle_1)

spiimplmodle_1.scope.ExtJsSelector

3.4 项目pom.xml(spiimplmodle_1)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.gwb</groupId>
    <artifactId>spi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spiimplmodle_1</artifactId>
  <dependencies>
      <dependency>
          <groupId>com.gwb</groupId>
          <artifactId>spiinterfaces</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
  </dependencies>
</project>

3.5 bootstrap 框架集成实现(spiimplmodle_2)

package sipimplmodle_2.scope;

import spiinterfaces.scope.Selector;

public class BootstrapSelector implements Selector{

    public void select() {
        System.out.println("from BootstrapSelector.select()");
    }

    public void select(Object obj) {
        System.out.println("from BootstrapSelector.select("+obj.toString()+")");
    }

}

3.6  在src/main/resources目录下新建文件夹META-INF,在META-INF文件夹下新建文件夹services,创建一个文件,命名为spiinterfaces.scope.Selector,内容:(spiimplmodle_2)

sipimplmodle_2.scope.BootstrapSelector

3.7 项目pom.xml(spiimplmodle_2)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.gwb</groupId>
    <artifactId>spi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>sipimplmodle_2</artifactId>
  <dependencies>
      <dependency>
          <groupId>com.gwb</groupId>
          <artifactId>spiinterfaces</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
  </dependencies>
</project>

3.8  项目pom.xml(spiapp)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.gwb</groupId>
    <artifactId>spi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spiapp</artifactId>
  <dependencies>
      <dependency>
          <groupId>com.gwb</groupId>
          <artifactId>spiimplmodle_1</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
      <dependency>
          <groupId>com.gwb</groupId>
          <artifactId>sipimplmodle_2</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
  </dependencies>
</project>

3.9 使用spi获取并将实例存入map(spiapp)

package spiapp.consumer;

import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

import spiinterfaces.scope.Selector;

/**
 * 利用spi技术,将单例的接口实现缓存起来,
 * 以类型为键,该类的实例为值,实现接口的解耦
 * @author HUAWEI
 *
 */
public class SelectorFactory {

    private static Map<Class<?>, Selector> cacheMap = new ConcurrentHashMap<Class<?>, Selector>();
    static {
        ServiceLoader<Selector> selector = ServiceLoader.load(Selector.class);
        selector.iterator().forEachRemaining((s)->{
            cacheMap.put(s.getClass(), s);
        });
    }
    public static Selector getSelector(Class<?> key) {
        return cacheMap.get(key);
    }
}

3.9.1 使用jdk代理获取(spiapp)

package spiapp.consumer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Proxy implements InvocationHandler{

    private Object target;

    @Override
    public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
        // TODO Auto-generated method stub
        return arg1.invoke(target, arg2);
    }
    public Object getJDKProxy(Object targetObject){
        //为目标对象target赋值
        this.setTarget(targetObject);
        //JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
        return java.lang.reflect.Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }
    public Object getTarget() {
        return target;
    }
    public void setTarget(Object target) {
        this.target = target;
    }
}

4.0 测试类调用(spiapp)

package spiapp.consumer;

import sipimplmodle_2.scope.BootstrapSelector;
import spiimplmodle_1.scope.ExtJsSelector;
import spiinterfaces.scope.Selector;

public class test {

    public static void main(String[] args) {
        useProxy();
    }
    
    public static void useFactory() {
        Selector selector = SelectorFactory.getSelector(ExtJsSelector.class);
        selector.select();
        Selector selector1 = SelectorFactory.getSelector(BootstrapSelector.class);
        selector1.select("hello spi");
    }
    
    public static void useProxy() {
        try {
            Proxy proxy = new Proxy();
            try {
                
                Selector selector = (Selector) proxy.getJDKProxy(ExtJsSelector.class.newInstance());
                selector.select();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

毕~

posted @ 2021-01-29 10:40  漂渡  阅读(210)  评论(0编辑  收藏  举报