본문 바로가기
스터디정리방

[기록] 220105

by gogumi 2022. 1. 9.

1. 인프라 로직

비즈니스 로직 외의 트랜잭션을 걸고 권한을 체크하는 등의 부가기능을 말한다.
애플리케이션 전 영역에 나타날 수 있다 → 중복 코드
비즈니스 로직과 함께 있으면 비즈니스 로직을 이해하기 어려워진다.

 

횡단 관심사

인프라 로직은 로깅, 트랜잭션, 권한검사, 성능측정 등 하나의 관심사를 갖게 된다.
비즈니스 로직을 수행할 때 인프라 로직의 중복이 횡단으로 나타나기 때문에 이를 cross-cutting concern, 횡단 관심사라고 부른다.


부가기능이라는 것은 횡단의 관심을 가지기 때문에 필수적으로 어떤 부가기능을 어디에 적용해야 하는가라는 질문을 만나게 된다.

aspectJ에서는 메소드가 호출될 때, 실행될 때 필드에 접근할때, 객체가 생성될때 등 다양하게 join point를 구현해놨지만, spring AOP에서는 메소드가 실행될때만으로 한정하고 있다.

2. Spring AOP vs AspectJ

3. Filter, Interceptor, AOP의 차이

 프로그래밍 시 공통 업무는 따로 분리하여 관리하는 것이 좋으며 다음과 같은 세가지를 활용할 수 있다.

  1. Filter
  2. Interceptor
  3. AOP

스프링 프레임워크에서 사용되는 Filter, Interceptor, AOP 세 가지 기능은 모두 요청 실행 전이나 실행 후에 추가적인 행동을 할 때 사용되는 기능들이다.

 

Filter, Interceptor, AOP의 흐름

  1. 서버를 실행시켜 서블릿이 올라오는 동안에 init이 실행되고, 그 후 doFilter가 실행된다.
  2. 컨트롤러에 들어가기 전 preHandler가 실행된다
  3. 컨트롤러에서 나와 postHandler, after Completion, doFilter 순으로 진행이 된다.
  4. 서블릿 종료 시 destroy가 실행된다.

  • Interceptor와 Filter는 Servlet 단위에서 실행된다. 반면 AOP는 메소드 앞에 Proxy 패턴의 형태로 실행된다.
  • 실행 순서를 보면 Filter가 가장 바깥쪽에 있고, 그 안에 Interceptor, 그 안에 AOP가 있는 형태이다.
  • 요청이 들어오면 Filter → Interceptor → AOP → Interceptor → Filter 순으로 거치게 된다.

Filter

Filter는 말 그대로 요청과 응답을 거른 뒤 정제하는 역할을 한다. 서블릿 필터는 DispatcherServlet 이전에 실행이 되는데 필터가 동작하도록 지정된 자원의 앞단에서 요청내용을 변경하거나, 여러가지 체크를 수행할 수 있다. 또한 자원의 처리가 끝난 후 응답내용에 대해서도 변경하는 처리를 할 수가 있다. 보통 web.xml에 등록하고, 일반적으로 인코딩 변환 처리, XSS방어 등의 요청에 대한 처리로 사용된다.

  • init() - 필터 인스턴스 초기화
  • doFilter() - 전/후 처리
  • destroy() - 필터 인스턴스 종료

Interceptor

Interceptor는 요청에 대한 작업 전/후를 가로챈다. 필터는 스프링 컨텍스트 외부에 존재하여 스프링과 무관한 자원에 대해 동작한다. 하지만 Interceptor는 스프링의 DispatcherServlet이 컨트롤러를 호출하기 전, 후로 끼어들기 때문에 스프링 컨텍스트 내부에서 Controller(Handler)에 관한 요청과 응답에 대해 처리하며 스프링의 모든 빈 객체에 접근할 수 있다. Interceptor는 여러 개를 사용할 수 있고 로그인 체크, 권한 체크, 로그 확인 등의 업무 처리로 사용한다.

  • preHandler() - 컨트롤러 메서드가 실행되기 전
  • postHandler() - 컨트롤러 메서드 실행 직 후 view 페이지 렌더링 되기 전
  • afterCompletion() - view 페이지가 렌더링 되고 난 후

AOP

AOP는 객체 지향의 프로그래밍을 했을 때, 중복을 줄일 수 없는 부분을 줄이기 위해 종단면(관점)에서 바라보고 처리한다. 주로 로깅, 트랜잭션, 에러 처리 등 비즈니스단의 메서드에서 조금 더 세밀하게 조정하고 싶을 때 사용한다.

Interceptor와 Filter와 달리 메소드 전 후의 지점에 자유롭게 설정이 가능하며 주소, 파라미터, 어노테이션 등 다양한 방법으로 대상을 지정할 수 있다. 반면 HandlerInterceptor는 Filter와 유사하게 HttpServletRequest, HttpServletResponse를 파라미터로 사용한다.

  • @Before - 대상 메서드의 수행 전
  • @After - 대상 메서드의 수행 후
  • @After-returning - 대상 메서드의 정상적인 수행 후
  • @After-throwing - 예외발생 후
  • @Around - 대상 메서드의 수행 전/후

 

4. AOP

: AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다.
관점 지향은 쉽게 말해 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이다.
여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다.

 

AOP의 주요 개념

Aspect : 여러 객체에 공통적으로 적용되는 관심사항으로써 위에서 설명한 흩어진 관심사를 모듈화 한 것. 주로 부가기능을 모듈화함. (Advice + PointCut = Aspect)
Target : Aspect를 적용하는 곳 (클래스, 메서드 .. )
Advice : 실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
JointPoint : 프로그램이 실행 중일 때 발생하는 메서드 실행, 생성자 호출, 필드 값 변경과 같은 특수한 지점을 의미함.
(Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능)
PointCut : JointPoint의 상세한 스펙을 정의한 것(정규표현식). 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음
(JoinPoint가 Pointcut에 일치할 때마다 해당 Pointcut에 관련된 Advice가 실행됨.)
Weaving : Aspect를 대상 객체에 연결시켜 관점지향 객체로 만드는 과정을 의미함.
(Advice를 비즈니스 로직 코드에 삽입하는것을 의미함)
Advisor : SpringAOP에서만 사용되는 특별한 용어로 Advice + PointCut

 

Spring AOP와 AspectJ 비교하기

Spring Aop와 AspectJ는 목적 자체가 다름.

Spring Aop는 개발자가 마주한 공통적인 문제를 해결하고자 Spring IOC를 통한 간단한 AOP 구현이 그 목적.
완전한 AOP를 의도한 것이 아니며, Spring Container에 의해 관리되는 Beans에만 적용이 가능함.
Proxy 기반 AOP 프레임 워크이며 메서드 조인 포인트만 지원함.(JoinPoint가 메서드 호출 시점도 안되고 메서드 실행시에만 지원됨.)
AspectJ에 비해 훨씬 느리지만 배우고 적용하기 쉽다.

반면 AspectJ 는 완전한 AOP를 제공하는 것이 목적인 근원적인 AOP기술.
Spring AOP보다 복잡하긴 하지만 모든 객체에 적용이 가능하고 성능이 더 좋다.

AspectJ는 세가지 방식의 Weaving을 사용할 수 있습니다.
-컴파일 시점 Weaving
-컴파일 후 Weaving
-로드시점 Weaving

Spring Aop는 런타임 Weaving을 사용합니다.
-런타임 시점 Weaving

 

5. 프록시 패턴

: Proxy는 우리말로 대리자, 대변인 이라는 뜻으로 프록시에게 어떤 일을 대신 시키는 것입니다.
객체에 직접 접근하지 않고 앞단에 프록시를 하나 둠으로써 시큐리티 로직, 로깅 등의 로직을 공통으로 넣기가 편합니다.

-proxy example

//IService.java
public interface IService {
	String runSomething();
}
//Service.java
public class Service implements IService {
	@Override
	public String runSomething() {
		return "서비스 짱!!!";
	}
}
//Proxy.java
public class Proxy implements IService {
	IService service1;

	@Override
	public String runSomething() {
		System.out.println("호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달");
		service1 = new Service();
		return service1.runSomething();
	}
}
//Main.java
public class Main {  	
public static void main(String[] args) { 		
	//직접 호출하지 않고 프록시를 호출한다. 		
	IService proxy = new Proxy(); 		
	System.out.println(proxy.runSomething()); 	
	}
}
}

인터페이스를 중간에 두어 구체 클래스들에게 영향을 받지 않도록 설계하였고,
직접 접근하지 않고 Proxy를 통해서 한번 더 우회해서 접근하도록 객체 지향적으로 설계.

 

6. 데코레이터 패턴

: 데코레이터 패턴(Decorator pattern)이란 주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로,
기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있다.

-decorator example

// the Window interface
interface Window {
    public void draw(); // draws the Window
    public String getDescription(); // returns a description of the Window
}

// implementation of a simple Window without any scrollbars
class SimpleWindow implements Window {
    public void draw() {
        // draw window
    }

    public String getDescription() {
        return "simple window";
    }
}
// abstract decorator class - note that it implements Window
abstract class WindowDecorator implements Window {
    protected Window decoratedWindow; // the Window being decorated

    public WindowDecorator (Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }
}

// the first concrete decorator which adds vertical scrollbar functionality
class VerticalScrollBarDecorator extends WindowDecorator {
    public VerticalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }

    public void draw() {
        drawVerticalScrollBar();
        decoratedWindow.draw();
    }

    private void drawVerticalScrollBar() {
        // draw the vertical scrollbar
    }

    public String getDescription() {
        return decoratedWindow.getDescription() + ", including vertical scrollbars";
    }
}

// the second concrete decorator which adds horizontal scrollbar functionality
class HorizontalScrollBarDecorator extends WindowDecorator {
    public HorizontalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }

    public void draw() {
        drawHorizontalScrollBar();
        decoratedWindow.draw();
    }

    private void drawHorizontalScrollBar() {
        // draw the horizontal scrollbar
    }

    public String getDescription() {
        return decoratedWindow.getDescription() + ", including horizontal scrollbars";
    }
}
public class DecoratedWindowTest {
    public static void main(String[] args) {
        // create a decorated Window with horizontal and vertical scrollbars
        Window decoratedWindow = new HorizontalScrollBarDecorator (
                new VerticalScrollBarDecorator(new SimpleWindow())); // 데코 형태

        // print the Window's description
        System.out.println(decoratedWindow.getDescription());
    }
}

 

7. 프록시

프록시란 단어는 대리자, 대변인 이라는 뜻을 가진 단어로 프록시 패턴에도 그 의미가 고스란히 담겨있다. 프록시 패턴은 누군가를 대신해 그 역할을 수행하는 것을 말한다.

클라이언트가 사용하려고 하는 실제 대상을 직접적으로 접근하지 않고 프록시를 통해서 요청을 받아주는 것을 말한다.

그렇게 프록시를 통해서 최종적으로 요청을 위임받아 추러히난 실체 객체를 타깃 또는 실체라고 부른다.

💡 프록시 는 사용 목적에 따라 분리될 수 있음 1. 클라이언트가 타깃에 접근하는 방법을 제어하기 위함 (프록시 패턴) 2. 타깃에 부가적인 기능을 부여해주기 위함 (데코레이터 패턴)

프록시 패턴
  • 프록시를 사용하는 방법 중에서 타깃에 대한 접근 방법을 제어하려는 목적을 가진 경우
  • 프록시 패턴은 타깃의 기능을 확장하거나 추가하지 않는다.
    • 클라이언트가 타깃에게 접근하는 방식을 변경해준다.
  • 실제 타깃 객체가 가진 메소드와 같은 이름의 메소드를 사용한다.
  • 인터페이스를 사용하면 클라이언트 쪽에서는 실제 타깃 객체를 누가 처리해서 값은 반환해주는지 모르게 처리할 수 있다.
// IService 인터페이스 
public interface IService {

    String runSomething();
}
// Service 클래스 (타깃)
public class Service implements IService {

    @Override
    public String runSomething() {
        return "Proxy Pattern";
    }
}
// Proxy 클래스 (프록시)
public class Proxy implements IService {

    IService service1;

    @Override
    public String runSomething() {
        System.out.println("호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달");

        service1 = new Service();
        return service1.runSomething();
    }

}
// 실행클래스
package study.weeok09.pattern;

public class ClientWithProxy {

    public static void main(String[] args) {
        // 프록시를 이용한 호출
        IService proxy = new Proxy();
        System.out.println(proxy.runSomething());
        
    }
}

// 결과
호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달
Proxy Pattern

  • 프록시 객체는 타깃과 같은 이름의 메소드 구현한다.
  • 프록시 객체는 타깃의 같은 이름을 가진 메소드를 호출하고 그 값을 클라이언트에게 돌려준다.
  • 타깃은 실제 서비스의 메소드 호출 전 후에 별도의 로직을 수행할 수 있다.

"제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 것"

프록시 패턴은 개방 폐쇄의 원칙(OCP)과 역전 의존의 원칙(DIP)이 적용된 디자인 패턴이다.

 

8. 데코레이터 패턴(Decorator Pattern)

  • 프록시를 사용하는 방법 중 하나로 클라이언트가 받는 반환값에 장식을 덧입히는 것을 말한다.
// IService 인터페이스
public interface IService {

    public abstract String runSomething();
}
// Service 클래스 (타깃)
public class Service implements IService{

    @Override
    public String runSomething() {
        return "서비스 짱!";
    }
}
// Decoreator 클래스
public class Decoreator implements IService{

    IService service;

    @Override
    public String runSomething() {
        System.out.println("호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달");
        service = new Service();
        return "정말" + service.runSomething(); // "정말"이라는 장식을 더함
    }
}
// 실행클래스
public class ClientWithDecolator {

    public static void main(String[] args) {
        IService decoreator = new Decoreator();
        System.out.println(decoreator.runSomething());
    }
}

// 결과
호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달
정말서비스 짱!
  • Wrapper Class는 타깃의 같은 이름을 가진 메서드를 호출하고, 그 반환값에 장식을 더해 클라이언트에게 돌려준다.
  • 데코레이터 객체는 타깃의 메서드 호출 전후로 별도의 로직을 수행할 수도 있다.

"메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴"

프록시 패턴은 개방 폐쇄의 원칙(OCP)과 역전 의존의 원칙(DIP)이 적용된 디자인 패턴이다.

 

9. AspectJ & Spring AOP

AOP 개념

  • Aspect : 어플리케이션의 여러위치에흩어져있고, 일반적으로 실제 비즈니스 로직(예. 트랜잭션 관리, 캐싱)과 다른 표준 코드, 기능이다. 각 Aspect는 Cross-Cutting 기능에 중점을 둔다. (여러 객체에 공통 적용되는 부가 기능의 관심사항)(cf. 핵심로직)
  • Joinpoint: 프로그램 실행 중 특정 지점이다. (예. 메서드 실행, 생성자 호출, 또는 필드 할당 )
  • Advice: 특정 Joinpoint에서 Aspect가 취한 조치
  • Pointcut:  Joinpoint과일치하는 정규식,Joinpoint가 Pointcut과 일치할때마다 해당Pointcut과 관련된 지정된 Advice가 실행된다.
  • Weaving: Advice된 객체를 생성하기 위해 대상 객체와 Aspect을 연결하는 프로세스이다.

기능과 목표 차이

  • Spring AOP
    • Spring AOP와 AspectJ는 다른 목표를 가지고 있다.
    • Spring AOP는 프로그래머가 직면하는 가장 일반적인 문제를 해결하기 위해 Spring IoC에서 간단한 AOP 구현을 제공하는 것을 목표로 한다.
    • 완전한 AOP 솔루션 이 아니라 Spring 컨테이너가 관리하는 Bean에만 적용 할 수 있다.
  • AspectJ
    • AspectJ는 완전한 AOP 솔루션을 제공하는 것을 목표로하는 독창적 인 AOP 기술이다.
    • Spring AOP보다 훨씬 더 복잡하다.
    • AspectJ가 모든 도메인 객체에 적용될 수 있다.

Weaving

  • Spring AOP
    • 런타임 Weaving을 사용한다.
    • 프록시 패턴 기반으로 한다.
    • Runtime weaving: Aspect 가 대상 객체의 Proxy(JDK 동적 Proxy 나 CGLIB 의 Proxy)를 실행시 Weaving 된다.
  • AspectJ
    • Compile-time weaving : AspectJ 컴파일러는 우리의 aspect와 우리 애플리케이션의 소스 코드를 입력으로 취하고 출력으로 엮인 클래스 파일을 생성
    • Post-compile weaving : (컴파일 후 위빙): binary weaving.이라고도한다. 기존 클래스 파일과 JAR 파일을 위빙하는데 사용한다.
    • Load-time weaving : 클래스 로더가 클래스 파일을 JVM에로드 할 때까지 weaving이 연기된다는 점이 다르다.
    • 런타임때 아무것도 안한다. Aspect를 코드에 Weaving하기 위해, AspectJ compiler(ajc)라는 컴파일러를 도입한다. 이 컴파일러를 통해 프로그램을 컴파일하고 작은 런타임 라이브러리를 추가해 동작시킨다.

SpringAOP VS AspectJ 비교표

10. 데코레이터 패턴 예제

데코레이터 패턴은 상속과 합성을 사용하여 객체에 동적으로 책임을 추가할 수 있게 한다. 이 방법은 서브 클래스를 생성하는 것보다 유연한 방법을 제공한다.

 

데코레이터 패턴의 예제

public class DecoratorPatternTest {
 
	public static void main(String[] args) {
		Car sportsCar = new SportsCar(new BasicCar());
		sportsCar.assemble();
		System.out.println("\n*****");
		
		Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
		sportsLuxuryCar.assemble();
	}
}

런타임 단계에서 Sports Car의 특징과 Luxury Car의 특징을 모두 갖고 있는 Car를 가지게 되었다. 이렇게 작성할 경우 종류가 많아질 수록 큰 효과를 발휘할 수 있다.

 

중요 포인트

  • 데코레이터 패턴은 런타임에서 유연하게 객체의 기능들을 수정하고 조합하는데 유용하게 사용되는 패턴이다.
  • 단점이 있다면, 다수의 데코레이터 객체를 생성하고 사용해야 한다는 것이다.
  • JDK 에서 FileReader, BufferedReader 등 IO 클래스에 사용되는 패턴이다.

 

10. 리플렉션 사용법 정리

 

Reflection은 다음과 같은 정보를 가져올 수 있다. 이 정보를 가져와서 객체를 생성하거나 메소드를 호출하거나 변수의 값을 변경할 수 있다.

Class

Constructor

Method

Field

 

아래는 예제는 클래스, 생성자, 메소드, 필드의 정보를 가져오는 것부터 필드의 값을 변경, static 메소드 호출 등을 해보는 것에 대한 튜토리얼이다.

 

준비

 

Parent.java

package test;

public class Parent {
    private String str1 = "1";
    public String str2 = "2";

    public Parent() {
    }

    private void method1() {
        System.out.println("method1");
    }

    public void method2(int n) {
        System.out.println("method2: " + n);
    }

    private void method3() {
        System.out.println("method3");
    }
}

Child.java

package test;

public class Child extends Parent {
    public String cstr1 = "1";
    private String cstr2 = "2";

    public Child() {
    }

    private Child(String str) {
        cstr1 = str;
    }

    public int method4(int n) {
        System.out.println("method4: " + n);
        return n;
    }

    private int method5(int n) {
        System.out.println("method5: " + n);
        return n;
    }
}

Test.java

Test 클래스의 main에서 reflection을 사용할 것. 아래와 같이 다음 3개의 클래스를 import해야 한다.

java.lang.reflect.Method

java.lang.reflect.Field

java.lang.reflect.Constructor

package test;

import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;

class Test {

    public static void main(String args[]) throws Exception {

    }
}

생성자 찾기

인자 없는 생성자 찾기

Class clazz = Class.forName("test.Child");
Constructor constructor = clazz.getDeclaredConstructor();
System.out.println("Constructor: " + constructor.getName());

파라미터 정보로 생성자 찾기

Class clazz = Class.forName("test.Child");
Constructor constructor2 = clazz.getDeclaredConstructor(String.class);
System.out.println("Constructor(String): " + constructor2.getName());

메소드 찾기

 

파라미터가 없는 메소드 찾기

Class clazz = Class.forName("test.Child");
Method method1 = clazz.getDeclaredMethod("method4", null);

파라미터 정보로 메소드 찾기

Class clazz = Class.forName("test.Child");
Method method1 = clazz.getDeclaredMethod("method4", int.class);
System.out.println("Find out method4 method in Child: " + method1);

파라미터 정보로 메소드 찾기

Class clazz = Class.forName("test.Child");
Class partypes[] = new Class[1];
partypes[0] = int.class;
Method method = clazz.getDeclaredMethod("method4", partypes);

파라미터가 두개 이상인 메소드 찾기

Class clazz = Class.forName("test.Child");
Class partypes[] = new Class[1];
partypes[0] = int.class;
Method method = clazz.getDeclaredMethod("method4", partypes);

상속받은 메소드 포함하여 모두 찾기

Class clazz = Class.forName("test.Child");
Method methods2[] = clazz.getMethods();
for (Method method : methods2) {
    System.out.println("Get public methods in both Parent and Child: " + method);
}

필드찾기

Class clazz = Class.forName("test.Child");
Field field = clazz.getDeclaredField("cstr1");
System.out.println("Find out cstr1 field in Child: " + field);

객체에 선언된 모든 필드 찾기

Class clazz = Class.forName("test.Child");
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("Get fields in Child: " + field);
}

상속받은 public 필드 포함하여 모두 찾기

Class clazz = Class.forName("test.Child");
Field fields2[] = clazz.getFields();
for (Field field : fields2) {
    System.out.println("Get public fields in both Parent and Child: " + field);
}

필드 변경

필드 값 수정하기

Child child = new Child();
Class clazz = Class.forName("test.Child");
Field fld = clazz.getField("cstr1");
System.out.println("child.cstr1: " + fld.get(child));

fld.set(child, "cstr1");
System.out.println("child.cstr1: " + fld.get(child));

private 필드 값 수정하기 (접근 상태 변경 후 수정)

Child child = new Child();
Class clazz = Class.forName("test.Child");
Field fld2 = clazz.getDeclaredField("cstr2");
fld2.setAccessible(true);    // 접근 상태 변경
fld2.set(child, "cstr2");
System.out.println("child.cstr2: " + fld2.get(child));

Static 메소드 호출 또는 필드 변경

튜토리얼 진행 전 Static 클래스 추가

package test;

public class StaticExample {
    public static String EXAMPLE = "Example";

    public static int getSquare(int num) {
        System.out.println("Get square: " + num * num);
        return num * num;
    }
}

static 메소드 호출(invoke()의 객체 전달하는 인자에는 null을 넣어준다.)

Class clazz = Class.forName("test.StaticExample");
Method method = clazz.getDeclaredMethod("getSquare", int.class);
method.invoke(null, 10);

static 필드 찾기 및 변경

Class clazz = Class.forName("test.StaticExample");
Field fld = clazz.getDeclaredField("EXAMPLE");
fld.set(null, "Hello, World");
System.out.println("StaticExample.EXAMPLE: " + fld.get(null));

 

 

 

References

필터, 인터셉터, AOP의 차이

제이의 Spring AOP

토비스프링 AOP 정리
우아한형제들 AOP
스프링 AOP 총정리
프록시패턴 정의
백기선님강의-프록시패턴
Enable Aspectj document
Spring AOP 와 AspectJ 비교
데코레이터 패턴

데코레이터 패턴의 예시

 

 

'스터디정리방' 카테고리의 다른 글

[기록] 220119  (0) 2022.01.25
[기록] 220112  (0) 2022.01.16
[기록] 211229  (0) 2022.01.02
[기록] 211222  (0) 2021.12.26
[기록] 211215  (0) 2021.12.18

댓글