Skip to content

Commit

Permalink
optimize code and comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Createsequence committed Jan 28, 2024
1 parent e83ac5c commit 0cb988d
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@
*
* @author huangchengxing
* @see cn.crane4j.core.executor.OperationAwareBeanOperationExecutor
* @see cn.crane4j.core.container.lifecycle.SmartOperationAware
* @see cn.crane4j.core.container.lifecycle.SmartOperationAwareBean
* @since 2.5.0
*/
public interface OperationAware {
public interface OperationAwareBean {

/**
* Whether the target object supports the specified operation.
*
* @param key key property name of the operation
* @return true if supported, false otherwise
*/
default boolean supportOperation(String key) {
return true;
}

/**
* Do something before the assembly operations begin.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package cn.crane4j.core.container.lifecycle;

import cn.crane4j.annotation.OperationAware;
import cn.crane4j.annotation.OperationAwareBean;
import cn.crane4j.core.executor.OperationAwareBeanOperationExecutor;
import cn.crane4j.core.parser.BeanOperations;
import cn.crane4j.core.parser.operation.KeyTriggerOperation;

/**
* <p>An interface that make the target object aware of the operation.<br />
* It's enhanced on the basis of {@link OperationAware} and supports awareness more arguments.
* It's enhanced on the basis of {@link OperationAwareBean} and supports awareness more arguments.
*
* @author huangchengxing
* @see cn.crane4j.core.executor.OperationAwareBeanOperationExecutor
* @see OperationAwareBeanOperationExecutor
* @since 2.5.0
*/
public interface SmartOperationAware extends OperationAware {
public interface SmartOperationAwareBean extends OperationAwareBean {

/**
* Whether the target object supports the specified operation.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cn.crane4j.core.executor;

import cn.crane4j.annotation.OperationAware;
import cn.crane4j.annotation.OperationAwareBean;
import cn.crane4j.core.container.ContainerManager;
import cn.crane4j.core.container.lifecycle.SmartOperationAware;
import cn.crane4j.core.container.lifecycle.SmartOperationAwareBean;
import cn.crane4j.core.parser.BeanOperations;
import cn.crane4j.core.parser.operation.KeyTriggerOperation;
import cn.crane4j.core.util.MultiMap;
Expand All @@ -16,8 +16,8 @@
* that supports the operation aware.
*
* @author huangchengxing
* @see OperationAware
* @see SmartOperationAware
* @see OperationAwareBean
* @see SmartOperationAwareBean
* @since 2.5.0
*/
public abstract class OperationAwareBeanOperationExecutor extends AbstractBeanOperationExecutor {
Expand All @@ -34,36 +34,36 @@ protected OperationAwareBeanOperationExecutor(ContainerManager containerManager)
@Override
protected void beforeAssembleOperation(MultiMap<BeanOperations, Object> targetWithOperations) {
targetWithOperations.forEach((operations, target) -> {
if (target instanceof OperationAware) {
((OperationAware)target).beforeAssembleOperation();
if (target instanceof SmartOperationAware) {
((SmartOperationAware)target).beforeAssembleOperation(operations);
if (target instanceof OperationAwareBean) {
((OperationAwareBean)target).beforeAssembleOperation();
if (target instanceof SmartOperationAwareBean) {
((SmartOperationAwareBean)target).beforeAssembleOperation(operations);
}
}
});
}

/**
* Trigger the {@link OperationAware#afterOperationsCompletion} method of the target object.
* Trigger the {@link OperationAwareBean#afterOperationsCompletion} method of the target object.
*
* @param targetWithOperations target with operations
* @since 2.5.0
*/
@Override
protected void afterOperationsCompletion(MultiMap<BeanOperations, Object> targetWithOperations) {
targetWithOperations.forEach((operations, target) -> {
if (target instanceof OperationAware) {
((OperationAware)target).afterOperationsCompletion();
if (target instanceof SmartOperationAware) {
((SmartOperationAware)target).afterOperationsCompletion(operations);
if (target instanceof OperationAwareBean) {
((OperationAwareBean)target).afterOperationsCompletion();
if (target instanceof SmartOperationAwareBean) {
((SmartOperationAwareBean)target).afterOperationsCompletion(operations);
}
}
});
}

/**
* Filter the targets that support the specified operation
* by the {@link SmartOperationAware#supportOperation} method.
* by the {@link OperationAwareBean#supportOperation} method.
*
* @param targets targets
* @param operation operation
Expand All @@ -75,8 +75,18 @@ protected void afterOperationsCompletion(MultiMap<BeanOperations, Object> target
protected <T> Collection<T> filterTargetsForSupportedOperation(
Collection<T> targets, KeyTriggerOperation operation) {
return targets.stream()
.filter(t -> !(t instanceof SmartOperationAware)
|| ((SmartOperationAware)t).supportOperation(operation))
.filter(t -> support(t, operation))
.collect(Collectors.toList());
}

private boolean support(Object target, KeyTriggerOperation operation) {
if (target instanceof OperationAwareBean) {
boolean support = ((OperationAwareBean)target).supportOperation(operation.getKey());
if (support && target instanceof SmartOperationAwareBean) {
return ((SmartOperationAwareBean)target).supportOperation(operation);
}
return support;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class ManyToManyAssembleOperationHandler extends OneToManyAssembleOperati
*/
@Setter
@NonNull
private Function<Object, Collection<Object>> keySplitter;
private KeySplitter keySplitter;

/**
* Create an {@link ManyToManyAssembleOperationHandler} instance.
Expand All @@ -50,7 +50,7 @@ public class ManyToManyAssembleOperationHandler extends OneToManyAssembleOperati
*/
public ManyToManyAssembleOperationHandler(
PropertyOperator propertyOperator, ConverterManager converterManager,
@NonNull Function<Object, Collection<Object>> keySplitter) {
@NonNull KeySplitter keySplitter) {
super(propertyOperator, converterManager);
this.keySplitter = keySplitter;
}
Expand Down Expand Up @@ -112,12 +112,20 @@ protected Object getTheAssociatedSource(Target target, Map<Object, Object> sourc
.collect(Collectors.toList());
}

/**
* Split the value of key attribute into multiple key values.
*
* @since 2.5.0
*/
public interface KeySplitter extends Function<Object, Collection<Object>> {
}

/**
* The default key value splitter supports splitting {@link Collection},
* arrays and strings with specified delimiters.
*/
@RequiredArgsConstructor
public static class DefaultSplitter implements Function<Object, Collection<Object>> {
public static class DefaultSplitter implements KeySplitter {
private final String strSeparator;
@SuppressWarnings("unchecked")
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ protected Collection<Target> collectToEntities(Collection<AssembleExecution> exe
UnaryOperator<Object> keyExtractor = getKeyExtractor(execution);
execution.getTargets().stream()
.map(t -> createTarget(execution, t, keyExtractor.apply(t)))
.filter(t -> !ignoreNullKey || Objects.nonNull(t.getKey()))
.forEach(targets::add);
}
return targets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import cn.crane4j.annotation.Assemble;
import cn.crane4j.annotation.Disassemble;
import cn.crane4j.core.container.ContainerManager;
import cn.crane4j.core.container.lifecycle.SmartOperationAware;
import cn.crane4j.core.container.lifecycle.SmartOperationAwareBean;
import cn.crane4j.core.parser.BeanOperations;
import cn.crane4j.core.parser.operation.AssembleOperation;
import cn.crane4j.core.parser.operation.KeyTriggerOperation;
Expand All @@ -24,6 +24,8 @@
import java.util.function.Predicate;

/**
* test for {@link OperationAwareBeanOperationExecutor}
*
* @author huangchengxing
*/
public class OperationAwareBeanOperationExecutorTest extends BaseExecutorTest {
Expand Down Expand Up @@ -56,11 +58,11 @@ public void execute() {
// bean * 3
Assert.assertEquals(6, callbackCountOfBean.get("beforeAssembleOperation").intValue());
Assert.assertEquals(6, callbackCountOfBean.get("afterOperationsCompletion").intValue());
Assert.assertEquals(9, callbackCountOfBean.get("supportOperation").intValue());
Assert.assertEquals(18, callbackCountOfBean.get("supportOperation").intValue());
// nestBean * 2
Assert.assertEquals(4, callbackCountOfNestedBean.get("beforeAssembleOperation").intValue());
Assert.assertEquals(4, callbackCountOfNestedBean.get("afterOperationsCompletion").intValue());
Assert.assertEquals(2, callbackCountOfNestedBean.get("supportOperation").intValue());
Assert.assertEquals(4, callbackCountOfNestedBean.get("supportOperation").intValue());
}

@Test
Expand Down Expand Up @@ -116,7 +118,7 @@ protected void executeOperations(List<AssembleExecution> executions, Options opt

@Accessors(chain = true)
@Data
private static class Bean implements SmartOperationAware {
private static class Bean implements SmartOperationAwareBean {
@Assemble(groups = {"op", "id"})
private Integer id;
private String name;
Expand All @@ -128,6 +130,11 @@ private static class Bean implements SmartOperationAware {
@Disassemble(type = NestedBean.class, groups = "op")
private NestedBean nestedBean;

@Override
public boolean supportOperation(String key) {
callbackCountOfBean.put("supportOperation", callbackCountOfBean.getOrDefault("supportOperation", 0) + 1);
return true;
}
@Override
public boolean supportOperation(KeyTriggerOperation operation) {
callbackCountOfBean.put("supportOperation", callbackCountOfBean.getOrDefault("supportOperation", 0) + 1);
Expand All @@ -153,11 +160,16 @@ public void afterOperationsCompletion(BeanOperations operations) {
}

@Data
private static class NestedBean implements SmartOperationAware {
private static class NestedBean implements SmartOperationAwareBean {
@Assemble(groups = {"op", "id"})
private Integer type;
private String typeName;

@Override
public boolean supportOperation(String key) {
callbackCountOfNestedBean.put("supportOperation", callbackCountOfNestedBean.getOrDefault("supportOperation", 0) + 1);
return true;
}
@Override
public void beforeAssembleOperation() {
callbackCountOfNestedBean.put("beforeAssembleOperation", callbackCountOfNestedBean.getOrDefault("beforeAssembleOperation", 0) + 1);
Expand All @@ -181,7 +193,7 @@ public void afterOperationsCompletion(BeanOperations operations) {
}
}

private static class NoneCallbackBean implements SmartOperationAware {
private static class NoneCallbackBean implements SmartOperationAwareBean {
@Assemble(groups = {"op", "id"})
private Integer type;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package cn.crane4j.spring.boot.example;

import cn.crane4j.spring.boot.annotation.EnableCrane4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @author huangchengxing
*/
@EnableCrane4j
@SpringBootApplication
public class Crane4jSpringBootStarterExampleApplication {

Expand Down
2 changes: 1 addition & 1 deletion website/docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const sidebarConfig = [
children: [
{ title: '缓存', path: "/advanced/cache.md"},
{ title: '组合注解', path: "/advanced/combination_annotation.md"},
{ title: '容器的生命周期', path: "/advanced/container_lifecycle.md"},
{ title: '组件的回调接口', path: "/advanced/callback_of_component.md"},
{ title: '注解处理器', path: "/advanced/operation_annotation_handler.md"},
{ title: '使用抽象方法填充', path: "/advanced/operator_interface.md"},
{ title: '反射工厂', path: "/advanced/reflection_factory.md"},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# 容器的生命周期
# 组件的回调接口

为了便于对在容器进行初始化和销毁阶段进行一些特殊的处理,crane4j 为容器设计了一套类似 Spring 的生命周期回调机制
为了便于用户对在 crane4j 各个组件的特定阶段插入自定义逻辑,crane4j 提供了一套类似 Spring 的回调机制

它包含容器生命周期处理器 `ContainerLifecycleProcessor` 与生命周期接口 `Container.Lifecycle` 两种,前者用于针对全局的容器进行处理器,而后者则用于处理特定类型的容器。
## 1.容器生命周期处理器

## 1.生命周期处理器

生命周期处理器 `ContainerLifecycleProcessor` 是用于感知并干涉容器生命周期的特色组件,它提个三个抽象方法:
容器生命周期处理器 `ContainerLifecycleProcessor` 是用于感知并干涉容器生命周期的特色组件,它提个三个抽象方法:

- `whenRegistered`:容器注册前回调,通过该方法获得要注册的容器示例或工厂方法;
- `whenCreated`:容器创建后,通过该方法可以获取创建后即将加入缓存的容器实例;
Expand All @@ -22,7 +20,7 @@

而如果在 Spring 环境,你只需将其交给 Spring 管理即可,在启动后 crane4j 会自动注册。

## 2.Lifecycle回调接口
## 2.容器生命周期接口

除针对全局容器的生命周期处理器外,crane4j 也提供了容器自身生命周期的回调接口 `Container.Lifecycle`,当一个容器类实现了 `Container.Lifecycle` 接口后,相关的回调方法会在这个容器的特定生命周期节点被调用。

Expand Down Expand Up @@ -59,4 +57,52 @@ public class Foo implements Container<String>, Container.Lifecycle {

在上述示例中,我们创建了一个缓存全部字典项的容器 `Foo`,它实现了 `Container.Lifecycle` 接口。

在容器被使用时,会调用 `init()` 方法进行初始化,该方法会查询并缓存字典值。在容器被销毁时,会调用 `destroy()` 方法进行销毁,该方法会清空缓存。
在容器被使用时,会调用 `init()` 方法进行初始化,该方法会查询并缓存字典值。在容器被销毁时,会调用 `destroy()` 方法进行销毁,该方法会清空缓存。

## 3.对象回调接口

从 2.5.0 开始,Crane4j 提供了两个操作感知接口,当你让**被填充的对象**实现上述接口后,该对象中实现的回调方法会在特定的处理阶段被触发:

- `OperationAwareBean`:在执行装配操作前和完成装配操作后,允许你自定义一些逻辑;
- `SmartOperationAwareBean`:前者的增强版本,能够获取到更多的参数;

结合一个简单的例子,你可以感受一下上述回调接口的使用场景:

~~~java
@Data
private static class Bean implements OperationAwareBean {

@Assemble(container = "user", props = @Mapping("name"))
private Integer id;
private String name;
@Assemble(container = "entry", props = @Mapping("value"))
private Integer key;
private String value;
@Disassemble(type = NestedBean.class)
private NestedBean nestedBean;
private String remark;

@Override
public boolean supportOperation(String key) {
// 若 nestedBean 为空,则不进行针对 nestedBean 属性的递归填充
return !Objects.equals("nestedBean", key)
|| Objects.nonNull(this.nestedBean)
}

@Override
public void beforeAssembleOperation() {
// 在填充开始前,若 id 为空,则为其设置一个默认值
if (Objects.isNull(this.id)) {
this.id = 0;
}
}

@Override
public void afterOperationsCompletion() {
// 在完成填充后,对属性值做一些处理
this.name = "尊敬的:" + this.name;
}
}
~~~

通过该回调接口,你可以更灵活的添加一些自定义的逻辑。
Loading

0 comments on commit 0cb988d

Please sign in to comment.