博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【撸码师整合】基于Spring + Drools6.4规则引擎代码实例
阅读量:7002 次
发布时间:2019-06-27

本文共 22030 字,大约阅读时间需要 73 分钟。

hot3.png

简介

官网地址:

 

关于Drools(官网简介直接Copy过来)

Drools is a Business Rules Management System (BRMS) solution.

It provides a core Business Rules Engine (BRE), a web authoring and rules management application (Drools Workbench) and an Eclipse IDE plugin for core development.

 

最近有个消费返现和后付费保险类型项目,要求根据不同规则进行消费返现及保险静默投保etc. ,为避免过多硬编码ifelse逻辑判断,影响程序可读性及削弱程序可扩展性,因此引入了Drools规则引擎。

至于规则引擎到底是啥,在这里就不赘述了,google一下,你就知道。

 

Code实现

下面基于一个简单的Mock User Register模拟流程,简单介绍一下关于Spring+Drools集成实现流程。

 

需求说明

新用户规则:1.系统Mock生成用户注册数据,并进入Drools规则引擎处理;2.对于新注册用户设定用户锁定状态,并初始用户等级为3级,覆盖新用户标识为非;非新用户规则:1.设定用户非锁定状态,每次Mock Code执行,用户等级+1(规则比较随意);

 

实现过程

 

添加Drools Pom依赖

6.4.0.Final
org.drools
drools-core
${drools-version}
org.drools
drools-compiler
${drools-version}

 

User实体Bean定义

@Getter@Setter@Access(AccessType.FIELD)@Accessors(chain = true)@MetaData(value = "登陆/认证用户信息" , comments = "monster-web / monster-web-admin模块使用统一的auth信息")@Entity@Table(name = "auth_MsUser" , uniqueConstraints = @UniqueConstraint(columnNames ={"authUid","authType"}))@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)public class User extends BaseNativeEntity {    ……    ……    @MetaData(value="用户全局唯一标识" , comments = "同时作为系统用户密码Salt值,Salt形式 [authUuid]")    @Column(length = 64 , nullable = false)    private String authUuid;    @MetaData(value="authUid,登陆账号")    @Column(length = 128 , nullable = false)    private String authUid;    @MetaData(value="密码",comments = "MD5加密串,格式:MD5({Salt}+sourcePassword)")    @Column(length = 128 , nullable = false)    private String password;    @MetaData(value="用户类型")    @Column(length = 32 , nullable = false)    @Enumerated(EnumType.STRING)    private AuthTypeEnum authType;    @MetaData(value = "身份证号码")    @Column(length = 32)    private String idCardNo;    @MetaData(value="性别")    @Column(length = 32)    @Enumerated(EnumType.STRING)    private GenderEnum gender;    @MetaData(value = "REST访问Token")    @Column    private String accessToken;    @MetaData(value = "访问Token过期时间")    @DateTimeFormat(pattern = DateUtils.DEFAULT_TIME_FORMAT)    @JsonFormat(pattern = DateUtils.DEFAULT_TIME_FORMAT)    private Date accessTokenExpireTime;    @MetaData(value = "是否新用户",tooltips = "用于新用户相关业务规则")    @Column    private Boolean isNew = Boolean.TRUE;    @MetaData(value = "账户未锁定标志", tooltips = "账号锁定后无法登录")    @Column    private Boolean accountNonLocked = Boolean.TRUE;    ……    ……        }

 

Drools相关Bean定义

 

提供Drools资源辅助类

package org.monster.drools.technorage;import org.kie.api.io.ResourceType;@setter@getterpublic class DroolsResource {	private String path;	private ResourcePathType pathType;	private ResourceType type;	private String username = null;	private String password = null;	/**	 * 	 * @param path	 *            The path to this resource.	 * @param pathType	 *            The type of path (FILE, URL, etc).	 * @param type	 *            The type of resource (DRL, Binary package, DSL, etc)	 */	public DroolsResource(String path, ResourcePathType pathType,			ResourceType type) {		this.path = path;		this.pathType = pathType;		this.type = type;	}	/**	 * 	 * @param path	 *            The path to this resource.	 * @param pathType	 *            The type of path (FILE, URL, etc).	 * @param type	 *            The type of resource (DRL, Binary package, DSL, etc)	 * @param username	 *            The user name for connecting to the resource.	 * @param password	 *            The password for connecting to the resource.	 */	public DroolsResource(String path, ResourcePathType pathType,			ResourceType type, String username, String password) {		this.path = path;		this.pathType = pathType;		this.type = type;		this.username = username;		this.password = password;	}	}

 

定义本地接口,并实现Drools提供的KieServices与KieContainer、KieSession接口

import org.kie.api.KieServices;public interface KieServicesBean extends KieServices {}

 

package org.monster.drools.technorage.spring;import org.kie.api.runtime.KieContainer;public interface KieContainerBean extends KieContainer {}
package org.monster.drools.technorage.spring;import org.kie.api.runtime.KieSession;public interface KieSessionBean extends KieSession {}

及其分别实现类

public class DefaultKieServicesBean implements KieServicesBean {    private static Logger log = LoggerFactory.getLogger(DefaultKieServicesBean.class);        private DroolsResource[] resources;        private KieServices kieServices;    private KieFileSystem kfs;         public DefaultKieServicesBean(DroolsResource[] resources) throws KieBuildException {        log.info("Initialising KnowledgeEnvironment with resources: " + this.resources);        this.resources = resources;        createAndBuildKieServices(resources);    }    /**     * Initialises the {@link org.kie.api.KieServices} by downloading the package from the     * Guvnor REST interface, at the location defined in the URL.     *      * @param url The URL of the package via the Guvnor REST API.     * @throws KieBuildException      */    public DefaultKieServicesBean(String url) throws KieBuildException {        log.info("Initialising KnowledgeEnvironment with resources: " + this.resources);        this.resources = new DroolsResource[] {                 new DroolsResource(url,                        ResourcePathType.URL,                        ResourceType.PKG            )};        createAndBuildKieServices(resources);    }    /**     * 根据提供的URL生成{@link org.kie.api.KieServices}     *      * @param url The URL of the package via the Guvnor REST API.     * @param username The Guvnor user name.     * @param password The Guvnor password.     * @throws KieBuildException      */    public DefaultKieServicesBean(String url, String username, String password) throws KieBuildException {        this.resources = new DroolsResource[] {                 new DroolsResource(url,                         ResourcePathType.URL,                         ResourceType.PKG,                         username,                         password        )};        createAndBuildKieServices(resources);    }        /**     * 根据提供的DroolsResource创建 {@link org.kie.api.KieServices}      *      * @param resources     *            An array of {@link DroolsResource} indicating where the     *            various resources should be loaded from. These could be     *            classpath, file or URL resources.     * @return A new {@link org.kie.api.runtime.KieContainer}.     * @throws KieBuildException      */    private void createAndBuildKieServices(DroolsResource[] resources) throws KieBuildException {        this.kieServices = KieServices.Factory.get();        this.kfs = newKieFileSystem();                for (DroolsResource resource : resources) {            log.info("Resource: " + resource.getType() + ", path type="                    + resource.getPathType() + ", path=" + resource.getPath());            switch (resource.getPathType()) {            case CLASSPATH:                this.kfs.write(ResourceFactory.newClassPathResource(resource.getPath()));                break;            case FILE:                this.kfs.write(ResourceFactory.newFileResource(resource.getPath()));                break;            case URL:                UrlResource urlResource = (UrlResource) ResourceFactory                        .newUrlResource(resource.getPath());                                if (resource.getUsername() != null) {                    log.info("Setting authentication for: " + resource.getUsername());                    urlResource.setBasicAuthentication("enabled");                    urlResource.setUsername(resource.getUsername());                    urlResource.setPassword(resource.getPassword());                }                                this.kfs.write(urlResource);                                break;            default:                throw new IllegalArgumentException(                        "Unable to build this resource path type.");            }        }                KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();                if (kieBuilder.getResults().hasMessages(Level.ERROR)) {            List
errors = kieBuilder.getResults().getMessages(Level.ERROR); StringBuilder sb = new StringBuilder("Errors:"); for (Message msg : errors) { sb.append("\n " + prettyBuildMessage(msg)); } throw new KieBuildException(sb.toString()); } log.info("KieServices built: " + toString()); } private static String prettyBuildMessage(Message msg) { return "Message: {" + "id="+ msg.getId() + ", level=" + msg.getLevel() + ", path=" + msg.getPath() + ", line=" + msg.getLine() + ", column=" + msg.getColumn() + ", text=\"" + msg.getText() + "\"" + "}"; } //省略相关实现方法 }
public class DefaultKieContainerBean implements KieContainerBean {    private KieServicesBean kieServices;    private KieContainer kieContainer;    public DefaultKieContainerBean(KieServicesBean kieServicesBean) {        this.kieServices = kieServicesBean;        this.kieContainer = this.kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());    }              /**            ……            ……          */}
public class DefaultKieSessionBean implements KieSessionBean {    private static Logger log = LoggerFactory.getLogger(DefaultKieSessionBean.class);    private KieSession kieSession;        public DefaultKieSessionBean(KieServicesBean kieServices, KieContainerBean kieContainer) {        this(kieServices, kieContainer, null);    }        public DefaultKieSessionBean(KieServicesBean kieServices, KieContainerBean kieContainer, Properties droolsProperties) {        log.info("Initialising session...");        KieSessionConfiguration conf;        if (droolsProperties == null) {            conf = SessionConfiguration.getDefaultInstance();        } else {            conf = SessionConfiguration.newInstance(droolsProperties);//new SessionConfiguration(droolsProperties);        }        this.kieSession = kieContainer.newKieSession(conf);    }    public void addEventListener(RuleRuntimeEventListener listener) {        kieSession.addEventListener(listener);    }    public void addEventListener(ProcessEventListener listener) {        kieSession.addEventListener(listener);    }    public ProcessInstance startProcess(String processId) {        return kieSession.startProcess(processId);    }    public void removeEventListener(RuleRuntimeEventListener listener) {        kieSession.removeEventListener(listener);    }    public int fireAllRules() {        return kieSession.fireAllRules();    }    public void removeEventListener(ProcessEventListener listener) {        kieSession.removeEventListener(listener);    }    public 
T getSessionClock() { return kieSession.getSessionClock(); } public int fireAllRules(int max) { return kieSession.fireAllRules(max); } public Collection
getWorkingMemoryEventListeners() { return kieSession.getRuleRuntimeEventListeners(); } public Collection
getProcessEventListeners() { return kieSession.getProcessEventListeners(); } public void setGlobal(String identifier, Object value) { kieSession.setGlobal(identifier, value); } public void halt() { kieSession.halt(); } public ProcessInstance startProcess(String processId, Map
parameters) { return kieSession.startProcess(processId, parameters); } public void addEventListener(AgendaEventListener listener) { kieSession.addEventListener(listener); } public Object getGlobal(String identifier) { return kieSession.getGlobal(identifier); } public Globals getGlobals() { return kieSession.getGlobals(); } public Calendars getCalendars() { return kieSession.getCalendars(); } public void removeEventListener(AgendaEventListener listener) { kieSession.removeEventListener(listener); } public Environment getEnvironment() { return kieSession.getEnvironment(); } public KieBase getKieBase() { return kieSession.getKieBase(); } public int fireAllRules(AgendaFilter agendaFilter) { return kieSession.fireAllRules(agendaFilter); } public void registerChannel(String name, Channel channel) { kieSession.registerChannel(name, channel); } public Collection
getAgendaEventListeners() { return kieSession.getAgendaEventListeners(); } public String getEntryPointId() { return kieSession.getEntryPointId(); } public void unregisterChannel(String name) { kieSession.unregisterChannel(name); } public Map
getChannels() { return kieSession.getChannels(); } public Agenda getAgenda() { return kieSession.getAgenda(); } public int fireAllRules(AgendaFilter agendaFilter, int max) { return kieSession.fireAllRules(agendaFilter, max); } public FactHandle insert(Object object) { return kieSession.insert(object); } public KieSessionConfiguration getSessionConfiguration() { return kieSession.getSessionConfiguration(); } @Override public EntryPoint getEntryPoint(String name) { return kieSession.getEntryPoint(name); } public ProcessInstance createProcessInstance(String processId, Map
parameters) { return kieSession.createProcessInstance(processId, parameters); } @Deprecated public void retract(FactHandle handle) { kieSession.retract(handle); } public Collection
getEntryPoints() { return kieSession.getEntryPoints(); } public void fireUntilHalt() { kieSession.fireUntilHalt(); } public
T execute(Command
command) { return kieSession.execute(command); } public void delete(FactHandle handle) { kieSession.delete(handle); } @Override public void delete(FactHandle handle, FactHandle.State fhState) { } public QueryResults getQueryResults(String query, Object... arguments) { return kieSession.getQueryResults(query, arguments); } public void update(FactHandle handle, Object object) { kieSession.update(handle, object); } public void fireUntilHalt(AgendaFilter agendaFilter) { kieSession.fireUntilHalt(agendaFilter); } public FactHandle getFactHandle(Object object) { return kieSession.getFactHandle(object); } public LiveQuery openLiveQuery(String query, Object[] arguments, ViewChangedEventListener listener) { return kieSession.openLiveQuery(query, arguments, listener); } public ProcessInstance startProcessInstance(long processInstanceId) { return kieSession.startProcessInstance(processInstanceId); } public Object getObject(FactHandle factHandle) { return kieSession.getObject(factHandle); } public int getId() { return kieSession.getId(); } @Override public long getIdentifier() { return 0; } public void signalEvent(String type, Object event) { kieSession.signalEvent(type, event); } public void dispose() { kieSession.dispose(); } public Collection
getObjects() { return kieSession.getObjects(); } public void destroy() { kieSession.destroy(); } public void signalEvent(String type, Object event, long processInstanceId) { kieSession.signalEvent(type, event, processInstanceId); } public Collection
getObjects(ObjectFilter filter) { return kieSession.getObjects(filter); } public
Collection
getFactHandles() { return kieSession.getFactHandles(); } public
Collection
getFactHandles( ObjectFilter filter) { return kieSession.getFactHandles(filter); } public Collection
getProcessInstances() { return kieSession.getProcessInstances(); } public long getFactCount() { return kieSession.getFactCount(); } public ProcessInstance getProcessInstance(long processInstanceId) { return kieSession.getProcessInstance(processInstanceId); } public ProcessInstance getProcessInstance(long processInstanceId, boolean readonly) { return kieSession.getProcessInstance(processInstanceId, readonly); } public void abortProcessInstance(long processInstanceId) { kieSession.abortProcessInstance(processInstanceId); } public WorkItemManager getWorkItemManager() { return kieSession.getWorkItemManager(); } @Override public KieRuntimeLogger getLogger() { return kieSession.getLogger(); } @Override public Collection
getRuleRuntimeEventListeners() { return kieSession.getRuleRuntimeEventListeners(); } }

集成Spring,交由spring托管

@Configuration//@Profile("drools")public class BaseKieConfig {    @Bean(name="kieServices")    public KieServicesBean kieServices() throws KieBuildException {        DroolsResource [] droolsResources = new DroolsResource[]{                new DroolsResource("rules/user-level.drl", ResourcePathType.CLASSPATH , ResourceType.DRL)        };        KieServicesBean kieServicesBean = new DefaultKieServicesBean(droolsResources);        return kieServicesBean;    }    @Bean(name="kieContainer")    public KieContainerBean kieContainer(KieServicesBean kieServices){        KieContainerBean kieContainer = new DefaultKieContainerBean(kieServices);        return kieContainer;    }}

定义相关业务接口

public interface UserRuleService
{ List
userRegister( List
users ); List
remUsers( List
users ); List
checkUserStatus();}
@Service@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON , proxyMode = ScopedProxyMode.INTERFACES)public class UserRuleServiceImpl implements UserRuleService
,Serializable { private Logger logger = LoggerFactory.getLogger(UserRuleServiceImpl.class); public KieSessionBean kieSession; private TrackingAgendaEventListener agendaEventListener; private TrackingWorkingMemoryEventListener workingMemoryEventListener; private Map
fact2User = Maps.newHashMap(); private FactFinder
userFactFinder = new FactFinder
(User.class); @Autowired public UserRuleServiceImpl(@Qualifier("kieServices") KieServicesBean kieServices , @Qualifier("kieContainer") KieContainerBean kieContainer){ System.setProperty("drools.negatable", "on"); kieSession = new DefaultKieSessionBean(kieServices , kieContainer); agendaEventListener = new TrackingAgendaEventListener(); workingMemoryEventListener = new TrackingWorkingMemoryEventListener(); kieSession.addEventListener(agendaEventListener); kieSession.addEventListener(workingMemoryEventListener); } @Override public List
userRegister(List
users) { for ( User user : users ) { if(logger.isDebugEnabled()){ logger.debug("执行用户注册规则模板,对应用户:{}",user.toString()); } if(!fact2User.containsKey(user.getId())){ FactHandle userFireHandle = kieSession.insert(user); fact2User.put(String.valueOf(user.getId()) , userFireHandle); } } kieSession.fireAllRules(); List
results = userFactFinder.findFacts(kieSession); pause(); kieSession.dispose(); return results; } @Override public List
remUsers(List
users) { for( User user : users ) { if(fact2User.containsKey(String.valueOf(user.getId()))) { kieSession.delete(fact2User.get(String.valueOf(user.getId()))); fact2User.remove(user); } } kieSession.fireAllRules(); List
result = userFactFinder.findFacts(kieSession); return result; } @Override public List
checkUserStatus() { return null; } public static void pause() { System.out.println( "Pressure enter to continue" ); Scanner keyboard = new Scanner(System.in); keyboard.nextLine(); }}

Mock代码

…… …… …… int userCnt = countTable(User.class);        for( int i = userCnt ; (i < INIT_USER_CNT && i
) userRuleService.userRegister(users); //存储用户信息 userService.save(users);

定义规则文件(user-register.drl)

//User-Level规则package rulesimport org.monster.core.auth.entity.User;rule RegistNewUserRule//ruleflow-group "Basic-User-Group"when  $user:User(isNew == Boolean.TRUE)then     //1.设置解除锁定状态     $user.setAccountNonLocked(false);     //2.用户注册送积分     $user.setUserLevel(3);     $user.setIsNew(Boolean.FALSE);     //3.根据性别     //System.out.println("++++++++++ Is New Flg True , [User:" + $user.toString() + "]");endrule RegistNewUserRuleNotNew//ruleflow-group "Basic-User-Group"when $user:User(isNew == false)then     //1.设置锁定状态         $user.setAccountNonLocked(true);         //2.老用户统一设定每次启动增加一级         $user.setUserLevel($user.getUserLevel()+1);         //System.out.println("---------- Is New Flg False, [User:" + $user.toString() +"]");end

 

————————————————————————————————————————————————————————————————————————————————

Drools中,其三者关系

1.KieServices

1.1 容器通过ClassPathResource获取KieFileSystem

//获取KieFileSystemthis.kfs.write(ResourceFactory.newClassPathResource(resource.getPath()));

1.2.并通过Factory.get()方法获取Service实例,进行相关装载校验

//获取kieServices实例this.kieServices = KieServices.Factory.get();……KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();                if (kieBuilder.getResults().hasMessages(Level.ERROR)) {            List
errors = kieBuilder.getResults().getMessages(Level.ERROR); StringBuilder sb = new StringBuilder("Errors:"); for (Message msg : errors) { sb.append("\n " + prettyBuildMessage(msg)); } throw new KieBuildException(sb.toString()); }

 

2.KieContainer

通过KieServices实例,构造KieContainer

this.kieContainer = this.kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());

3.KieSession

通过KieContainer及相关KieSessionConfig获取current working Session对象

KieSessionConfiguration conf;        if (droolsProperties == null) {            conf = SessionConfiguration.getDefaultInstance();        } else {            conf = SessionConfiguration.newInstance(droolsProperties);//new SessionConfiguration(droolsProperties);        }        this.kieSession = kieContainer.newKieSession(conf);

 

时间匆忙写的比较乱,基本贴的代码。有空整理

转载于:https://my.oschina.net/xiehongfei/blog/690074

你可能感兴趣的文章