Optaplanner 在使用自定义过滤器类时不会终止
Posted
技术标签:
【中文标题】Optaplanner 在使用自定义过滤器类时不会终止【英文标题】:Optaplanner doesn't terminate when using custom filter class 【发布时间】:2015-09-13 07:50:55 【问题描述】:在某些情况下,但并非总是如此,看似随机且使用完全相同的配置,Optaplanner 不会在经过 secondsSpentLimit 课程后终止。它只是挂着“INFO --- [main] .c.i.c.DefaultConstructionHeuristicPhase:构造启发式阶段(1)结束:总步数(0),花费时间(1507),最佳分数(-9hard / 0soft)”
这是我的配置:
<solver>
<environmentMode>FULL_ASSERT</environmentMode>
<!-- Domain model configuration -->
<solutionClass>com.rdthree.plenty.services.activities.planner.ActivitySolution</solutionClass>
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskPlannerDto</entityClass>
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskResourceAllocationPlannerDto</entityClass>
<!-- Score configuration -->
<scoreDirectorFactory>
<scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
<scoreDrl>com/rdthree/plenty/services/activities/planner/activity-scoring.drl</scoreDrl>
<initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<terminationCompositionStyle>OR</terminationCompositionStyle>
<bestScoreLimit>0hard/0soft</bestScoreLimit>
<secondsSpentLimit>60</secondsSpentLimit>
</termination>
<constructionHeuristic>
<queuedEntityPlacer>
<entitySelector id="resourceAllocationSelector">
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskResourceAllocationPlannerDto</entityClass>
<cacheType>PHASE</cacheType>
<selectionOrder>SORTED</selectionOrder>
<sorterManner>DECREASING_DIFFICULTY_IF_AVAILABLE</sorterManner>
</entitySelector>
<changeMoveSelector>
<entitySelector mimicSelectorRef="resourceAllocationSelector" />
<valueSelector>
<variableName>resource</variableName>
<cacheType>PHASE</cacheType>
</valueSelector>
</changeMoveSelector>
</queuedEntityPlacer>
</constructionHeuristic>
<constructionHeuristic>
<queuedEntityPlacer>
<entitySelector id="taskSelector">
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskPlannerDto</entityClass>
<cacheType>PHASE</cacheType>
<selectionOrder>SORTED</selectionOrder>
<sorterManner>DECREASING_DIFFICULTY_IF_AVAILABLE</sorterManner>
</entitySelector>
<changeMoveSelector>
<entitySelector mimicSelectorRef="taskSelector" />
<filterClass>com.rdthree.plenty.services.activities.planner.TaskLengthChnageFilter</filterClass>
<valueSelector>
<variableName>interval</variableName>
<cacheType>PHASE</cacheType>
</valueSelector>
</changeMoveSelector>
</queuedEntityPlacer>
</constructionHeuristic>
<localSearch>
<unionMoveSelector>
<moveListFactory>
<moveListFactoryClass>com.rdthree.plenty.services.activities.planner.MoveResourceAllocationMoveFactory</moveListFactoryClass>
</moveListFactory>
<changeMoveSelector>
<fixedProbabilityWeight>1.0</fixedProbabilityWeight>
<filterClass>com.rdthree.plenty.services.activities.planner.TaskLengthChnageFilter</filterClass>
<entitySelector id="taskMoveSelector">
<entityClass>com.rdthree.plenty.services.activities.helpers.dtos.TaskPlannerDto</entityClass>
</entitySelector>
<valueSelector>
<variableName>interval</variableName>
</valueSelector>
</changeMoveSelector>
</unionMoveSelector>
<acceptor>
<valueTabuSize>7</valueTabuSize>
</acceptor>
<forager>
<acceptedCountLimit>2000</acceptedCountLimit>
</forager>
</localSearch>
我还有一个移动过滤器:
public class TaskLengthChnageFilter implements SelectionFilter<ChangeMove>
@SuppressWarnings("unchecked")
@Override
public boolean accept(ScoreDirector scoreDirector, ChangeMove selection)
// get the solution
Solution<HardSoftScore> solution = scoreDirector.getWorkingSolution();
List<TaskRequirementsMapper> taskRequirementsMappers = new ArrayList<>();
// find the taskRequirementsMappers in the problem facts
for (Object fact : solution.getProblemFacts())
if (fact instanceof TaskRequirementsMapper)
taskRequirementsMappers.add((TaskRequirementsMapper) fact);
for (Object obj : selection.getPlanningEntities())
TaskPlannerDto task;
Interval interval = null;
// get a task move
if (TaskPlannerDto.class.equals(obj.getClass()))
// get the planning value (i.e the resource that is being changed in the allocation)
for (Object thePvalue : selection.getPlanningValues())
// the collection should only hold one value so take it and break
interval = (Interval) thePvalue;
break;
task = (TaskPlannerDto) obj;
// iterate over all the task requirement mappers
for (TaskRequirementsMapper taskRequirementsMapper : taskRequirementsMappers)
// and find the one relevant for this allocation
if (task.getId().equals(taskRequirementsMapper.getTaskId()))
// check
int newLength = interval.toPeriod().getDays();
int oldLength = taskRequirementsMapper.getLength();
if (newLength != oldLength)
return false;
else
return true;
else
return false;
return true;
这是我用 kill -3 PID 杀死进程后的线程转储。此外,跟踪日志消息:
2015-09-18 12:36:05.079 INFO --- [ main] o.d.c.k.builder.impl.KieRepositoryImpl : KieModule was added:MemoryKieModule[ ReleaseId=org.default:artifact:1.0.0-SNAPSHOT]
2015-09-18 12:36:05.414 INFO --- [ main] o.o.core.impl.solver.DefaultSolver : Solving started: time spent (155), best score (-9hard/0soft), environment mode (FULL_ASSERT), random (JDK with seed 0).
2015-09-18 12:36:05.425 INFO --- [ main] o.o.c.a.s.event.SolverEventListener : New Best Solution Found with score : -9hard/0soft
2015-09-18 12:36:05.426 INFO --- [ main] .c.i.c.DefaultConstructionHeuristicPhase : Construction Heuristic phase (0) ended: step total (0), time spent (167), best score (-9hard/0soft).
2015-09-18 12:36:05.436 INFO --- [ main] o.o.c.a.s.event.SolverEventListener : New Best Solution Found with score : -9hard/0soft
2015-09-18 12:36:05.436 INFO --- [ main] .c.i.c.DefaultConstructionHeuristicPhase : Construction Heuristic phase (1) ended: step total (0), time spent (177), best score (-9hard/0soft).
2015-09-18 12:36:05.446 TRACE --- [ main] .m.f.MoveListFactoryToMoveSelectorBridge : Created cachedMoveList: size (60), moveSelector (MoveListFactory(class com.rdthree.plenty.services.activities.planner.MoveResourceAllocationMoveFactory)).
2015-09-18 12:39:16
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode):
"WeakCollectionCleaner" daemon prio=5 tid=0x00007f954e143800 nid=0xd507 in Object.wait() [0x0000000115f09000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007840964c0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000007840964c0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at org.geotools.util.WeakCollectionCleaner.run(WeakCollectionCleaner.java:77)
"GT authority factory disposer" daemon prio=5 tid=0x00007f954ca1e800 nid=0xd207 in Object.wait() [0x0000000116093000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007840ea820> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:552)
- locked <0x00000007840ea820> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:505)
"AWT-AppKit" daemon prio=5 tid=0x00007f954e552800 nid=0x713 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"java-sdk-http-connection-reaper" daemon prio=5 tid=0x00007f954d69a000 nid=0x5b03 waiting on condition [0x0000000115667000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.amazonaws.http.IdleConnectionReaper.run(IdleConnectionReaper.java:112)
"Abandoned connection cleanup thread" daemon prio=5 tid=0x00007f954e0b5800 nid=0x5903 in Object.wait() [0x0000000115bba000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007816e4b98> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000007816e4b98> (a java.lang.ref.ReferenceQueue$Lock)
at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)
"Tomcat JDBC Pool Cleaner[1625026637:1442568952184]" daemon prio=5 tid=0x00007f954e11e800 nid=0x5807 in Object.wait() [0x00000001157d3000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007814885e0> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:552)
- locked <0x00000007814885e0> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:505)
"ReaderThread" prio=5 tid=0x00007f954e08d800 nid=0x5103 runnable [0x00000001152ed000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x000000078056f568> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x000000078056f568> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner$ReaderThread.run(RemoteTestRunner.java:135)
"Service Thread" daemon prio=5 tid=0x00007f954e011000 nid=0x4d03 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=5 tid=0x00007f954c089000 nid=0x4b03 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=5 tid=0x00007f954c072000 nid=0x4903 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=5 tid=0x00007f954c02a000 nid=0x3c13 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=5 tid=0x00007f954c06f800 nid=0x3503 in Object.wait() [0x00000001125db000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000078056a588> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x000000078056a588> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" daemon prio=5 tid=0x00007f954c06f000 nid=0x3303 in Object.wait() [0x00000001124d8000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000780597940> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x0000000780597940> (a java.lang.ref.Reference$Lock)
"main" prio=5 tid=0x00007f954c02c800 nid=0x1303 runnable [0x0000000103374000]
java.lang.Thread.State: RUNNABLE
at org.optaplanner.core.impl.heuristic.selector.move.generic.ChangeMoveSelector$RandomChangeMoveIterator.createUpcomingSelection(ChangeMoveSelector.java:166)
at org.optaplanner.core.impl.heuristic.selector.move.generic.ChangeMoveSelector$RandomChangeMoveIterator.createUpcomingSelection(ChangeMoveSelector.java:129)
at org.optaplanner.core.impl.heuristic.selector.common.iterator.UpcomingSelectionIterator.hasNext(UpcomingSelectionIterator.java:40)
at org.optaplanner.core.impl.heuristic.selector.move.decorator.FilteringMoveSelector$JustInTimeFilteringMoveIterator.createUpcomingSelection(FilteringMoveSelector.java:90)
at org.optaplanner.core.impl.heuristic.selector.move.decorator.FilteringMoveSelector$JustInTimeFilteringMoveIterator.createUpcomingSelection(FilteringMoveSelector.java:77)
at org.optaplanner.core.impl.heuristic.selector.common.iterator.UpcomingSelectionIterator.hasNext(UpcomingSelectionIterator.java:40)
at org.optaplanner.core.impl.heuristic.selector.move.composite.UnionMoveSelector$RandomUnionMoveIterator.refreshMoveIteratorMap(UnionMoveSelector.java:183)
at org.optaplanner.core.impl.heuristic.selector.move.composite.UnionMoveSelector$RandomUnionMoveIterator.hasNext(UnionMoveSelector.java:159)
at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:112)
at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:66)
at org.optaplanner.core.impl.solver.DefaultSolver.runPhases(DefaultSolver.java:213)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:176)
at com.rdthree.plenty.services.activities.auto_scheduler.AutoSchedulerServiceBean.autoSchedule(AutoSchedulerServiceBean.java:138)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy227.autoSchedule(Unknown Source)
at com.rdthree.plenty.threads.SchedulerThread.run(SchedulerThread.java:104)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at com.rdthree.plenty.services.notifications.TestNotificationService.testSchedulerThreadFailNotification(TestNotificationService.java:578)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at com.rdthree.plenty.PlentyGeneralTest$RetryRule$1.eval(PlentyGeneralTest.java:46)
at com.rdthree.plenty.PlentyGeneralTest$RetryRule$1.evaluate(PlentyGeneralTest.java:56)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
"VM Thread" prio=5 tid=0x00007f954d00d800 nid=0x3103 runnable
"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007f954c038800 nid=0x2103 runnable
"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007f954c039000 nid=0x2303 runnable
"GC task thread#2 (ParallelGC)" prio=5 tid=0x00007f954c03a000 nid=0x2503 runnable
"GC task thread#3 (ParallelGC)" prio=5 tid=0x00007f954c03a800 nid=0x2703 runnable
"GC task thread#4 (ParallelGC)" prio=5 tid=0x00007f954d000800 nid=0x2903 runnable
"GC task thread#5 (ParallelGC)" prio=5 tid=0x00007f954d001000 nid=0x2b03 runnable
"GC task thread#6 (ParallelGC)" prio=5 tid=0x00007f954d001800 nid=0x2d03 runnable
"GC task thread#7 (ParallelGC)" prio=5 tid=0x00007f954d002800 nid=0x2f03 runnable
"VM Periodic Task Thread" prio=5 tid=0x00007f954e010000 nid=0x4f03 waiting on condition
JNI global references: 697
Heap
PSYoungGen total 698880K, used 154259K [0x00000007d5500000, 0x0000000800000000, 0x0000000800000000)
eden space 698368K, 22% used [0x00000007d5500000,0x00000007deba4f78,0x00000007fff00000)
from space 512K, 0% used [0x00000007fff00000,0x00000007fff00000,0x00000007fff80000)
to space 512K, 0% used [0x00000007fff80000,0x00000007fff80000,0x0000000800000000)
ParOldGen total 349696K, used 92182K [0x0000000780000000, 0x0000000795580000, 0x00000007d5500000)
object space 349696K, 26% used [0x0000000780000000,0x0000000785a05be8,0x0000000795580000)
PSPermGen total 131072K, used 85162K [0x0000000700000000, 0x0000000708000000, 0x0000000780000000)
object space 131072K, 64% used [0x0000000700000000,0x000000070532ab80,0x0000000708000000)
【问题讨论】:
您能否提供更多有关如何配置求解器的信息?构建启发式之后是否有任何阶段? 您使用移动或实体过滤器吗? @GeoffreyDeSmet,是的,我正在使用 SelectionFilter我敢打赌这不是随机的:如果在构建启发式结束之前满足终止条件,它将终止。但是,如果它到达本地搜索阶段(或本地搜索阶段中的特定移动选择器),它就会卡住。
我看到了 2 个场景:
如果您的自定义 MoveListFactory
或自定义 MoveFilter
陷入无限循环,则 OptaPlanner 不会终止。在 JVM 未终止时执行 Threads Dump(控制台中的 ctrl-break,或 IntelliJ 控制台中的那个按钮)以找出当前运行代码的堆栈跟踪。
如果您的自定义 MoveFilter
不接受任何移动,则不会选择移动,因此不会评估移动。打开警告异或跟踪日志(请参阅 optaplanner 文档)。在警告日志中,如果这种情况发生太多,它将显示救助警告。在跟踪记录中,它会显示当它卡住时不会评估任何移动(因此没有跟踪消息)。
【讨论】:
谢谢 Geoffrey,我知道你对 inifinte 循环和救助的意思,因为我的代码存在另一个问题,但我已经解决了,所以现在不是这种情况,我有我的登录 Trace。也许你可以帮我处理线程转储?我在我的问题中进行了编辑 线程转储清楚地证明了您的代码中没有无限循环(所以情况 1)。它还表明正在大量咨询 FilteringMoveSelector,因此我相信案例 2 在这里适用:您的自定义 MoveFilter 永远不会返回 true。只需记录(或 system.out)每个 MoveFilter 调用的结果。连同在某个时刻记录它的跟踪一起发送移动日志消息,并且仅过滤器返回错误消息(从不为真)。以上是关于Optaplanner 在使用自定义过滤器类时不会终止的主要内容,如果未能解决你的问题,请参考以下文章
使用 Ajax 的带有自定义分类法的 Wordpress 多个自定义帖子类型过滤器 - 所有新创建的帖子都不会在响应中显示
JSF / Spring Security - 添加其他登录字段不会调用自定义过滤器
自定义 pager/formfilter/buildquery 不会将过滤器数据处理为查询