文章目录
自定义 Reflector 实现可以通过扩展 MyBatis 的 Reflector 实现类来实现对实体类带有自定义注解的属性进行加解密处理。
自定义组件
注解
首先需要定义一个自定义注解,用于标记需要进行加密和解密处理的实体类属性。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EncryptColumn {
}
加解密接口
public interface ColumnEncryptor {
Object encrypt(Object object);
Object decrypt(Object object);
}
实现Reflector
接下来创建一个自定义 Reflector 类,继承 MyBatis 的 Reflector 实现类,并覆盖其 getSetInvoker、getGetInvoker方法,实现对带有 EncryptColumn 注解的属性进行加解密处理。
public class EncryptReflector extends Reflector {
private final Map<String, Field> fieldMap;
private final ColumnEncryptor encryptor;
public EncryptReflector(Class<?> type, ColumnEncryptor encryptor) {
super(type);
this.encryptor = encryptor;
this.fieldMap = new HashMap<>();
for (Field field : type.getDeclaredFields()) {
fieldMap.put(field.getName(), field);
}
}
@Override
public Invoker getSetInvoker(String propertyName) {
log.info("propertyName={}", propertyName);
Invoker invoker = super.getSetInvoker(propertyName);
EncryptColumn encryptColumn = this.getEncryptColumn(propertyName);
if (encryptColumn == null) {
return invoker;
}
return new Invoker() {
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
Object[] decryptArgs = Arrays.stream(args).map(EncryptReflector.this.encryptor::decrypt).toArray();
log.info("property={}, args={}, decryptArgs={}", propertyName, args, decryptArgs);
return invoker.invoke(target, decryptArgs);
}
@Override
public Class<?> getType() {
return invoker.getType();
}
};
}
@Override
public Invoker getGetInvoker(String propertyName) {
Invoker invoker = super.getGetInvoker(propertyName);
EncryptColumn encryptColumn = this.getEncryptColumn(propertyName);
if (encryptColumn == null) {
return invoker;
}
return new Invoker() {
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
Object origin = invoker.invoke(target, args);
Object encrypt = EncryptReflector.this.encryptor.encrypt(origin);
return encrypt;
}
@Override
public Class<?> getType() {
return invoker.getType();
}
};
}
private EncryptColumn getEncryptColumn(String propertyName) {
Field field = this.fieldMap.get(propertyName);
if (field == null) {
return null;
}
return field.getAnnotation(EncryptColumn.class);
}
}
在上述代码中,覆盖了 Reflector 类的getSetInvoker、getGetInvoker方法,当找到带有 EncryptColumn注解的属性时,通过加密和解密函数对属性进行处理,返回加密或解密后的值。
注册Reflector
自定义ConfigurationCustomizer
最后通过实现 ConfigurationCustomizer 的替换 Configuration 中原有的 reflectorFactory(默认采用的DefaultReflectorFactory)。
public class ReflectorConfigurationCustomizer implements ConfigurationCustomizer {
private ColumnEncryptor encryptor;
public ReflectorConfigurationCustomizer(ColumnEncryptor encryptor) {
this.encryptor = encryptor;
}
@Override
public void customize(Configuration configuration) {
configuration.setReflectorFactory(new EncryptReflectorFactory(this.encryptor));
}
}
实现ReflectorFactory类
其中 EncryptReflectorFactory 是自定义的 Reflector 工厂类,其实现如下:
public class EncryptReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
private final ColumnEncryptor encryptor;
private final ConcurrentMap<Class<?>, Reflector> reflectorMap;
public EncryptReflectorFactory(ColumnEncryptor encryptor) {
this.encryptor = encryptor;
this.reflectorMap = new ConcurrentHashMap<>();
}
@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
@Override
public Reflector findForClass(final Class<?> type) {
if (classCacheEnabled) {
return reflectorMap.computeIfAbsent(type, t -> new EncryptReflector(type, this.encryptor));
} else {
return new EncryptReflector(type, this.encryptor);
}
}
}
在上述代码中,通过 ConcurrentHashMap 缓存 Reflector 实例,避免多次创建 Reflector 对象。
编写Configuration类
@Configuration
@ConditionalOnBean(ColumnEncryptor.class)
public class EncryptConfiguration {
public EncryptConfiguration() {
log.info("start encrypt");
}
@Bean
public ConfigurationCustomizer reflectorConfigurationCustomizer(ColumnEncryptor encryptor) {
return new ReflectorConfigurationCustomizer(encryptor);
}
}
通过以上步骤,就可以实现对 MyBatis 实体类带有自定义注解的属性进行加解密处理。
使用方法
使用时需要根据自身业务需求实现ColumnEncryptor,并注册到spring容器
@Component
public class SimpleColumnEncryptor implements ColumnEncryptor {
@Override
public Object encrypt(Object object) {
return object;
}
@Override
public Object decrypt(Object object) {
return object;
}
}