电子商务网站建设方面的论文市场营销策略模板
news/
2025/9/23 2:42:13/
文章来源:
电子商务网站建设方面的论文,市场营销策略模板,常德网站建设开发哪家好,做网络销售如何找客户文章目录 前言ClassLoaderJAVA SPI机制Spring SPI机制示例原理 如何加载jar包里的class 前言
Java的SPI机制与Spring中的SPI机制是如何实现的#xff1f;
ClassLoader
这里涉及到了class Loader的机制#xff0c;有些复杂#xff0c;jdk中提供默认3个class Loader#x… 文章目录 前言ClassLoaderJAVA SPI机制Spring SPI机制示例原理 如何加载jar包里的class 前言
Java的SPI机制与Spring中的SPI机制是如何实现的
ClassLoader
这里涉及到了class Loader的机制有些复杂jdk中提供默认3个class Loader
Bootstrap ClassLoader加载jdk核心类库加载%JAVA_HOME\lib%下的jarExtClassLoader加载jdk扩展类库加载%JAVA_HOME\lib\ext%下的jarAppClassLoader加载classpath下的class以及关联到maven仓库里的jar
AppClassLoader和ExtClassLoader父类都是URLClassLoader我们自定义也是继承URLClassLoader进行扩展的
所以当我们使用类加载器加载资源时它会找上面这些路径而AppClassLoader是找当前执行程序的classpath也就是我们target/classes目录如果有是maven引用了其他依赖包那么也会将maven地址下的依赖包的路径加到AppClassLoader的URL里如果是多模块的项目还会把引用的其他模块下target/classes的目录也加进来。 JAVA SPI机制
Java中提供的SPI机制是通过读取META-INF/services/目录下的接口文件从而加载到实现类。
其规则如下
规定号开放api实现提供方需要依赖开发接口完成实现例如msyql实现提供方resource下提供META-INF/services/接口全名文件内容为实现类
例如下面这个 重现建一个项目app用来测试 定义接口plugin-api打成jar包 /*** author ALI* since 2023/6/30*/
public interface Plugin {Object run(Object data);
} 定义实现然后打成jar包 /*** author ALI* since 2023/6/30*/
public class PluginImpl implements Plugin {Overridepublic Object run(Object data) {Motest motest new Motest();System.out.println(motest.getName());System.out.println(data);return null;}
}/*** author ALI* since 2023/6/30*/
public class Motest {private String name;public Motest() {name sss;}public String getName() {return name;}
} 这里我还定义了一个其他的类用来测试再load class时是否会加载。 在新项目中加载jar中的资源引入plugin-api /*** 使用jar的classLoader*/private static void load2() throws Exception{String jarPath E:/workspace/git/test-plugin/app/target/classes/plugin-impl-1.0-SNAPSHOT.jar;URLClassLoader jarUrlClassLoader new URLClassLoader(new URL[]{new URL(file: jarPath)});// ServerLoader搜索ServiceLoaderPlugin load ServiceLoader.load(Plugin.class, jarUrlClassLoader);IteratorPlugin iterator load.iterator();while (iterator.hasNext()) {// 实例化对象这里会进行加载Class.forName然后反射实例化Plugin next iterator.next();next.run(sdsdsdsds);}}这里使用ServiceLoader时传入了jarClassLoader开篇已经解释过了因为类加载器的原因不会加载我们自定义的jar包所以手动创建类加载器。 结果已经很显而易见已经成功加载了这种方式的划会加载jar包里实现了接口的所有实现类这个方式使用也是很方便的。 使用URLClassLoader加载class
Spring SPI机制
在Spring中它的SPI机制和JAVA 中的类似需要这样的条件 定义接口模块包用于开发给第三方实现 第三方要有resources\META-INF\spring.factories文件其内容是键值对方式key为接口类value就是我们的实现类
而Spring执行就是获取到文件里的value然后反射实例化。
示例
定义接口模块 定义第三方实现组件并配置spring.factoryies 项目中引入接口模块组件和实现组件 结果
原理
loadFactories两个参数
Class factoryType用于反射实例化
ClassLoader classLoader用于加载资源所有这里可以直接使用URLClassLoader指定jar的类加载如果不指定就是它自己本身的类加载 public static T ListT loadFactories(ClassT factoryType, Nullable ClassLoader classLoader) {Assert.notNull(factoryType, factoryType must not be null);ClassLoader classLoaderToUse classLoader;if (classLoaderToUse null) {// 如果为空它用自己的加载器classLoaderToUse SpringFactoriesLoader.class.getClassLoader();}// 这里就是加载spring.factories文件里的value值// 找出所有的实现类的类路径ListString factoryImplementationNames loadFactoryNames(factoryType, classLoaderToUse);if (logger.isTraceEnabled()) {logger.trace(Loaded [ factoryType.getName() ] names: factoryImplementationNames);}ListT result new ArrayList(factoryImplementationNames.size());// 遍历找出来的类然后通过反射实例化for (String factoryImplementationName : factoryImplementationNames) {result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));}// 排序AnnotationAwareOrderComparator.sort(result);return result;}
这里看一下 public static ListString loadFactoryNames(Class? factoryType, Nullable ClassLoader classLoader) {// 将接口类转化成类路径如com.liry.pluginapi.PluginString factoryTypeName factoryType.getName();// 先获取到spring.factories里的键值对map,然后再getreturn loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static MapString, ListString loadSpringFactories(Nullable ClassLoader classLoader) {// 缓存程序运行中需要多次获取MultiValueMapString, String result cache.get(classLoader);if (result ! null) {return result;}try {// 通过类加载获取所有资源地址urlEnumerationURL urls (classLoader ! null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result new LinkedMultiValueMap();// 遍历while (urls.hasMoreElements()) {URL url urls.nextElement();UrlResource resource new UrlResource(url);// 通过PropertiesLoaderUtils工具获取spring.factories里的键值对Properties properties PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry?, ? entry : properties.entrySet()) {String factoryTypeName ((String) entry.getKey()).trim();// 将value通过逗号分隔成数组然后再全部添加到结果集中for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}// 加入缓存cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException(Unable to load factories from location [ FACTORIES_RESOURCE_LOCATION ], ex);}}
注意MultiValueMap这个map相同的key不会覆盖value而是组成链表如下一个key可以有多个value逗号分隔 public void add(K key, Nullable V value) {ListV values this.targetMap.computeIfAbsent(key, k - new LinkedList());values.add(value);}如何加载jar包里的class
假设需要获取一个jar包里的class该如何
如下4个步骤即可 public static void main(String[] args) throws Exception {String packageName com.liry.springplugin;// 1. 转换为 com/liry/springpluginString packagePath ClassUtils.convertClassNameToResourcePath(packageName);// 2. 通过类加载器加载jar包URL
// ClassLoader classLoader Test.class.getClassLoader();ClassLoader classLoader new URLClassLoader(new URL[]{new URL(file:E:\\workspace\\git\\test-plugin\\spring-plugin\\target\\spring-plugin-1.0-SNAPSHOT.jar)});URL resources classLoader.getResource(packagePath);// 3. 打开资源通道JarFile jarFile null;URLConnection urlConnection resources.openConnection();if (urlConnection instanceof java.net.JarURLConnection) {java.net.JarURLConnection jarURLConnection (java.net.JarURLConnection) urlConnection;jarFile jarURLConnection.getJarFile();}// 定义一个结果集ListString resultClasses new ArrayList();// 4. 遍历资源文件EnumerationJarEntry entries jarFile.entries();while (entries.hasMoreElements()) {JarEntry entry entries.nextElement();// 文件全路径String path entry.getName();// 判断是否在指定包路径下jar包里有多层目录、MF文件、class文件等多种文件信息if (path.startsWith(packagePath)) {// 使用spring的路径匹配器匹配class文件if (path.endsWith(.class)) {resultClasses.add(path);}}}resultClasses.forEach(System.out::println);}说明一下加载jar包的问题
上面给出了两种方式
第一种使用类加载加载
ClassLoader classLoader Test.class.getClassLoader();第二种使用URLClassLoader加载
ClassLoader classLoader new URLClassLoader(new URL[]{new URL(file:E:\\workspace\\git\\test-plugin\\spring-plugin\\target\\spring-plugin-1.0-SNAPSHOT.jar)});这两种方式不同之处在于查找jar的路径第一种方式因为我测试项目使用的maven在pom.xml里引入了spring-plugin-1.0-SNAPSHOT的包所以才能通过类加载器直接进行加载这是因为使用mavenmaven引用的依赖路径会被加入到AppClassLoader种然后使用Test.class.getClassLoader()去加载class时会委派给AppClassLoader进行加载才会加载到。
所以如果不是在maven种引入的包使用第二种方式。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/911144.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!