본문 바로가기

Spring/Spring

(SPRING) cglib에 대해서 (with Enhancer)

스프링에서는 @Configuration을 사용하면 해당 클래스 내부의 @Bean의 인스턴스를 cglib로 등록하게 된다.
이에 대해서 cglib에 대해서 깊이 있게 공부하는 시간을 갖고자 한다.

https://github.com/cglib/cglib

 

cglib/cglib

cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept f...

github.com

 

cglib는 하이버 데이터 혹은 스프링과 같은 자바 프레임워크에서 사용하는 바이트코드 조작 라이브러리이다.
이러한 바이트 코드를 조작하는 기법은 프로그램의 컴파일 단계 이후에 클래스를 조작하거나 작성할 수 있게끔 도와준다.

Maven Dependency

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.4</version>
</dependency>

Cglib

자바의 클래스들은 런타임에 동적으로 로드된다.

Cglib는 이미 구동 중인 자바 프로그램에 새로운 클래스를 생성하는 것을 가능하게끔 도와준다.

 

Cglib 구현

단순하게 String을 리턴하는 메서드와 해당 String의 길이를 리턴하는 메서드를 구현한다.

public class PersonService {
    public String sayHello(String name) {
        return "Hello" +name;
    }

    public Integer lengthOfName(String name) {
        return name.length();
    }
}

 

1. 런타임 시 Intercept

 

Enhancer 인스턴스를 생성하여 런타임 시 해당 결과 값을 설정

@Test
public void CglibEx() {

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(PersonService.class);
    enhancer.setCallback((FixedValue) () -> "Hello Junwoo !!");
    PersonService personService = (PersonService) enhancer.create();

    String res = personService.sayHello(null);

    assertEquals("Hello Junwoo !!", res);
}

실행결과 정상적으로 작동하는 것을 볼 수 있다.

2. 메서드 시그니처에 따라서 Intercept

 

Object 클래스에 대한 예외처리를 한다. (hashCode, toString에 대한 Interceptor를 방지하기 위해 )

리턴 타입에 따른 분기를 태워서 String, Integer일 때를 구분하여 사용한다.

@Test
public void CglibEx2() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(PersonService.class);
    enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {

        if (method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
            return "Hello Junwoo!!";
        } else {
            return proxy.invokeSuper(obj, args);
        }
    });

    PersonService personService = (PersonService) enhancer.create();

    assertEquals("Hello Junwoo!!", personService.sayHello(null));
    Integer integer = personService.lengthOfName("Junwoo");

    assertEquals(6, integer);
}

실행결과 정상적으로 작동하는 것을 볼 수 있다.

3. BeanGenerator의 Cglib의 사용

 

@Test
public void Cglib3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    BeanGenerator beanGenerator = new BeanGenerator();

    beanGenerator.addProperty("name", String.class);
    Object myBean = beanGenerator.create();
    Method setter = myBean.getClass().getMethod("setName", String.class);
    setter.invoke(myBean, "operating Cglib...!");

    Method getter = myBean.getClass().getMethod("getName");
    assertEquals("operating Cglib...!", getter.invoke(myBean));

}

실행결과 정상적으로 작동하는 것을 볼 수 있다.


Code Link

https://github.com/mike6321/Spring/tree/master/spring-core

 

mike6321/Spring

Contribute to mike6321/Spring development by creating an account on GitHub.

github.com

https://github.com/cglib/cglib/blob/master/cglib/src/main/java/net/sf/cglib/beans/BeanGenerator.java

 

cglib/cglib

cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept f...

github.com

References

https://www.baeldung.com/cglib

 

Introduction to cglib | Baeldung

Overview of cglib, the popular code generation library, its features and most common use cases

www.baeldung.com