上海电商网站开发公司,wordpress自动回复插件,大腕 网站建设,app开发平台开发我时不时地发现自己摸索了一些旧的代码#xff0c;以找到示例“我在哪里做过工厂一样的事情”。 上周再次发生这种情况时#xff0c;我决定只查找所有示例#xff0c;并创建一个示例项目和有关它的博客文章。 所以在这篇文章中#xff0c;我#xff1a; 从简单的“原始… 我时不时地发现自己摸索了一些旧的代码以找到示例“我在哪里做过工厂一样的事情”。 上周再次发生这种情况时我决定只查找所有示例并创建一个示例项目和有关它的博客文章。 所以在这篇文章中我 从简单的“原始” Java SE工厂示例开始 然后使用Java SE SPI Java SE上的CDI Java EE上的 CDI Java EE上的EJB Java SE上的动态SPI 最后是Java EE上的SPI 这个例子 这个示例应用程序是一个非常简单的“ Hello World”您可以输入名称并且有多种表达问候的方法。 Greeting Service获取Greeting Factory的实例。 然后它可以按名称要求工厂提供Greeting 接口然后工厂将返回正确的实现。 有3种具体的实现方式 English将打招呼“好日子名字” 。 Afrikaans将打招呼“ Goeie dag name” 。 请参阅https://www.youtube.com/watch?vCtxB4sbV0pA Bugs Bunny会打招呼“ Eeee 叫什么名字 ” 请参阅https://www.youtube.com/watch?vUeVtZjGII-I Github中提供了此博客的所有源代码 git clone https://github.com/phillip-kruger/factories-example 问候界面 public interface Greeting {public String getName();public String sayHello(String to);}香草 这个基本的Java SE应用程序有一个主要方法该方法可让您传递名称和希望打招呼的方式。 工厂是获得正确实现的基本if-statement public Greeting getGreeting(String name){if(name.equalsIgnoreCase(BugsBunny)){return new BugsBunny();}else if(name.equalsIgnoreCase(Afrikaans)){return new Afrikaans();}else {return new English();}} 一个具体的实现示例 英语 public class English implements Greeting {Overridepublic String sayHello(String to) {return Good day to .;}Overridepublic String getName() {return English;}}运行示例 在vanilla文件夹中 mvn clean install 这将构建项目并运行该应用程序。 日志将输出 SEVERE: Good day Phillip.Goeie dag Phillip.Eeee, whats up Phillip ? 您也可以在Maven之外运行此命令 java -jar target/vanilla-1.0.0-SNAPSHOT.jar World BugsBunnySEVERE: Eeee, whats up World ?另见 https://alvinalexander.com/java/java-factory-pattern-example 服务提供商接口SPI 上面的示例意味着我可以非常轻松地添加另一个实现并在询问时更新if statement以返回该实现。 但是我们要改进的是if-statement 。 我们希望可以在不修改现有代码的情况下添加新的实现。 我要做的就是添加新的实现。 SPI是Java SE的一部分是允许您构建可插入扩展的API。 将应用程序分解为模块。 我们要做的第一件事是将应用程序分解为模块 API –这将包含Greeting接口我们的合同 引擎–其中将包含服务和工厂以及默认的英语实现 其他实现–所有其他实现都变成了自己的模块因此一种用于南非荷兰语另一种用于Bugs Bunny等 这已经意味着我可以通过创建一个新模块来添加新的实现而不必触摸代码只需更新依赖项即可 dependenciesdependencygroupId${project.groupId}/groupIdartifactIdspi-api/artifactIdversion${project.version}/version/dependencydependencygroupId${project.groupId}/groupIdartifactIdspi-impl-afrikaans/artifactIdversion${project.version}/version/dependencydependencygroupId${project.groupId}/groupIdartifactIdspi-impl-bugsbunny/artifactIdversion${project.version}/version/dependency/dependencies映射文件 具体的实现需要通过在/src/main/resources/META-INF/services/添加一个文件com.github.phillipkruger.factory.api.Greeting 接口的全限定名将其Greeting类注册为实现。 文件的内容是实现的名称例如Bugs Bunny com.github.phillipkruger.factory.impl.BugsBunny该工厂 工厂现在需要获取所有Greetings实例 ServiceLoaderGreeting loader ServiceLoader.load(Greeting.class);IteratorGreeting greetingIterator loader.iterator();while (greetingIterator.hasNext()) {Greeting greeting greetingIterator.next();loadedGreetings.put(greeting.getName(), greeting);} 现在我们摆脱了工厂中的if-statement 。 运行示例 在spi文件夹中 mvn clean install 这将构建项目并运行该应用程序。 日志将输出 SEVERE: Good day Phillip.Goeie dag Phillip.Eeee, whats up Phillip ? 您也可以在Maven之外运行此命令 java -jar spi-engine/target/spi-engine-1.0.0-SNAPSHOT-jar-with-dependencies.jar Johny AfrikaansSEVERE: Goeie dag Johny.另见 https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html 上下文和依赖注入CDI 最新版本的CDI允许您在Java SE中使用CDI。 为了创建工厂我们将创建自己的注释作为称为GreetingProvider的API的一部分 QualifierRetention(RetentionPolicy.RUNTIME)Target(ElementType.TYPE)public interface GreetingProvider {String value();} value是实现的名称。 以上的文字实现 AllArgsConstructorpublic class GreetingProviderLiteral extends AnnotationLiteralGreetingProvider implements GreetingProvider {private final String name;Overridepublic String value() {return this.name;}} 这将允许我们使用GreetingProvider注释任何具体的实现现在是RequestScoped CDI Bean例如英语 GreetingProvider(English)RequestScopedpublic class English implements Greeting {Overridepublic String sayHello(String to) {return Good day to .;}Overridepublic String getName() {return English;}} 工厂更改以查找所有GreetingProvider类 public class GreetingFactory {Inject Anyprivate InstanceGreeting greetings;public Greeting getGreeting(String name) {InstanceGreeting instance greetings.select(new GreetingProviderLiteral(name));if(!instance.isUnsatisfied()){Greeting provider instance.get();return provider;}else{return new English();}}} 因此现在我们不再需要SPI映射文件工厂中没有if-statement 但是我们仍然必须更新依赖项以包含所需的所有实现。 运行示例 在cdi文件夹中 mvn clean install 这将构建项目并运行该应用程序。 日志将输出 SEVERE: Good day Phillip.Goeie dag Phillip.Eeee, whats up Phillip ? 您也可以在Maven之外运行此命令 java -jar cdi-engine/target/cdi-engine-1.0.0-SNAPSHOT-jar-with-dependencies.jar Charmaine BugsBunnySEVERE: Eeee, whats up Charmaine ?另见 http://www.mastertheboss.com/jboss-frameworks/cdi/building-a-cdi-2-standalone-java-application http://www.adam-bien.com/roller/abien/entry/injecting_classes_in_java_se Java EE上的CDI 我们还可以使用CDI在Application Server上创建解决方案。 现在我们将入口点设为REST服务而不是主要方法因此我们需要创建并添加ApplicationConfig来启用JAX-RS ApplicationPath(/api)public class ApplicationConfig extends Application {} GreetingService现在成为REST资源使您可以执行GET 将名称作为PathParam传递以及将可选方式作为QueryParam进行问候 Path(/)Produces(MediaType.APPLICATION_JSON)public class GreetingService {Injectprivate GreetingFactory factory;GETPath({to})public String sayHello(PathParam(to) String to, QueryParam(way) ListString way){//....}} 工厂和带注释的RequestScoped CDI Bean实现与Java SE示例上的CDI完全相同。 运行示例 该示例可以在3个不同的应用程序服务器上运行为诚实起见 野蜂群 开放自由 Payara Micro 您不必下载安装或配置任何东西Maven构建会做到这一点 在javaee-cdi文件夹中 mvn clean install -P wildfly 要么 mvn clean install -P liberty 要么 mvn clean install -P payara 在所有3种情况下maven都会 在部署了应用程序的情况下启动应用程序服务器 击中2个REST网址 http// localhost8080 / javaee-cdi-engine / api 此列表所有实现 关闭应用程序服务器Payara除外 因此在日志中您将看到类似
[BugsBunny,Afrikaans,English][Eeee, whats up Phillip ?,Goeie dag Phillip.,Good day Phillip.]如果运行Payara则服务器不会关闭因此您也可以手动测试工厂 wget -qO- http://localhost:8080/javaee-cdi-engine/api/Donald?wayBugsBunny[Eeee, whats up Donald ?]Java EE上的EJB 只是为了完成示例这是在Java EE上使用EJB的方法因此没有CDI –因此也没有自定义注释 我们仅使用JNDI查找命名的EJB。 GreetingService与Java EE CDI示例相同因此我们仍然有一个REST入口点。 现在具体的实现变为EJB例如英语 StatelessEJB(beanInterface Greeting.class, beanName English, name English)public class English implements Greeting {Overridepublic String sayHello(String to) {return Good day to .;}Overridepublic String getName() {return English;}} 现在 工厂将基于bean名称进行JNDI查找 LogStatelesspublic class GreetingFactory {EJB(lookup java:module/English)private Greeting english; // defaultpublic Greeting getGreeting(String name) {Greeting g lookup(java:module/ name);if(gnull)return english;return g;}public ListGreeting getAll(){ListGreeting greetings new ArrayList();try {InitialContext context new InitialContext();NamingEnumerationBinding list (NamingEnumerationBinding)context.listBindings(java:global/javaee-ejb-engine); while (list.hasMore()) {Binding next list.next();if(next.getName().endsWith(Greeting.class.getName())){Greeting g lookup(java:global/javaee-ejb-engine/ next.getName());if(g!null !greetings.contains(g))greetings.add(g);}}} catch (NamingException e) {throw new RuntimeException(e);} return greetings;}private Greeting lookup(String jndi){try {InitialContext context new InitialContext();Object o context.lookup(jndi);return (Greeting)o;} catch (NamingException e) {log.log(Level.SEVERE, Could not lookup [{0}], jndi);return null;} }}运行示例 与Java EE CDI示例类似它在Wildfly Swarm Open Liberty和Payara Micro上运行 在javaee-ejb文件夹中 mvn clean install -P wildfly 或-P自由或-P payara 在所有3种情况下maven都会 在部署了应用程序的情况下启动应用程序服务器 击中2个REST网址 http// localhost8080 / javaee-ejb-engine / api 此列表列出了所有实现 关闭应用程序服务器Payara除外 因此在日志中您将看到类似
[BugsBunny,Afrikaans,English][Eeee, whats up Phillip ?,Goeie dag Phillip.,Good day Phillip.]如果运行Payara则服务器不会关闭因此您也可以手动测试工厂 wget -qO- http://localhost:8080/javaee-ejb-engine/api/Barney?wayAfrikaans[Goeie dag Barney.]动态SPI 到目前为止添加新实现时我们唯一要做的就是创建包含Greeting实现的模块并更新pom.xml以包含新的依赖项。 接下来让我们看看如何动态加载新的实现因此无需更新依赖项。 实现完全类似于Java SE SPI示例包括映射文件但是现在我们可以删除模块作为pom.xml依赖项 dependenciesdependencygroupId${project.groupId}/groupIdartifactIddynamic-spi-api/artifactIdversion${project.version}/version/dependency!-- This will be loaded dynamicallydependencygroupId${project.groupId}/groupIdartifactIddynamic-spi-impl-afrikaans/artifactIdversion${project.version}/version/dependencydependencygroupId${project.groupId}/groupIdartifactIddynamic-spi-impl-bugsbunny/artifactIdversion${project.version}/version/dependency--/dependencies 工厂看起来像这样 public class GreetingFactory {private final MapString,Greeting loadedGreetings new HashMap();public GreetingFactory(){URLClassLoader classloader getURLClassLoader();ServiceLoaderGreeting loader ServiceLoader.load(Greeting.class, classloader);IteratorGreeting greetingIterator loader.iterator();while (greetingIterator.hasNext()) {Greeting greeting greetingIterator.next();loadedGreetings.put(greeting.getName(), greeting);}}public Greeting getGreeting(String name){if(loadedGreetings.containsKey(name)){return loadedGreetings.get(name);}else {return new English();}}private URLClassLoader getURLClassLoader(){File[] pluginFiles getPluginFiles();ArrayListURL urls new ArrayList();for(File plugin:pluginFiles){try{URL pluginURL plugin.toURI().toURL();urls.add(pluginURL);}catch(MalformedURLException m){log.log(Level.SEVERE, Could not load [{0}], ignoring, plugin.getName());}}return new URLClassLoader(urls.toArray(new URL[]{}),GreetingFactory.class.getClassLoader());}private File[] getPluginFiles(){File loc new File(plugins);File[] pluginFiles loc.listFiles((File file) - file.getPath().toLowerCase().endsWith(.jar));return pluginFiles;}} 基本上工厂仍将使用SPI的ServiceLoader加载可用的问候语但我们传入自定义的ClassLoader。我们在plugins文件夹中查找任何jar文件并使用URLClassloader加载。 这意味着我现在可以只创建一个新的实现模块并将文件放在plugins文件夹中。 美观且可插拔。 运行示例 在dynamic-spi文件夹中 mvn clean install 这将构建项目并运行该应用程序。 日志将输出 SEVERE: Good day Phillip.Goeie dag Phillip.Eeee, whats up Phillip ? 您也可以在Maven之外运行此命令 java -jar dynamic-spi-engine/target/dynamic-spi-engine-1.0.0-SNAPSHOT-jar-with-dependencies.jar Madonna BugsBunnySEVERE: Eeee, whats up Madonna ?Java EE上的动态SPI 现在这是否是个好主意将进行另外的讨论只是为了表明它是可能的我们现在将使用动态SPI在应用程序服务器上加载实现。 这意味着我可以向正在运行的服务器添加新的实现。 因此我不仅可以在不接触代码或依赖项的情况下添加新的实现而且还可以启用该新实现而无需重新启动应用程序。 实现看起来完全像Java SE SPI示例 pom.xml不包含任何实现模块并且我们现在有了一个新类可以将模块加载到plugins文件夹中 这是一个ApplicationScoped CDI Bean可在启动时加载模块。 这些模块也可以通过REST重新加载 Path(/pluginloader)ApplicationScopedLogpublic class PluginLoader {Produces Named(Greetings)private final MapString,Greeting loadedGreetings new HashMap();public void init(Observes Initialized(ApplicationScoped.class) ServletContext context) {loadPlugins();}GETPath(/reload)public Response loadPlugins(){ClassLoader classloader getClassLoader();ServiceLoaderGreeting loader ServiceLoader.load(Greeting.class, classloader);IteratorGreeting greetingIterator loader.iterator();while (greetingIterator.hasNext()) {Greeting greeting greetingIterator.next();log.log(Level.SEVERE, Adding provider [{0}], greeting.getName());if(!loadedGreetings.containsKey(greeting.getName())){loadedGreetings.put(greeting.getName(), greeting);}}return Response.ok(ok).build();}private ClassLoader getClassLoader(){File[] pluginFiles getPluginFiles();if(pluginFiles!null){ ArrayListURL urls new ArrayList();for(File plugin:pluginFiles){try{URL pluginURL plugin.toURI().toURL();urls.add(pluginURL);}catch(MalformedURLException m){log.log(Level.SEVERE, Could not load [{0}], ignoring, plugin.getName());}}return new URLClassLoader(urls.toArray(new URL[]{}),this.getClass().getClassLoader());}return this.getClass().getClassLoader();}private File[] getPluginFiles(){File loc getPluginDirectory();if(locnull)return null;File[] pluginFiles loc.listFiles((File file) - file.getPath().toLowerCase().endsWith(.jar));return pluginFiles;}private File getPluginDirectory(){File plugins new File(plugins);if(plugins.exists())return plugins; return null;}} 所有加载的Greetings在MapString,Greeting中都可用可以将其注入工厂 RequestScopedLogpublic class GreetingFactory {Inject Named(Greetings)private MapString,Greeting greetings;// ...}运行示例 与Java EE CDI和EJB示例类似它在Wildfly Swarm Open Liberty和Payara Micro上运行 在javaee-spi文件夹中 mvn clean install -P wildfly 或-P自由或-P payara 在所有3种情况下maven都会 在部署了应用程序的情况下启动应用程序服务器 击中2个REST网址 http// localhost8080 / javaee-spi-engine / api 此列表列出了所有实现 关闭应用程序服务器Payara除外 因此在日志中您将看到类似
[BugsBunny,Afrikaans,English][Eeee, whats up Phillip ?,Goeie dag Phillip.,Good day Phillip.]如果运行Payara则服务器不会关闭因此您也可以手动测试工厂 wget -qO- http://localhost:8080/javaee-spi-engine/api/Frans?wayAfrikaans[Goeie dag Frans.] 当前在plugins文件夹中您将看到2个已知的实现南非荷兰语和Bugs Bunny ls javaee-spi-engine/plugins/javaee-spi-impl-afrikaans-1.0.0-SNAPSHOT.jar javaee-spi-impl-bugsbunny-1.0.0-SNAPSHOT.jar 当我们构建这些实现时将其复制到那里。 现在让服务器保持运行状态并添加一种新的问候方式称为AliG。 请参阅https://www.youtube.com/watch?vb00lc92lExw cd javaee-spi-impl-aligmvn clean install -P plugin 这会将Ali G实现复制到plugins文件夹。 现在让我们再次问候Frans wget -qO- http://localhost:8080/javaee-spi-engine/api/Frans?wayAliG[Booyakasha Frans !] 因此我们可以向正在运行的服务器添加新的具体实现。 结束 就是这样现在。 欢迎任何评论和您自己的示例 翻译自: https://www.javacodegeeks.com/2017/12/some-factory-examples.html