rainsister
  • 신비한 비 Blog
  • Design Pattern
    • Adapter Pattern
    • Proxy Pattern
    • Mediator Pattern
    • Visitor Pattern
    • State Pattern
    • Memento Pattern
    • Factory Pattern
    • Template Pattern
    • Strategy Pattern
    • Bridge Pattern
  • springboot 2.x
    • 메시징 - 큐
      • RabbitMQ 기본설정
      • RabbitMQ 지연 큐(delayed queue)
    • Log
      • 기본 Log 설정 및 Logback 설정
      • Log4j2 사용해보기
      • tinylog 모듈 사용해보기
    • 기타 Database 에 대한 기본가이드
      • PostgreSQL
      • InfluxDB
      • MongoDB
    • 수행속도 UP! 각종 cache 어노테이션 사용법
      • Redis를 사용하여 Cache 관리하기
      • EhCache 사용해보기
      • Thread내캐쉬사용 및 Cache 어노테이션 사용법
    • Database Connection
      • Springboot 2.5 이후 data init script 초기화에 대한 변경
      • JTA 로 JPA 다중 DataSource 트랜잭션 처리 하기
      • Flyway 로 DataBase 형상 관리해보자
      • 트랜잭션 기초읽기
      • MyBatis 의 다중 DataSource
      • Spring Data JPA 다중 DataSource
      • JdbcTemplate 다중 DataSource
      • XML 로 Mybatis 설정하기
      • Mybatis 로 Mysql 연결하기
      • ORM(Spring data jpa)
      • Druid datasource 연결
      • Hikari 설정
      • JdbcTemplate 로 db 접근
    • rest api
      • XML에 대한 요청 및 응답 처리
      • SpringFox 3 및 Swagger 설정
      • 프로젝트 구동 시 RequestMappingHandler 로그 설정
      • Swagger 의 api들을 분류하는 법
      • 간단한 Restful API 만들고 테스트 코드 작성
      • Swagger2 구성하여 API 문서 자동화하기
      • JSR-303 그리고 validation
    • 설정
      • 시작
      • 멀티환경구성에 대한 새로운 방법
      • 멀티환경구성에 대한 새로운 include
      • 프로젝트 설정파일
      • 민감한 정보에 대한 암호화
  • java버전별차이
    • JAVA18
    • JAVA9
    • JAVA10
    • JAVA11
    • JAVA14
    • JAVA15
    • JAVA17
    • JAVA16
  • spring노하우
    • BeanUtils 권장하지 않는이유
    • 개인정보 암호화
    • Springboot 3가지 CROS 설정
    • Springboot 내장된 유용한 Utils
    • Spring Security WebSecurityConfigurerAdapter 가 deprecated 된 이슈해결하기
    • 아직도 HttpUtil ? SpringBoot 3.0의 HTTP Client Util 을 사용해보라
    • JDBC 소스를 뽀개기
    • spring-boot-configuration-processor 는 뭐하는놈임?
    • Apache BeanUtils vs Spring BeanUtils 성능비교
  • Effetive Java 3th
    • Finalizer & Cleaner
Powered by GitBook
On this page
  • 히든 클래스
  • 리텐션(Retention)을 이용하여 위에서 작성한 클래스를 로등하여 히든클래스의 hello함수를 호출할수 있다.
  1. java버전별차이

JAVA15

  • 문자열 처리

문자열 붙이기 과거에는 "" +"" 혹은 StringBuilder 혹은 StringBuffer 객체를 이용해서 무한 append 했었죠.

String html = 
    "<html>\n" +
    "<body>\n"+
    "  <h1>Java 15 새로운 문자열 붙이기...완전 좋네요!</h1>\n"+
    "  <p>didispace.com</p>\n"+
    "</body>\n"+
    "</html>\n";
StringBuilder sb = new StringBuilder();
sb.append("abc");
sb.append("def");
sb.append("ghi");
StringBuffer sb = new StringBuffer();
sb.append("abc");
sb.append("def");
sb.append("ghi");

하지만 JAVA 15부터 아래와 같이 쓸수 있게 되었네요. "" 아닌 """ (3개)를 쓰면 됩니다. 줄바꿈 자유롭게 할수 있습니다.

String html = """
    <html>
    <body>
      <h1>Java 15 새로운 문자열 붙이기...완전 좋네요!</h1>
      <p>didispace.com</p>
    </body>
    </html>
    """;

히든 클래스

다른 class의 bytecode에서 직접 사용할 수 없는 class이다. Hidden class는 runtime에 class를 생성하고 reflection을 통해 간접적으로 사용하는 framework에서 사용하기 위한 것이다. hidden class는 access 제어 중첩의 member로 정의될 수 있으며 다른 class와 독립적으로 unload 될 수 있다.

일반 클래스 하나 생성해 보자

public class JEP371HiddenClasses {

    public static String hello() {
        return "https://rainsister.tistory.com";
    }

}

해당 클래스를 컴파일 하고 나서

String filePath = "JEP371HiddenClasses.class";
byte[] b = Files.readAllBytes(Paths.get(filePath));
log.info(Base64.getEncoder().encodeToString(b));

아래와 같은 코드(문자열)을 얻을 수 있다.

yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==

리텐션(Retention)을 이용하여 위에서 작성한 클래스를 로등하여 히든클래스의 hello함수를 호출할수 있다.

@Test
void testHiddenClasses() throws Throwable {
  // 1.히든클래스 로딩 
  String CLASS_INFO = "yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==";
  byte[] classInBytes = getDecoder().decode(CLASS_INFO);

  Class<?> proxy = MethodHandles.lookup()
    .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
    .lookupClass();

  // class name 
  log.info(proxy.getName());
  // class에 어떤 함수가 있는지 보여주기
  for(Method method : proxy.getDeclaredMethods()) {
    log.info(method.getName());
  }
  // 2. hello함수 호출
  MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "hello", MethodType.methodType(String.class));
  String result = (String) mh.invokeExact();
  log.info(result);
}

여기서 CLASS_INFO 는 아까 출력된 문자열들이다.

일단 Base64 로 해당 코드를 복호화하고 리텐션을 이용하여 히든클래스의 프록시를 생성한다.

Class<?> proxy = MethodHandles.lookup()
    .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
    .lookupClass();

이분을 유심히 살펴보면 히든클래스 생성이랑 ,일반 클래스 생성차이를 알수 있다.

  • bytes:jvm 규격의 바이트 코드.

  • initialize: 클래스 코기화 진행 여부.

  • options:java 클래스 타입 -> 여기를 java.lang.invoke.MethodHandles.Lookup.ClassOption 확인하면 됨.

PreviousJAVA14NextJAVA17

Last updated 8 months ago