스프링에서는 @Configuration을 사용하면 해당 클래스 내부의 @Bean의 인스턴스를 cglib로 등록하게 된다.
이에 대해서 cglib에 대해서 깊이 있게 공부하는 시간을 갖고자 한다.
https://github.com/cglib/cglib
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
https://github.com/cglib/cglib/blob/master/cglib/src/main/java/net/sf/cglib/beans/BeanGenerator.java
References
https://www.baeldung.com/cglib
'Spring > Spring' 카테고리의 다른 글
(SPRING) getBean()에 대해서 (0) | 2020.03.23 |
---|---|
(SPRING) Dynamically register bean (0) | 2020.03.22 |
(SPRING) 빈의 스코프 (0) | 2020.03.22 |
(SPRING) Spring ApplicationContext의 내부 (2) (0) | 2020.03.01 |
(SPRING) Spring ApplicationContext의 내부 (1) (1) | 2020.03.01 |