SpringBoot整合高性能BeanCopy-Orika工具

8 阅读2分钟

SpringBoot整合高性能BeanCopy-Orika工具

我们在业务中,经常需要转换对象,来解决各种 POJO,VO,DTO 之间的转换,在不使用工具类的情况下,需要写大量的 Get,Set 方法,代码看起来很臃肿.现在也有很多工具类可以让我们来使用,解决这个问题,常用的有 mapstruct、Spring BeanUtils、Apache BeanUtils、dozer 等,今天要介绍的是 orika.

Orika是一个简单、快速的JavaBean拷贝框架,它能够递归地将数据从一个JavaBean复制到另一个JavaBean,这在多层应用开发中是非常有用的。Orika 底层采用了javassist类库生成Bean映射的字节码,之后直接加载执行生成的字节码文件,因此在速度上比使用反射进行赋值会快很多.

  1. MapperFactoryBean
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.Mapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MapperFactoryBean implements FactoryBean<MapperFactory>, ApplicationContextAware {

    ApplicationContext applicationContext;

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public MapperFactory getObject() throws Exception {
        DefaultMapperFactory build = new DefaultMapperFactory.Builder().build();
        for (CustomConverter converter : applicationContext.getBeansOfType(CustomConverter.class).values()) {
            build.getConverterFactory().registerConverter(converter);
        }
        for (Mapper<?, ?> mapper : applicationContext.getBeansOfType(Mapper.class).values()) {
            build.registerMapper(mapper);
        }
        for (ClassMapBuilder<?, ?> mapper : applicationContext.getBeansOfType(ClassMapBuilder.class).values()) {
            build.registerClassMap(mapper);
        }
        return build;
    }

    @Override
    public Class<?> getObjectType() {
        return MapperFactory.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
  1. OrikaConfig
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.converter.BidirectionalConverter;
import ma.glasnost.orika.metadata.Type;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

@Configuration
public class OrikaConfig {
    @Bean
    public MapperFactoryBean loadFactory(){
        return new MapperFactoryBean();
    }

    @Bean
    public MapperFacade loadMapperFacade(MapperFactory factory){
        return factory.getMapperFacade();
    }

    @Autowired
    private MapperFactory mapperFactory;

    /**
     * 解决orika映射LocalDateTime报错问题
     */
    @PostConstruct
    public void init() {
        mapperFactory.getConverterFactory().registerConverter(new LocalDateTimeConverter());
        mapperFactory.getConverterFactory().registerConverter(new LocalDateConverter());
        mapperFactory.getConverterFactory().registerConverter(new LocalTimeConverter());
        mapperFactory.getConverterFactory().registerConverter(new IntegerToBooleanConverter());
    }
    private static class LocalDateTimeConverter extends BidirectionalConverter<LocalDateTime, LocalDateTime> {
        @Override
        public LocalDateTime convertTo(LocalDateTime source, Type<LocalDateTime> destinationType) {
            return LocalDateTime.from(source);
        }
        @Override
        public LocalDateTime convertFrom(LocalDateTime source, Type<LocalDateTime> destinationType) {
            return LocalDateTime.from(source);
        }
    }
    private static class LocalDateConverter extends BidirectionalConverter<LocalDate, LocalDate> {
        @Override
        public LocalDate convertTo(LocalDate source, Type<LocalDate> destinationType) {
            return LocalDate.from(source);
        }
        @Override
        public LocalDate convertFrom(LocalDate source, Type<LocalDate> destinationType) {
            return LocalDate.from(source);
        }
    }
    private static class LocalTimeConverter extends BidirectionalConverter<LocalTime, LocalTime> {
        @Override
        public LocalTime convertTo(LocalTime source, Type<LocalTime> destinationType) {
            return LocalTime.from(source);
        }
        @Override
        public LocalTime convertFrom(LocalTime source, Type<LocalTime> destinationType) {
            return LocalTime.from(source);
        }
    }

    private static class IntegerToBooleanConverter extends BidirectionalConverter<Integer, Boolean> {
        @Override
        public Boolean convertTo(Integer source, Type<Boolean> destinationType) {
            return source != null && source == 1;
        }

        @Override
        public Integer convertFrom(Boolean source, Type<Integer> destinationType) {
            return source ? 1 : 0;
        }
    }
}
  1. OrikaUtil
import ma.glasnost.orika.MapperFacade;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Component
public class OrikaUtil {

    @Resource
    private MapperFacade mapperFacade;
    
    public static MapperFacade staticMapperFacade;

    @PostConstruct
    public void init() {
        staticMapperFacade=mapperFacade;
    }

    public static MapperFacade getMapperFacade() {
        return staticMapperFacade;
    }
}