[25.1.2 TIL] ์ฑŒ๋ฆฐ์ง€ ์„ธ์…˜ - Spring๊ณผ Proxy

01. Proxy๋ž€ ?

  • ๋Œ€๋ฆฌ์ธ, ์ค‘๊ฐœ์ž
  • ํด๋ผ์ด์–ธํŠธ / ํ˜ธ์ถœ์ž์˜ ์š”์ฒญ์„ ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ์—ญํ• 

 

Diagram

 

Code

public class Service {
	public void perform() {
		// ์‹ค์ œ ๋กœ์ง
	}
}

//ํ”„๋ก์‹œ ๊ฐ์ฒด
public class ServiceProxy implements Service {

    private final Service target = new Service();

    public void perform() {
        // ์‚ฌ์ „ ์ฒ˜๋ฆฌ
        target.perform();
        // ์‚ฌํ›„ ์ฒ˜๋ฆฌ
    }
}

 

 

02. Spring Framework์—์„œ์˜ Proxy

1. Proxy ์ƒ์„ฑ ๋ฐฉ๋ฒ•

1) JDK Dynamic Proxy

  • ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘
  • ๋Œ€์ƒ ํด๋ž˜์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ
  • java.lang.reflect.Proxy ํด๋ž˜์Šค ํ™œ์šฉ

2) CGLIB Proxy

  • ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘
  • ๋Œ€์ƒ ํด๋ž˜์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์‚ฌ์šฉ
  • ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘์„ ํ†ตํ•ด ํ•˜์œ„ ํด๋ž˜์Šค ์ƒ์„ฑ

 

2. AOP (Aspect-oriented Programming)

  • ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋™์ผํ•œ ๋กœ์ง์„ ๊ณตํ†ต์ ์œผ๋กœ ์ฒ˜๋ฆฌ / ๊ด€๋ฆฌ ๋ชจ๋“ˆํ™”๋ฅผ ํ•˜๊ธฐ ์œ„ํ•œ Framework
  • OOP์˜ ํ•œ๊ณ„๋ฅผ ๊ทน๋ณตํ•˜์—ฌ ๊ธฐ๋Šฅ์„ ๋ณด์™„ํ•ด์คŒ
    1. ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ ์–ด๋ ค์›€
    - ๋กœ๊น…, ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๊ฐ™์€ ๊ณตํ†ต ๊ธฐ๋Šฅ (ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ)์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์•ˆ์— ํฉ์–ด์ง€๊ธฐ ์‰ฝ๋‹ค.
    - ๊ธฐ๋Šฅ์„ ํด๋ž˜์Šค๋‚˜ ๋ฉ”์„œ๋“œ ๋‹จ์œ„๋กœ ๊น”๋”ํžˆ ๋ถ„๋ฆฌํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์ฝ”๋“œ ์ค‘๋ณต์ด๋‚˜ ๊ฐ€๋…์„ฑ ์ €ํ•˜๋ฅผ ์ดˆ๋ž˜ํ•œ๋‹ค.

    2. ๊ฐ์ฒด ๊ฐ„ ๊ฒฐํ•ฉ๋„ ์ฆ๊ฐ€
    - ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ๊ฐ•ํ•˜๊ฒŒ ์˜์กดํ•˜๊ฒŒ ๋˜๋ฉด (์ƒ์†•์ง์ ‘ ์ฐธ์กฐ) ๋ชจ๋“ˆ ๊ฐ„ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋†’์•„์ง„๋‹ค.

์šฉ์–ด ์ •๋ฆฌ

  • Join Point: Advice๊ฐ€ ์ ์šฉ ๊ฐ€๋Šฅํ•œ ์ง€์  (๋ฉ”์„œ๋“œ ์‹คํ–‰ ๋“ฑ)
  • Pointcut: Join Point ์ค‘ ํŠน์ • ์ง€์ ์„ ์„ ๋ณ„ํ•˜๋Š” ํ‘œํ˜„์‹
  • Advice: ์‹ค์ œ๋กœ ์‹คํ–‰๋˜๋Š” ๊ธฐ๋Šฅ (Before, After, Around ๋“ฑ)
  • Aspect: Advice์™€ Pointcut์„ ๊ฒฐํ•ฉํ•œ ๋ชจ๋“ˆ ๋‹จ์œ„

 

03. AOP์˜ ๋Œ€ํ‘œ ์‚ฌ๋ก€

@Transactional: ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ Aspect

//without AOP
public class UserService {

	private final EntityManager em;
		
	public void save() {
		EntityTransaction et = em.getTransaction()		
				
		try {
			et.begin();
            
			// ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
			et.commit();
		} catch(Exception e) {
			et.rollback();
			}
	}
}

// With AOP
public class UserService {

	@Transactional
	public void save() {
	
		// ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
				
	}
}

 

 

Self-Invocation ์ž๊ฐ€ ํ˜ธ์ถœ

public class UserService {

	public void externalMethod() {
		this.internalMethod(); // -> ๋‚ด๋ถ€ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ(์ž๊ฐ€ ํ˜ธ์ถœ)
	}
		
	@Transactional
	private void internalMethod() {
				
	}
}

 

 

Self-Invocation ์‹คํ–‰ ์ˆœ์„œ

์ ‘๊ทผ์ œ์–ด์ž์™€๋Š” ์ƒ๊ด€ ์—†์ด ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์€ Proxy๋ฅผ ํ†ตํ•˜์ง€ ์•Š์Œ์œผ๋กœ Advice๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์Œ

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  • ์ž๊ธฐ ์ž์‹ ์„ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉ
  • AopContext.currentProxy()์„ ํ†ตํ•ด ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœ
  • Spring AOP ๋Œ€์‹  AspectJ์˜ Weaving ์‚ฌ์šฉ
  • ํด๋ž˜์Šค ๋ถ„๋ฆฌ

 

04. JPA

์ง€์—ฐ ๋กœ๋”ฉ์„ ์œ„ํ•ด Entity๋ฅผ ์ตœ์ดˆ๋กœ ๋กœ๋”ฉํ•  ๋•Œ ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ์ƒ์†ํ•œ Proxy ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ ์—ฐ๊ด€๊ด€๊ณ„์— ์ถ”๊ฐ€ 

@Getter
@Entity
public class User {
	private long id;
	private String name;		
}

//ํ”„๋ก์‹œ ๊ฐ์ฒด
public class UserProxy extends User {

	private long id = 1; //์™ธ๋ž˜ํ‚ค๋กœ ์‚ฌ์šฉ๋˜์—ˆ๋˜ id์˜ ๊ฐ’์€ ์•Œ๊ณ  ์žˆ์Œ.
	private User targetEntity = null;
		
	@Override
	public String getName() {
	      
		if(targetEntity == null) {
		//1. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์‹ค์ œ Entity ์ƒ์„ฑ ์š”์ฒญ
		//2. DB์—์„œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
		//3. ์‹ค์ œ Entity ์ƒ์„ฑ ๋ฐ ํƒ€๊ฒŸ ๋“ฑ๋ก
		this.targetEntity = foundEntity;
        
	    }
	      
	     return this.targetEntity.getName();
	}
}

 

๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์‹œ์ ์— DB์— ์งˆ์˜๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ค๊ธฐ ๋•Œ๋ฌธ์—

  • ๋ถˆํ•„์š”ํ•œ ์ฟผ๋ฆฌ์˜ ๋ฐœ์ƒ์„ ๋ฐฉ์ง€
  • ๋ถˆํ•„์š”ํ•œ DB ํ†ต์‹  ๋ฏธ์‚ฌ์šฉ ๋ฐ DB ๋ถ€ํ•˜ ๊ฐ์†Œ
  • ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œํ•˜๋Š” ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„ ๋ฐฉ์ง€

Proxy๋ฅผ ํ†ตํ•œ LazyLoading์€ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ๋‚ด์—์„œ ๋™์ž‘ํ•˜๋ฏ€๋กœ LazyInitializationException์„ ์ฃผ์˜

 

 

Persistence Content Proxy VS AOP Proxy

๊ตฌ๋ถ„ ์˜์†์„ฑ (์ง€์—ฐ ๋กœ๋”ฉ) ํ”„๋ก์‹œ Spring AOP ํ”„๋ก์‹œ
๋ชฉ์  ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ๋•Œ๊นŒ์ง€ ์ง€์—ฐ ๋กœ๋”ฉ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ (ํŠธ๋žœ์žญ์…˜, ๋กœ๊น…, ๋ณด์•ˆ ๋“ฑ) ์ ์šฉ
๋Œ€์ƒ ๊ฐ์ฒด JPA ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค ์Šคํ”„๋ง ๋นˆ (Bean)
์ƒ์„ฑ ์‹œ์  EntityManager / ์„ธ์…˜์ด ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฒ˜์Œ ๋กœ๋”ฉํ•  ๋•Œ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ์‹œ, ๋นˆ ๋“ฑ๋ก ๋‹จ๊ณ„์—์„œ
ํ”„๋ก์‹œ ํƒ€์ž… ํด๋ž˜์Šค ์„œ๋ธŒํด๋ž˜์Šค (CGLIB ๊ณ„์—ด ๋ฐ”์ดํŠธ ์ฝ”๋“œ ์กฐ์ž‘) ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด JDK ๋‹ค์ด๋‚˜๋ฏน ํ”„๋ก์‹œ /
์—†์œผ๋ฉด CGLIB ํ”„๋ก์‹œ
์ƒ์„ฑ ์ฃผ์ฒด JPA ๊ตฌํ˜„์ฒด (Hibernate, EclipseLink ๋“ฑ) Spring AOP (ProxyFactoryBean ๋“ฑ)
๋™์ž‘ ๋ฐฉ์‹ ํ”„๋ก์‹œ ๋‚ด๋ถ€์— targetEntity ์ฐธ์กฐ๋ฅผ ์ง€์—ฐํ•ด์„œ ์ฑ„์šฐ๊ณ 
getter ํ˜ธ์ถœ ์‹œ์ ์— ํ•œ ๋ฒˆ๋งŒ DB ์กฐํšŒ
ํ”„๋ก์‹œ๊ฐ€ InvocatioHandler / MethodInterceptor๋ฅผ ํ†ตํ•ด ๋ฉ”์„œ๋“œ ์ง„์ž…•์ข…๋ฃŒ ์‹œ์ ์— Advice (์ „•ํ›„์ฒ˜๋ฆฌ)๋ฅผ ์ ์šฉ
๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘ ๋Ÿฐํƒ€์ž„์— ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค ์ž์ฒด๋ฅผ ์กฐ์ž‘ ๋นˆ (Bean) ๋“ฑ๋ก ์‹œ์ ์— ํ”„๋ก์‹œ ํด๋ž˜์Šค ์ƒ์„ฑ
์ข…์†์„ฑ JPA ํ‘œ์ค€ ๋ฐ ๊ตฌํ˜„์ฒด์— ์ข…์† Spring AOP ๋ชจ๋“ˆ (์Šคํ”„๋ง ์ฝ”์–ด)์— ์ข…์†