利用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(); } } }
毕~