比如对于策略模式,我们通常是定义一个接口,然后有不同的实现,这种是可以的,但是如果通用流程中要扩展的点较多的话,这些不同的实现也需要管理,可以把他们合并到一个单独的包中,再进一步,我们甚至可以将包单独提取出来,支持运行时加载包实现新增功能的支持
JDK对此功能的支持就是 SPI,但是它的限制较多,也不够灵活,比如dubbo就是自己定义了一套SPI的实现,这次我们来看另一个实现,pf4j 提供一套在基本框架中定义扩展点接口,然后通过不同的插件来实现扩展点的功能,来支持对新增开放对修改关闭
下面我们就来学习一下它的使用
使用
比如我们有一套通用的流程,假设是下单流程,不同的业务线等对于下单都有一些特殊点,但是它们的基本流程是相似的,这时候我们就可以先定义好通用的流程,不同的地方预留出扩展点接口,使用 pf4j 的流程如下
先定义好扩展点接口(需要定义单独的包,因为基本应用和各个扩展点的包都依赖它)
定义单独的插件包,其中实现扩展点接口的功能
在应用中编写基本流程和扩展点的发现使用功能
这次我们就参考 pf4j 提供的例子来看一下
1. 定义扩展点接口
pom.xml首先声明依赖
<dependency>
<groupId>org.pf4j</groupId>
<artifactId>pf4j</artifactId>
<version>3.6.0</version>
<!-- 一般应用中会依赖这个包,所以这里设置为provided即可 -->
<scope>provided</scope>
</dependency>
之后即可声明各个扩展点接口
/**
* 假设我们需要一个通知用户的功能
* 需要注意的是,我们一定要继承 ExtensionPoint 接口,表示这是一个扩展点
*/
public interface Notice extends ExtensionPoint {
boolean notice(List<Long> userIds);
}
本文例子基于Github地址:https://github.com/pf4j/pf4j
<dependency>
<groupId>org.pf4j</groupId>
<artifactId>pf4j</artifactId>
<version>3.6.0</version>
</dependency>
插件项目会涉及到3个工程:工程结构
plugin-api:定义可扩展接口
plugins:插件项目,可以包含多个插件,需要实现plugin-api中定义的接口
plugin-app:主程序,需要依赖plugin-api,加载并执行plugins
定义可扩展接口(plugin-api)
简单定义一个接口,需继承ExtensionPoint:
package plugin.api;
import org.pf4j.ExtensionPoint;
public interface Greeting extends ExtensionPoint {
String getGreeting();
}
实现插件(plugins)
插件需要实现plugin-api定义的接口,并且使用@Extension标记:
package plugins;
import org.pf4j.Extension;
import plugin.api.Greeting;
@Extension
public class WelcomeGreeting implements Greeting {
public String getGreeting() {
return "Welcome";
}
}
插件打包(plugins)
插件打包时,需要往MANIFEST.MF写入插件信息,此处使用maven插件(打包命令为package):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestEntries>
<Plugin-Id>welcome-plugin</Plugin-Id>
<Plugin-Version>0.0.1</Plugin-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>
报错原因为配置中找不到一个指定自动注入类型的bean。
那么我们要从collecter层开始查找,点击service层,看service实现类是否加上@Service或者@Component,检查service实现类是否有implements service。如果这些都没有问题:
我们来看@SpringBootApplication,点过去。可以看到有个@ComponentScan,ComponentScan做的事情就是告诉Spring从哪里找到bean
那可以直接在@SpringBootApplication加上
还有一种问题,你的spring启动类不在同一个父包路径下,比如你的其它类在com.heckjj.blog,而你的启动类在heckjj下,也会报错扫不到其它的类,比如说service找不到。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<encoding>UTF-8</encoding>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
<nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
在使用beanutils工具类封装javabean时,beanUtils不提供直接将字符串转换成Date(java.util.Date)数据类型的方法,所以会出现下面警告:
在控制层中写入以下代码
DateConverter converter = new DateConverter();
converter.setPattern(new String("yyyy-MM-dd"));
ConvertUtils.register(converter, Date.class);
于是Iteger类型的数据为空时填写–写”直接转为0
以上情况均不符合要求,数据库要求为integer的默认值NULL
后来查阅资料寻找到以下方法
ConvertUtils.register(new IntegerConverter(null), Integer.class);
通过转换器来设置为null时的默认转换值。其它类型依次类推设置为相应的基本类型的包装类即可。
当我们安装了redis服务后,发现在其配置文件redis.windows.conf(或redis.conf)设置了密码:requirepass ******
但是打开redis-cli.exe后输入命令config get requirepass发现:

这说明配置文件中密码设置后没有生效。
原因:问题在于我们启动redis服务时是直接在其安装目录中双击redis-server.exe启动的,这样启动的结果是,配置文件不会指定,此时redis并不会自动使用安装目录下的redis.windows.conf(或redis.conf)文件

红线框住的的提示说的很明确“ Warning: no config file specified”没有指定配置文件
解决方法:
法1:实际上我们直接在安装目录中启动redis服务时错误的,正确的方式是打开“运行”,键入“cmd”切到安装目录后输出redis-server.exe redis.windows.conf,回车,就可以了。

法2:在redis安装目录下新建文件startup.bat后,右击“编辑”,或者先用记事本建立该文件,再把扩展名改一下,文件里面写上:redis-server.exe redis.windows.conf。保存,以后再运行就直接运行这个文件,不要再直接运行redis-server.exe了,就可以了。

2、原因:后台传过去的json数据用了阿里的fastjson转换,但是解析list中引用的数据时,jvm会自动将其处理为“循环引用”,因此,也就出现了问题{" r e f " : " ref":" ref":".data[0].children[0]"},数据以引用的方式传给前台,前台却无法解析到那段引用的数据。
循环引用就是:当一个对象包含另一个对象时,fastjson就会把该对象解析成引用。
二、解决方案
JSON.toJSONString(list,SerializerFeature.DisableCircularReferenceDetect)
用这种转换方式,把list替换成你要转换的数据就可以了。







