1.매번인터페이스 구현 2.중복발생
의 문제를 해결해주게 된다.런타임
에 생성되는 프록시 객체를 의미한다.리플렉션
을 사용한다자바에서는 JVM이 실행되면 사용자가 작성한 자바 코드가 컴파일러를 거쳐 바이트 코드로 변환되어 static 영역에 저장됩니다.
Reflection API는 이 정보를 활용합니다. 그래서 클래스 이름만 알고 있다면 언제든 static 영역을 뒤져서 정보를 가져올 수 있는 것입니다.
자바에서 다이나믹 프록시를 만드는 방법
ParentInterface parentInterface = (ParentInterface)Proxy.newProxyInstance(HelloApplication.class.getClassLoader(), new Class[]{ParentInterface.class}, (proxy, method, args) -> {
System.out.println("메소드 수행전에 할일");
Object methodResult = method.invoke(new ChildClass(), args);//child라는 class에 args를 모두 넘긴다
if(method.getName() == "sayHello"){//메서드 이름에 따라.. 처리를 분류할 수 있으니 다 정의하지 않아도됨 모든 메서드에 대해 기본적으로 정의되는거니까 중복도 피할 수 있음
System.out.println("sayHello!");
return methodResult;
}
System.out.println("sayOne!");
return methodResult;
});
parentInterface.sayHello();
//클라이언트는 인터페이스타입에 대해 그 메서드를 호출한다 이 인터페이스에 대한 메서드를 호출하면 위에서 정의한대로 프록스 객체를 런타임에 하나 만들어줘서
//위에서 정의한 대로의 로직을 타고 클라이언트에게 결과를 전송해준다
parentInterface.sayOne();
스프링 aop는 자바가 제공하는 다이나믹 프록시만 제공하는게 아니라 스프링빈중에 인터페이스를 상속받지않는
클래스에대해서도 프록시를 적용해야한다하면 cglib을 사용
@Test
void makeClassProxy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<? extends Class1> proxyClass = new ByteBuddy().subclass(Class1.class)
.method(named("sayHello")).intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("aaa");
Object result = method.invoke(new Class1(), args);
System.out.println("bbb");
return result;
}
}))
.make().load(Class1.class.getClassLoader()).getLoaded();
Class1 class1 = proxyClass.getConstructor(null).newInstance();
class1.sayHello();
}
AOP는 관점지향 프로그래밍이라는으로 "기능을 핵심 비즈니스 기능과 공통기능으로 '구분’하고,모든 비즈니스 로직에 들어가는 공통기능의 코드를 개발자의 코드 밖에서 필요한 시점에 적용하는 프로그래밍 방식입니다.
Spring 에서 AOP 구현체들을 제공해주고 있는데, JDK Dynamic Proxy 와 CGlib 을 통해 Proxy화 합니다.