프로젝트에서 MapStruct 패키지 사용

6833 단어 javabean
MapStruct는 일반적으로 서로 다른 계층 모델의 객체 속성 복제에 사용되는 객체 속성 복제 도구입니다.
인터넷에서 다른 사람이 테스트한 성능 대비를 해봤어요.
pc 구성: i7,16G 메모리 다양한 Bean 복사 도구 비교
공구.
10개의 객체 복제 1회
1만 개 대상 1회 복사
백만 개체 복제 1회
백만 개체 복사 5회
mapStruct
0ms
3ms
96ms
281ms
hutools의 BeanUtil
23ms
102ms
1734ms
8316ms
spring의 BeanUtils
2ms
47ms
726ms
3676ms
아파치의 BeanUtils
20ms
156ms
10658ms
52355ms
apache의 PropertyUtils
5ms
68ms
6767ms
30694ms
출처: MapStruct 사용 및 성능 테스트, BeanUtil 스톱

기본 사용


종속 구성


pom.xml 설정 아래 내용, 예에서 lombok을 사용했기 때문에 저는 lombok의 설정도 추가했습니다.

    
        1.4.2.Final
        1.18.20
    

    
        
            org.projectlombok
            lombok
            ${lombok.version}
            true
         
        
            org.mapstruct
            mapstruct
            ${org.mapstruct.version}
        
    
    
    

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    
                        
                            org.projectlombok
                            lombok
                            ${lombok.version}
                        
                        
                            org.mapstruct
                            mapstruct-processor
                            ${org.mapstruct.version}
                        
                    
                
            
        
    
    

관례

@Data
public class Car {
 
    private String make;
    private int numberOfSeats;
    private CarType type;

}

@Data
public class CarDto {
 
    private String make;
    private int seatCount;
    private String type;
 
}

@Mapper
public interface CarMapper {
 
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
 
    //  , @Mapping 
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}

@Test
public void shouldMapCarToDto() {
    //given
    Car car = new Car("Morris", 5, CarType.SEDAN);
 
    //when
    CarDto carDto = CarMapper.INSTANCE.carToCarDto(car);
 
    //then
    assertThat(carDto).isNotNull();
    assertThat(carDto.getMake()).isEqualTo( "Morris");
    assertThat(carDto.getSeatCount()).isEqualTo(5);
    assertThat(carDto.getType()).isEqualTo("SEDAN");
}

봉인


위의 예에서 매번 사용할 때마다 한 번Mapper.INSTANCE을 호출해야만 Mapper를 얻을 수 있다. 그러면 Mapper는 업무 코드와 결합되어 나중에 다른 도구를 교체하는 데 불리하다.우리는 대상 속성 복제 기능을 하나의 인터페이스Convert로 추상화할 수 있다. 모든 빈은 Convert의 하위 클래스이기 때문에 모든 빈은 대상 전환 능력을 가진다.
public interface Convert extends Serializable {
    /**
     *  JavaBean 
     *
     * @param clazz class 
     * @param     
     * @return  
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    default  T convert(Class clazz) {
        BeanConvertMapper mapper = BeanConvertMappers.getMapper(this.getClass(), clazz);
        return (T) mapper.to(this);
    }
}
BeanConvertMapper 대상 전환 인터페이스를 정의했다
public interface BeanConvertMapper {

    /**
     * source to target
     *
     * @param source source
     * @return target
     */
    TARGET to(SOURCE source);

}
BeanConvertMappers는 도구 종류로 Class Class를 통해 Mapper를 얻는 방법을 제공한다.
@SuppressWarnings({"rawtypes", "unchecked"})
public class BeanConvertMappers {

    public static  BeanConvertMapper getMapper(Class sourceClass, Class targetClass) {
        String key = MapperDefinition.generateKey(sourceClass, targetClass);
        Class mapperClass = MapperDefinition.getMappers().get(key);
        if (mapperClass == null) {
            throw new IllegalArgumentException(StrUtil.format(" {} {} Mapper", sourceClass.getName(), targetClass.getName()));
        }
        return (BeanConvertMapper) Mappers.getMapper(mapperClass);
    }

}
MapperDefinition 모든 유지보수Mapper, 신규 Mapper는 맵에 등록하면 됩니다.
@SuppressWarnings("rawtypes")
public class MapperDefinition {

    private static Map MAPPERS = new HashMap<>(16);

    static {
        registerMapper(CarDto.class, Car.class, CarDtoToCarMapper.class);
        //  Mapper 
        MAPPERS = MapUtil.unmodifiable(MAPPERS);
    }



    /* Mapper  */

    @Mapper
    public interface CarDtoToCarMapper extends BeanConvertMapper {
    }
    
    /* Mapper  */


    public static Map getMappers() {
        return MAPPERS;
    }


    public static  String generateKey(Class sourceClass, Class targetClass) {
        return sourceClass.getName() + targetClass.getName();
    }

    private static  void registerMapper(Class sourceClass, Class targetClass, Class extends BeanConvertMapper> mapperClass) {
        MAPPERS.put(generateKey(sourceClass, targetClass), mapperClass);
    }
}

한층 더 최적화하다


위의 봉인은 Mapper 결합 문제를 해결했지만 Mapper를 정의할 때 대량의 템플릿 인터페이스가 존재하기 때문에 더 좋은 방법으로 해결할 수 있습니까?
내가 생각한 방안은 다음과 같다.
mapstruct 원리와 마찬가지로 mapstruct의 주석 프로세서에 앞서 주석을 통해 BeanConvertMapper 인터페이스를 생성하고 주석은 대체로 다음과 같으며 맵에 자동으로 주입됩니다.Mapper를 추가하려면 메모 하나만 정의하면 됩니다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface MapperDefinition {

    /**
     *  Class
     * 
     * @return Class
     */
    Class> source();

    /**
     *  Class
     * 
     * @return Class
     */
    Class> target();
}

더 좋은 방안이 있습니까? 함께 공유하세요.

좋은 웹페이지 즐겨찾기