在项目迭代开发中经常会遇到对已有功能的改造需求,尽管我们可能已经预留了扩展点,并且尝试通过接口或扩展类完成此类任务。可是,仍然有很多难以预料的场景无法通过上述方式解决。修改原有代码当然能够做到,但是这会增加许多附加成本,回归测试带来大量工作和一些潜在的未知风险。特别是一些极其重要的公共模块,可谓牵一发而动全身,稍有不慎都将引发重大的故障。这里分享一下自己在项目开发中的一点实践,一种基于AOP的插件化(扩展)方案。
假设一个场景:
现有一个可获取人员信息的服务:UserService。
public class UserService { public User getUserById(String id) { // ... } }
该服务作为一个基础服务一直运行良好,但是客户出于对数据安全的考虑需要对人员信息中某些属性进行脱敏。该需求总体来说不是很复杂,解决方案也不止一个,那么来看看基于AOP的实现方式是怎么样的。
插件点注解:
@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Component public @interface PluginPoint { Class<?> service(); String method(); PluginType type(); enum PluginType { BEFORE, AFTER, OVERRIDE; } }
插件服务接口(后期所有的插件都必须实现这个接口):
public interface PluginService { Object process(Object[] args, Object result) throws Exception; }
PluginServiceHolder.java:
public class PluginServiceHolder { private PluginService before; private PluginService override; private PluginService after; public PluginService getBefore() { return before; } public void setBefore(PluginService before) { this.before = before; } public boolean hasBefore() { return before != null; } public void doBefore(Object[] args) throws Exception { before.process(args, null); } public PluginService getOverride() { return override; } public void setOverride(PluginService override) { this.override = override; } public boolean hasOverride() { return override != null; } public Object doOverride(Object[] args) throws Exception { return override.process(args, null); } public PluginService getAfter() { return after; } public void setAfter(PluginService after) { this.after = after; } public boolean hasAfter() { return after != null; } public Object doAfter(Object[] args, Object result) throws Exception { return after.process(args, result); } }