6. AOP

AOP

AOP๋Š” IoC/DI, ์„œ๋น„์Šค ์ถ”์ƒํ™”์™€ ํ•จ๊ป˜ Spring 3๋Œ€ ๊ธฐ๋ฐ˜ ๊ธฐ์ˆ ์ด๋‹ค ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ... ํŠธ๋žœ์žญ์…˜์—์„œ ์‹œ์ž‘ ํŠธ๋žœ์žญ์…˜ ์ฝ”๋“œ์™€ ๋น„์ฆˆ๋‹ˆ์Šค ์ฝ”๋“œ์˜ ๋ถ„๋ฆฌ -> ์—ฌ๊ธฐ์—์„œ ํŠธ๋žœ์žญ์…˜ ์ฝ”๋“œ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. ๋ถ„๋ฆฌ๋ฅผ ํ•˜์—ฌ ๋”ฐ๋กœ ์ž‘์„ฑํ•˜๋ฉด์„œ ์ ์ ˆํžˆ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ!

์—ฌ๊ธฐ์—์„œ ๋“ฑ์žฅํ•˜๋Š” ๊ฐœ๋…์ด AOP

@Autowired์˜ ๋ฌธ์ œ์ 

  • type ๊ธฐ๋ฐ˜์œผ๋กœ ๋นˆ์„ ์ฐพ์Œ -> ์ƒ์œ„ํƒ€์ž… Autowired์ผ ๊ฒฝ์šฐ ํ•˜์œ„ํƒ€์ž…์ด 2๊ฐœ์ด์ƒ์ด๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ.. (์• ๋งคํ•˜๋‹ค๊ณ  ์•Œ๋ ค์คŒ)

๊ณ ๋ฆฝ๋œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ์˜ ๊ฐ€์žฅ ์ข‹์€ ๋‹จ์œ„๋Š” ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ž‘๊ฒŒ ์ชผ๊ฐœ์„œ ํ…Œ์ŠคํŠธ

  • ํ…Œ์ŠคํŠธ ์‹คํŒจ์‹œ ์›์ธ ๋ถ„์„์ด ๋น ๋ฆ„

ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์˜ ์˜์กด๋Œ€์ƒ

A๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์€๋ฐ A์™€ ๊ด€๊ณ„๋ฅผ ๊ฐ–๋Š” B,C,D ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๊ทธ๋ฆฌ๊ณ  B,C,D๋Š” ๋˜ ๊ฐ๊ฐ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ฐ–๋Š” ๋‹ค๋ฅธ ํด๋ž˜์Šค๋„ ์กด์žฌ ํ•  ๊ฒƒ์ด๋‹ค. ์ฆ‰ ์—ฌ๋Ÿฌ๊ณณ์— ์˜ํ–ฅ์„ ๋ฐ›๊ฑฐ๋‚˜ ๋ฏธ์น˜๊ณ  ์žˆ๋Š”์…ˆ.. ์ด๋Ÿด ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ๋Š” A๋ฅผ ํ•˜๊ณ ์‹ถ์—ˆ๋Š”๋ฐ.. ๋‹ค๋ฅธ๊ฒŒ ๋” ์‹ ๊ฒฝ์“ฐ์ด๊ฒŒ ๋˜๋ฒ„๋ฆฌ๋Š” ํ˜„์ƒ์ด ๋‚˜์˜ค๋Š” ๊ฒƒ์ด๋‹ค.

ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ์˜ค๋ธŒ์ ํŠธ ๊ณ ๋ฆฝ

๊ทธ๋ž˜์„œ ํ…Œ์ŠคํŠธ์˜ ๋Œ€์ƒ์ด ํ™˜๊ฒฝ, ์™ธ๋ถ€์„œ๋ฒ„, ๋‹ค๋ฅธํด๋ž˜์Šค์˜ ์ฝ”๋“œ์— ์ข…์†๋˜๊ณ  ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ๊ณ ๋ฆฝ์‹œ์ผœ์•ผํ•œ๋‹ค. -> ๋ชฉ์˜ค๋ธŒ์ ํŠธ ์ž‘์„ฑ์„ ํ•˜์—ฌ ์ ์ ˆํžˆ ๊ตฌํ˜„ -> ๊ตฌํ˜„์‹œ ์‚ฌ์šฉ์•ˆํ•˜๋Š” ๋ฉ”์„œ๋“œ๋Š”

   // ์‚ฌ์šฉ์•ˆํ•˜๋Š” ๋ฉ”์„œ๋“œ :  ์˜ˆ์™ธ ์ฒ˜๋ฆฌ -> ์‚ฌ์šฉ์•ˆํ•˜๋Š” ๊ฑฐ๋ผ๊ณ  ๋ช…์‹œ
   public void add(){
     throw new UnsupportedOperationException() 
   }

๋‹จํ…Œ, ํ†ตํ…Œ

๋‹จํ…Œ์˜ ๊ฒฝ์šฐ๋ฅผ ํ•ญ์ƒ ๋จผ์ € ์ƒ๊ฐ, ์™ธ๋ถ€ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ํ†ตํ…Œ, ๋‹จํ…Œ์˜ ์–ด๋ ค์›€ (ex DAO)๋„ ์กด์žฌ. ์Šคํ”„๋ง ํ…Œ์ŠคํŠธ ์ปจํ…์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ -> ํ†ตํ•ฉํ…Œ์ŠคํŠธ

Mockito ํ”„๋ ˆ์ž„์›Œํฌ

๋ชฉ์˜ ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ๊ฐœ๋…์ด ํ”„๋ก์‹œ์˜ ์Šคํ… ๊ฐ™์€ ๋Š๋‚Œ ๋ชฉ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ผ์ผ์ด ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋Œ€์‹ ํ•ด์ฃผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ, ์ฆ‰ ๊ธฐ์กด์ฒ˜๋Ÿผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Œ!! ๊ฐœ์‹ ๋ฐ•ํ•จ!!!

  • Java ํด๋ž˜์Šค ์ž„ํฌํŠธ

    // mock ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ์„ ์œ„ํ•œ ํด๋ž˜์Šค ์ž„ํฌํŠธ
    import static org.mockito.Mockito.*;
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ maven ์ถ”๊ฐ€

    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.10.19</version>
      <scope>test</scope>
    </dependency>

๋‹ค์ด๋‚ด๋ฏน ํ”„๋ก์‹œ์™€ ํŒฉํ† ๋ฆฌ๋นˆ

  • ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ• mock, when, thenReturn, verify, times, any ๋ฉ”์„œ๋“œ

    @Test
    public void mockitoTest() {
    
      // mock ์ƒ์„ฑ
      UserDao mockUserDao = mock(UserDao.class);
    
      // ์Šคํ…๊ธฐ๋Šฅ ์ถ”๊ฐ€ : getAll ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋์„๋•Œ, users ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š” ๋ผ๋Š” ์˜๋ฏธ
      when(mockUserDao.getAll()).thenReturn(this.users);
    
      // ํ•ด๋‹น๋ฉ”์„œ๋“œ(update)์˜ ์‹คํ–‰์—ฌ๋ถ€ ๊ฒ€์ฆ : update ๋ฉ”์„œ๋“œ๊ฐ€ 2๋ฒˆ ์‹คํ–‰๋๋Š”์ง€ ํ™•์ธ(verify)ํ•˜๋ผ
      verify(mockUserDao, times(2)).update(any(User.class));
    }
  • ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด.. ๋””ํŒจ์—์„œ ๋ฐฐ์› ๋˜ ๋‚ด์šฉ ์š”์•ฝ.. ๋™์ ์œผ๋กœ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„๋œ ํŒจํ„ด

  • ํ”„๋ก์‹œ ํ”„๋ก์‹œ, ๋Œ€๋ฆฌ์ธ ์—ญํ™œ, ์ ‘๊ทผ์ œ์–ด, ์Šคํ…๊ณผ ๋ชฉ์˜ ๊ธฐ๋ฐ˜์ด๋˜๋Š” ๊ฐœ๋… RMI ๋“ฑ ์›๊ฒฉ ํ”„๋ก์‹œ ํƒ€๊ฒŸ ์ธํ„ฐํŽ˜์ด์Šค์— ์œ„์ž„, ์‹ค์ œ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‹ค์ œ object๋ฅผ ํ˜ธ์ถœ

  • ๋ฆฌํ”Œ๋ ‰์…˜ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป๊ฑฐ๋‚˜, ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋“ฑ ๋™์ ์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ X.class ๋‚˜ x.getClass() ๋ฅผ ํ™œ์šฉํ•˜์—ฌ Class ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Œ

    @Test
    public void reflectStringTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
      String name = "Spring";
    
      // length
      assertThat(name.length(), CoreMatchers.is(6));
      Method method = String.class.getMethod("length");
      assertThat(method.invoke(name), CoreMatchers.is(6));
    
      // charAt
      assertThat(name.charAt(0), CoreMatchers.is('S'));
      Method method2 = String.class.getMethod("charAt", int.class);
      assertThat(method2.invoke(name, 0), CoreMatchers.is('S'));
    }
  • ๋‹ค์ด๋‚˜๋ฏน proxy ํด๋ž˜์Šค

    ```java

// Hello ์ธํ„ฐํŽ˜์ด์Šค public interface Hello { String sayHello(String name);

String sayHi(String name);

String sayThankYou(String name); }

// ํƒ€๊ฒŸ ์˜ค๋ธŒ์ ํŠธ public class HelloTarget implements Hello { @Override public String sayHello(String name) { return "Hello " + name; }

@Override public String sayHi(String name) { return "Hi " + name; }

@Override public String sayThankYou(String name) { return "Thank You " + name; } }

// ๋‹ค์ด๋‚˜๋ฏน Proxy์—์„œ ์‚ฌ์šฉํ•  ๋ถ€๊ฐ€๊ธฐ๋Šฅ : InvocationHandler๋ฅผ ๊ผญ ๊ตฌํ˜„ํ•ด์•ผํ•จ public class UppercaseHandler implements InvocationHandler { Hello target; // ํƒ€๊ฒŸ ์ธํ„ฐํŽ˜์ด์Šค

public UppercaseHandler(Hello target) { this.target = target; }

@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String ret = (String) method.invoke(target, args); return ret.toUpperCase(); } }

### `์žฅ์ `  
HelloUppercase ๊ฐ™์€๊ฒฝ์šฐ ๋ฉ”์„œ๋“œ๊ฐ€ 3๊ฐœ์— ๋ถˆ๊ณผํ•˜์ง€๋งŒ ์ด๊ฒƒ์ด 30๊ฐœ๋ผ๊ณ  ํ•œ๋‹ค๋ฉด...? ํ™•์žฅ์— ๋Œ€ํ•œ ์œ ์—ฐ์„ฑ์ด ์ •์ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ ๊ฒƒ๊ณผ ๋‹ค์ด๋‚˜๋ฏน Proxy๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋งŒ๋“ ๊ฒƒ์€ ์—„์ฒญ๋‚œ ์ฐจ์ด๊ฐ€ ๋‚œ๋‹ค.. 

ํ˜„์žฌ ์ƒํƒœ์—์„œ `Hello ์ธํ„ฐํŽ˜์ด์Šค`์˜ ๋ฉ”์„œ๋“œ๋ฅผ 30๊ฐœ๋กœ ๋Š˜๋ฆฐ๋‹ค ์น˜๋ฉด,  
1. Hello ์ธํ„ฐํŽ˜์ด์Šค 30๊ฐœ ์ถ”๊ฐ€
2. Hello ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌํ˜„์ฒด(ex HelloUppsercase)๋„ ์ธํ„ฐํŽ˜์ด์Šค์— ๋งž๊ฒŒ 30๊ฐœ ๊ตฌํ˜„ -> **์—ฌ๊ธฐ๊ฐ€ ๋ฌธ์ œ์ **
3. ๊ตฌํ˜„์ฒด๊ฐ€ 2๊ฐœ,3๊ฐœ ... ๋งŽ์œผ๋ฉด ๋งŽ์„์ˆ˜๋ก ์ˆ˜์ •์‚ฌํ•ญ์ด ๋งŽ์ด ๋ฐœ์ƒ

**`๋‹ค์ด๋‚˜๋ฏน Proxy๋ฅผ ์ด์šฉํ•œ๋‹ค๋ฉด..`**  
1. Hello ์ธํ„ฐํŽ˜์ด์Šค 30๊ฐœ ์ถ”๊ฐ€ ๋

### ๋นˆ์ƒ์„ฑ ๋ฐฉ๋ฒ•
๋””ํดํŠธ ์ƒ์„ฑ์ž ์™ธ `ํŒฉํ† ๋ฆฌ๋นˆ`์œผ๋กœ ๋นˆ์„ ์ƒ์„ฑ.  

**`ํŒฉํ† ๋ฆฌ๋นˆ`**์ด๋ž€ ์Šคํ”„๋ง์„ ๋Œ€์‹ ํ•ด์„œ ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ง„ ํŠน๋ณ„ํ•œ ๋นˆ.  

- FactoryBean ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„


`private ์ƒ์„ฑ์ž` -> ๊ฐ์ฒด ์ƒ์„ฑ์€ static ๋ฉ”์„œ๋“œ๋กœ ๊ตฌํ˜„, ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์ง€ ๋ง๊ฒƒ, ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ด์šฉํ•ด์„œ ์ƒ์„ฑ์€๊ฐ€๋Šฅํ•˜๋‹ค  
getBean("&์ด๋ฆ„") -> factoryBean์„ ๋“ค๊ณ ์˜ด

- ํŠธ๋žœ์žญ์…˜ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋นˆ -> ์œ ์—ฐํ•˜๊ฒŒ ํŠธ๋ž™์žฐ์…˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋„๋กํ•ด์คŒ
  `Class<?>์˜ serviceInterface`๊ฐ€ ํƒ€์ž…์œผ๋กœ ์„ค์ • ๋จ  
  Obejct์˜ target์€ ๊ทธ ํƒ€๊ฒŸ์ด ๋˜๋Š” ๋Œ€์ƒ์ด ๋ฌด๊ถ๋ฌด์ง„  
```java
public class TxProxyFactoryBean implements FactoryBean {
  Object target;
  PlatformTransactionManager transactionManager;
  String pattern;
  Class<?> serviceInterface;

  public void setTarget(Object target) {
    this.target = target;
  }

  public void setTransactionManager(PlatformTransactionManager transactionManager) {
    this.transactionManager = transactionManager;
  }

  public void setPattern(String pattern) {
    this.pattern = pattern;
  }

  public void setServiceInterface(Class<?> serviceInterface) {
    this.serviceInterface = serviceInterface;
  }

  @Override
  public Object getObject() throws Exception {
    TransactionHandler handler = new TransactionHandler();
    handler.setTarget(target);
    handler.setTransactionManager(transactionManager);
    handler.setPattern(pattern);

    return Proxy.newProxyInstance(
        getClass().getClassLoader(),
        new Class[]{serviceInterface},
        handler
    );
  }

  @Override
  public Class<?> getObjectType() {
    return serviceInterface;
  }

  @Override
  public boolean isSingleton() {
    return false;
  }
}

๋‹ค์ด๋‚˜๋ฏน Proxy์˜ ๋‹จ์ ์€... ํƒ€๊นƒ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด ๊ทธ๋งŒํผ Proxy๋ฅผ ๋งŒ๋“ค์–ด์ค˜์•ผํ•˜๋Š”... ์ƒํ™ฉ์ด ๋ฐœ์ƒ... -> ๊ทธ๋ ‡๊ฒŒ๋˜๋‹ค๋ณด๋ฉด ์„ค์ • ๋ถ€๋ถ„๋„ ์ค‘๋ณต... -> ํ•ด๊ฒฐ์ฑ…์€ ? ํŒฉํ† ๋ฆฌ๋นˆ -> ํŒฉํ† ๋ฆฌ๋นˆ -> ์Šคํ”„๋งํŒฉํ† ๋ฆฌ๋นˆ

์Šคํ”„๋ง์˜ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ ๋นˆ

ํ”„๋ก์‹œ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ธฐ์ˆ ์„ ์ถ”์ƒํ™”ํ•œ ํŒฉํ† ๋ฆฌ ๋นˆ

ProxyFactoryBean

  • ์ˆœ์ˆ˜ํ•˜๊ฒŒ Proxy ์ƒ์„ฑ๋งŒ ๋‹ด๋‹น. ๊ธฐ์กด์— ํŠธ๋žœ์žญ์…˜ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์ด ๋“ค์–ด๊ฐ„ ๋งŒ๋“  TxProxyFactoryBeanํ•˜๊ณ ๋Š” ๊ธฐ๋Šฅ๋งŒ ๋‹ค๋ฆ„

  • ์ฆ‰ ์ˆœ์ˆœ Proxy ์ƒ์„ฑ๋งŒ ๋‹ด๋‹น / ๋ถ€๊ฐ€๊ธฐ๋Šฅ์€ ๋”ฐ๋กœ ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉ

  • ๊ธฐ๋Šฅ๊ณผ ์—ญํ™œ์˜ ๋ถ„๋ฆฌ.... ๋ฏธ์นœ๋“ฏํ•œ ์„ค๊ณ„.. ๊ฐํƒ„

org.aopalliance.intercept.MethodInterceptor extends Advice

  • ๋ถ€๊ฐ€๊ธฐ๋Šฅ์€ MethodInterceptor ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์„ ํ†ตํ•ด ๋งŒ๋“ฌ

  • InvocationHandler ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋‹ค๋ฅด๋‹ค -> ์ด๋…€์„์˜ invoke ๋ฉ”์„œ๋“œ์—์„œ๋Š” ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ์˜ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Œ

  • MethodInterceptor์˜ invoke ๋ฉ”์„œ๋“œ -> ProxyFactoryBean์œผ๋กœ ๋ถ€ํ„ฐ ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ œ๊ณต ๋ฐ›์Œ. ๋”ฐ๋ผ์„œ ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ์— ๊ตฌ์•  ๋ฐ›์ง€ ์•Š๊ณ  ๋…๋ฆญ์ ‘์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ

  • ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ํ”„๋ก์‹œ์— ํ•จ๊ป˜ ์‚ฌ์šฉ, ์‹ฑ๊ธ€ํ†ค ๋นˆ ๋“ฑ๋ก ๊ฐ€๋Šฅ

  • invoke ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ -> methodInvocation.proceed()๋Š” Method์™€ ๋‹ฌ๋ฆฌ ํƒ€๊นƒ ์ •๋ณด๋ฅผ ํ•จ๊ผ ์ „๋‹ฌํ•œ๋‹ค

  • Advice ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค

์–ด๋“œ๋ฐ”์ด์Šค ! (ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ํ•„์š”์—†๋Š” ์ˆœ์ˆ˜ํ•œ ๋ถ€๊ฐ€๊ธฐ๋Šฅ)

  • MethodInvocation ๊ฐ™์€ ๊ฒฝ์šฐ ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ์™€ ํ•จ๊ป˜ ์ „๋‹ฌํ•˜์—ฌ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉฐ, ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๊ตฌํ˜„์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ ๊ธฐ ๊ตฌํ˜„ํ–ˆ๋˜ InvocationHandler์™€์˜ ์ฐจ์ด์ ์ด๋‹ค.

  • MethodInvocation์€ ์ผ์ข…์˜ ์ฝœ๋ฐฑ ์˜ค๋ธŒ์ ํŠธ, procced ๋ฉ”์„œ๋“œ -> ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ์‹คํ–‰

  • ProxyFactoryBean.addAdvice() -> ์—ฌ๋Ÿฌ ๊ฐœ์˜ MethodInvocation์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ 

    -> ์ฆ‰, ProxyFactoryBran์— ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋„ฃ์„ ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธ

  • ํƒ€๊นƒ์— ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์„ ์Šคํ”„๋ง์—์„œ๋Š” ์–ด๋“œ๋ฐ”์ด์Šค๋ผ๊ณ  ํ•œ๋‹ค

  • ์ˆœ์ˆ˜ํ•œ ๊ธฐ๋Šฅ์„ ๋‹ด์€ ์˜ค๋ธŒ์ ํŠธ๋ผ ํ•  ์ˆ˜ ์žˆ์Œ

ํฌ์ธํŠธ ์ปท ! ๋ถ€๊ฐ€๊ธฐ๋Šฅ ์ ์šฉ๋Œ€์ƒ์˜ ๋ฉ”์†Œ๋“œ ์„ ์ •

๋ฉ”์†Œ๋“œ ์„ ์ • ์•Œ๊ณ ๋ฆฌ์ฆ˜ ProxyFactoryBean -> Advice(๋ถ€๊ฐ€๊ธฐ๋Šฅ) + PointCut(๋Œ€์ƒ๋ฉ”์„œ๋“œ) ๊ด€๋ฆฌ ๋ฐ ์ ์šฉ

  • NameMatchMethodPointcut (์Šคํ”„๋ง ์ œ๊ณต)

์–ด๋“œ๋ฐ”์ด์ € = advice + pointcut

DefaultPointcutAdvisor (์Šคํ”„๋ง ์ œ๊ณต)

  • ์–ด๋“œ๋ฐ”์ด์Šค ๋”ฐ๋กœ, ํฌ์ธํŠธ์ปท ๋”ฐ๋กœ ๋“ฑ๋ก์„ ์•ˆํ•˜๋Š” ์ด์œ ๋Š” ์–ด๋–ค ์–ด๋“œ๋ฐ”์ด์Šค์— ์–ด๋–ค ํฌ์ธํŠธ์ปท์ด ์ ์šฉ๋ ์ง€ ์• ๋งคํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ๋”ฐ๋ผ์„œ ์–ด๋“œ๋ฐ”์ด์ €๋กœ ๋“ฑ๋ก์„ ํ•ด์•ผํ•œ๋‹ค.

xml ์„ค์ •

    <!-- Advice ์„ค์ • -->
    <bean id="transactionAdvice" class="chap06_AOP.TransactionAdvice">
        <property name="transactionManager" ref="transactionManger"/>
    </bean>

    <!-- PointCut ์„ค์ • -->
    <bean id="transactionPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedName" value="upgrade*"/>
    </bean>

    <!-- Advisor ์„ค์ •-->
    <bean id="transactionAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice" ref="transactionAdvice"/>
        <property name="pointcut" ref="transactionPointcut"/>
    </bean>

    <!-- ProxyFactoryBean ์„ค์ • -->
    <bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="userServiceImpl"/>
        <property name="interceptorNames">
            <list>
                <value>transactionAdvisor</value>
            </list>
        </property>
    </bean>

interceptorNames ์†์„ฑ -> ์–ด๋“œ๋ฐ”์ด์Šค์™€ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ํ˜ผํ•ฉํ•ด์„œ ์„ค์ • ๊ฐ€๋Šฅํ•˜๋‹ค

์Šคํ”„๋ง AOP

ํˆฌ๋ช…์„ฑ : ๋ถ„๋ฆฌ๋ฅผ ํ†ตํ•ด ํˆฌ๋ช…ํ•œ ๋ถ€๊ฐ€๊ธฐ๋Šฅ ํ˜•ํƒœ๋กœ ์ œ๊ณต ๋˜์–ด์•ผํ•จ. ํˆฌ๋ช…ํ•˜๋‹ค๋Š” ๊ฒƒ์€ ๋งˆ์น˜ ํˆฌ๋ช…ํ•œ ์œ ๋ฆฌ๋ฅผ ์‚ฌ์ด์— ๋‘”๊ฒƒ ๊ฐ™๋‹ค๋Š” ๊ฒƒ. OCP๊ฐœ๋…์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ๋„ ์žˆ๋‹ค. ์ถ”๊ฐ€, ์ œ๊ฑฐ ๋ฐ ํ™•์žฅ์—๋Š” ํ•ญ์ƒ ์—ด๋ ค ์žˆ์–ด์•ผ ํ•˜๋‹ค๋Š” ๊ฒƒ. DI์˜ ๋ฉ‹์ง„ ์‘์šฉ๋ฐฉ์‹

๋นˆํ›„์ฒ˜๋ฆฌ๊ธฐ

๋ง ๊ทธ๋Œ€๋กœ ์Šคํ”„๋ง Bean ์ƒ์„ฑ ํ›„ ํ›„๊ฐ€๊ณต์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ดํ”„ ์‚ฌ์ดํด.

  • BeanPostProcessor ์ธํ„ฐํŽ˜์ด์Šค

ํฌ์ธํŠธ์ปท์˜ 2๊ฐ€์ง€ ๊ธฐ๋Šฅ

  1. ๋ฉ”์†Œ๋“œ ์„ ์ • -> MethodMatcher

  2. ์˜ค๋ธŒ์ ํŠธ ์„ ํƒ -> ClassFilter

DefaultAdvisorAutoProxyCreator

ํ”„๋ก์‹œ ์ ์šฉ ๋Œ€์ƒ์ด๋ฉด, ํ”„๋ก์‹œ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑ -> ํƒ€๊ฒŸ์˜ค๋ธŒ์ ํŠธ์— ์—ฐ๊ฒฐ -> ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ ์ž๋™ํ”„๋ก์‹œ ์ƒ์„ฑ์š” ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ

ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹์„ ์ด์šฉํ•œ ํฌ์ธํŠธ์ปท

  • AspectJExpressionPointcut ํด๋ž˜์Šค ์‚ฌ์šฉ

  • AspectJ๋ผ๋Š” ์™ธ๋ถ€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ํ™•์žฅํ•˜์—ฌ ์Šคํ”„๋ง์—์„œ ์žฌ ๊ฐ€๊ณต์ฒ˜๋ฆฌ

  • AspectJ์˜ execution ์ง€์‹œ์ž๋ฅผ ํ†ตํ•ด ์„ค์ •

execution([์ ‘๊ทผ์ œํ•œ์ž ํŒจํ„ด] ํƒ€์ž…ํŒจํ„ด [ํƒ€์ž…ํŒจํ„ด.] ์ด๋ฆ„ํŒจํ„ด (ํƒ€์ž…ํŒจํ„ด|"..", ...))([throws ์˜ˆ์™ธํŒจํ„ด])

  • ์™€์ผ๋“œ์นด๋“œ : ๊ทธ์™ธ - *, ํŒŒ๋ผํ‹ฐ๋จธ - ..

  • ๋ชจ๋“ ํŒจํ‚ค์ง€, ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ์ด๋ฆ„, ์˜ˆ์™ธ์ด๋ฆ„, ๋ฆฌํ„ดํƒ€์ž…์— ์™€์ผ๋“œ์นด๋“œ ์ ์šฉ๊ฐ€๋Šฅ

  • ํด๋ž˜์Šค : .. -> ์„œ๋ธŒํŒจํ‚ค์ง€ / com..Target.* -> com์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŒจํ‚ค์ง€์—์„œ Targetํด๋ž˜์Šค์˜ ๋ชจ๋“ ๋ฉ”์„œ๋“œ

  • ํ•„์ˆ˜ : ๋ฆฌํ„ดํƒ€์ž…, ๋ฉ”์„œ๋“œ, ํŒŒ๋ผ๋ฏธํ„ฐ / ๋‚˜๋จธ์ง€ ์ƒ๋žต๊ฐ€๋Šฅ

  • ํฌ์ธํŠธ์ปท ํ‘œ์…˜์‹ -> ์ธํ„ฐํŽ˜์ด์Šค, ์ถ”์ƒํด๋ž˜์Šค๋„ ํฌ์ธํŠธ์ปท ์„ ์ • ๊ฐ€๋Šฅ

  • AspectJExpressionPointcut ์‚ฌ์šฉ์‹œ ์•„๋ž˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ (Maven)

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjtools</artifactId>
      <version>1.9.4</version>
    </dependency>
  • Java -> setExpression์œผ๋กœ execution ์„ค์ • -> ํฌ์ธํŠธ์ปท ํด๋ž˜์Šคํ•„ํ„ฐ, ๋ฉ”์†Œ๋“œ๋งค์ฒ˜ ๋น„๊ต

      AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
      pointcut.setExpression("execution(public int chap06_AOP.Target.minus(int,int) throws java.lang.RuntimeException)");
  • Test

    ```java @Test public void pointcut() throws Exception { targetClassPointcutMatches("execution( (..))", true, true, true, true, true, true); targetClassPointcutMatches("execution( hello(..))", true, true, false, false, false, false); targetClassPointcutMatches("execution( hello())", true, false, false, false, false, false); targetClassPointcutMatches("execution( hello(String))", false, true, false, false, false, false); targetClassPointcutMatches("execution( meth(..))", false, false, false, false, true, true); targetClassPointcutMatches("execution( (int,int))", false, false, true, true, false, false); targetClassPointcutMatches("execution( ())", true, false, false, false, true, true); targetClassPointcutMatches("execution( .Target.(..))", true, true, true, true, true, false); targetClassPointcutMatches("execution( chap06_AOP.Target.(..))", true, true, true, true, true, false); targetClassPointcutMatches("execution( chap06_AOP...(..))", true, true, true, true, true, true); targetClassPointcutMatches("execution( ..Target.(..))", true, true, true, true, true, false); targetClassPointcutMatches("execution( ..Tar.(..))", true, true, true, true, true, false); targetClassPointcutMatches("execution( ..get.(..))", true, true, true, true, true, false); targetClassPointcutMatches("execution( ..B.(..))", false, false, false, false, false, true); targetClassPointcutMatches("execution( ..TargetInterface.(..))", true, true, true, true, false, false); targetClassPointcutMatches("execution( (..) throws Runtime)", false, false, false, true, false, true); targetClassPointcutMatches("execution(int (..))", false, false, true, true, false, false); targetClassPointcutMatches("execution(void (..))", true, true, false, false, true, true); }

private void targetClassPointcutMatches(String expression, boolean... expected) throws Exception{ pointcutMatches(expression, expected[0], Target.class, "hello"); pointcutMatches(expression, expected[1], Target.class, "hello", String.class); pointcutMatches(expression, expected[2], Target.class, "plus", int.class, int.class); pointcutMatches(expression, expected[3], Target.class, "minus", int.class, int.class); pointcutMatches(expression, expected[4], Target.class, "method"); pointcutMatches(expression, expected[5], Bean.class, "method");

}

private void pointcutMatches(String expression, Boolean expected, Class<?> clazz, String methodName, Class<?>... args) throws Exception { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression);

// ํฌ์ธํŠธ์ปท ํด๋ž˜์Šคํ•„ํ„ฐ, ๋ฉ”์„œ๋“œ๋งค์ฒ˜ ํ™•์ธ
assertThat(pointcut.getClassFilter().matches(clazz)
        && pointcut.getMethodMatcher().matches(clazz.getMethod(methodName, args), null)
    , is(expected));

}

### Aspect
- **ํ”„๋ก์‹œ๊ฐ€ ์•„๋‹Œ ๋กœ๋” ๋œ ํด๋ž˜์Šค์— ์ ‘๊ทผ**
- ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด์„œ ์ ‘๊ทผํ•˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ **์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ์ œ์–ด**
- `๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘`๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉ -> **์ž๋™ํ”„๋ก์‹œ ์ƒ์„ฑ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ AOP ์ ์šฉ์ด ๊ฐ€๋Šฅ**. `์•„๋ฌด๋ฐ์„œ๋‚˜ ๊ฐ€๋Šฅ`
- ๋ฉ”์„œ๋“œ๋ฟ ์•„๋‹ˆ๋ผ ์˜ค๋ธŒ์ ํŠธ์˜ ์ƒ์„ฑ, ํ•„๋“œ๊ฐ’์˜ ์กฐํšŒ ์กฐ์ž‘, ์Šคํƒœํ‹ฑ ์ดˆ๊ธฐํ™” ๋“ฑ `๋‹ค์–‘ํ•œ ์ž‘์—…์— ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๋ถ€์—ฌ ๊ฐ€๋Šฅ`
- ์ผ๋ฐ˜์ ์œผ๋กœ `์Šคํ”„๋งAOP`๋ฉด ์ถฉ๋ถ„(ํ”„๋ก์‹œ ๋ฐฉ์‹์˜), **ํŠน๋ณ„ํ•œ AOP ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ** `AspectJ` ์‚ฌ์šฉ

### ์šฉ์–ด๋“ค
- ํƒ€๊นƒ
- ์–ด๋“œ๋ฐ”์ด์Šค
- ์กฐ์ธํฌ์ธํŠธ
- ํฌ์ธํŠธ์ปท
- ํ”„๋ก์‹œ
- ์–ด๋“œ๋ฐ”์ด์ €
- ์• ์ŠคํŽ™ํŠธ

### AOP ๋„ค์ž„์ŠคํŽ˜์ด์Šค
- ์ž๋™ํ”„๋ก์‹œ์ƒ์„ฑ๊ธฐ : DefaultAdvisorAutoProxyCreator (์Šคํ”„๋ง)
- **์–ด๋“œ๋ฐ”์ด์Šค : TransactionAdvice (์ง์ ‘๊ตฌํ˜„)**
- ํฌ์ธํŠธ์ปท : AspectJExpressionPointcut (์Šคํ”„๋ง)
- ์–ด๋“œ๋ฐ”์ด์ € : DefaultPointcutAdviosr (์Šคํ”„๋ง)
**์–ด๋“œ๋ฐ”์ด์Šค ๋นผ๊ณ  3๊ฐœ๋Š” ์Šคํ”„๋ง ๋””ํดํŠธํด๋ž˜์Šค ์‚ฌ์šฉ**

- xml ์„ค์ •์œผ๋กœ -> `aop ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์‚ฌ์šฉ`
  **์ง์ ‘ ๊ตฌํ˜„ํ•œ ์–ด๋“œ๋ฐ”์ด์Šค ์™ธ์— ๋‚˜๋จธ์ง€๋Š” ์ „์šฉํƒœ๊ทธ ์‚ฌ์šฉ์„ ๊ถŒ์žฅ**
  ```xml
    <aop:config>
        <aop:pointcut id="transactionPointcut" expression="execution(* *..*ServiceImpl.upgrade*(..)"/>
        <aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut"/>
    </aop:config>

6.6 ํŠธ๋žœ์žญ์…˜ ์†์„ฑ

  • ํŠธ๋ž™์žฐ์…˜ ๋งค๋‹ˆ์ € : PlatformTransactionManager

  • ํŠธ๋žœ์žญ์…˜ ์ •์˜ : DefaultTransactionDefinition

ํŠธ๋žœ์žญ์…˜ ์ •์˜

์ตœ์†Œ์˜ ์ž‘์—…๋‹จ์œ„. TransactionDefinition ์ธํ„ฐํŽ˜์ด์Šค 4๊ฐ€์ง€ ์†์„ฑ ์ •์˜

  • ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ ์ด๋ฏธ ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์žˆ์„ ๋•Œ or ์—†์„ ๋•Œ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•  ๊ฒƒ์ธ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐฉ์‹ AํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ์ค‘ Bํ˜ธ์ถœ -> B๋Š” A์˜ ํŠธ๋žœ์žญ์…˜ ์•ˆ์— ์žˆ๋‹ค. ์ด๋Ÿด ๊ฒฝ์šฐ ์ทจ์†Œ๋˜๋ฉด ๋‘˜๋‹ค ๋กค๋ฐฑ B๊ฐ€ ๋…๋ฆฝ์ ์ธ ํŠธ๋žœ์žญ์…˜์„ ๊ฐ–๊ณ  ์žˆ๊ณ , B๋Š” ๋๋‚œ์ƒํƒœ์—์„œ A๊ฐ€ ์˜ˆ์™ธ๋กœ ์ทจ์†Œ๋˜๋ฉด A๋งŒ ๋กค๋ฐฑ

    • PROPAGATION_REQUIRED ์†์„ฑ (๊ฐ€์žฅ๋งŽ์ด ์‚ฌ์šฉ) : ์žˆ์œผ๋ฉด ๊ทธ๊ฑฐ์“ฐ๊ณ , ์—†์œผ๋ฉด ์ƒˆ๋กœ๋งŒ๋“ฌ -> ์žฌ์‚ฌ์šฉ

    • PROPAGATION_REQUIRED_NEW : ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜ ์ƒ์„ฑ

    • PROPAGATION_NOT_SUPPORTED : ์ œ์™ธํ•˜๊ณ ์ž ํ•  ๋•Œ ๋งŽ์ด ์“ฐ์ž„

  • ๊ฒฉ๋ฆฌ์ˆ˜์ค€ ์„œ๋ฒ„์—์„œ๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์„ ์ œ์–ดํ•ด์ค˜์•ผํ•จ ISOLATION_DEFAULT, Datasoruce์˜ ๋””ํดํŠธ๋ฅผ ๋”ฐ๋ฅด๋Š” ํŽธ์ด ์ข‹์ง€๋งŒ, ๋•Œ์— ๋”ฐ๋ผ์„œ๋Š” ๋…์ž์ ์ธ ๊ฒฉ๋ฆฌ์ˆ˜์ค€ ํ•„์š”

  • ์ œํ•œ์‹œ๊ฐ„ ํŠธ๋žœ์žญ์…˜์˜ ์ˆ˜ํ–‰ ์ œํ•œ์‹œ๊ฐ„ ์„ค์ • DefaultTransactionDefinition ์˜ ๊ธฐ๋ณธ๊ฐ’์€ ์ œํ•œ์‹œ๊ฐ„ ์—†์Œ PROPAGATION_REQUIRED or PROPAGATION_REQUIRES_NEW ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ์˜๋ฏธ ์žˆ์Œ

  • ์ฝ๊ธฐ ์ „์šฉ ๋ฐ์ดํ„ฐ์˜ ์กฐ์ž‘์„ ๋ง‰์Œ. ์กฐํšŒ๊ธฐ๋Šฅ์— readonly ๋กœ ์„ค์ • ํ•˜๋ฉด ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ ์ˆ˜ ์žˆ์Œ

ํŠธ๋žœ์žญ์…˜ ์ธํ„ฐ์…‰ํ„ฐ์™€ ํŠธ๋žœ์žญ์…˜ ์†์„ฑ

๋ฉ”์†Œ๋“œ๋ณ„๋กœ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜ ์ •์˜ -> ์–ด๋“œ๋ฐ”์ด์Šค ๊ธฐ๋Šฅ ํ™•์žฅ

  • TransactionInterceptor ๋ฉ”์†Œ๋“œ ์ด๋ฆ„ ํŒจํ„ด์„ ์ด์šฉํ•˜์—ฌ ๋‹ค๋ฅด๊ฒŒ ์ง€์ • ํ•  ์ˆ˜ ์žˆ์Œ ๋Ÿฐํƒ€์ž„ ์˜ˆ์™ธ ๋ฐœ์ƒ -> ๋กค๋ฐฑ ๊ฒ€์‚ฌ์˜ˆ์™ธ ๋ฐœ์ƒ -> ์ปค๋ฐ‹ 1. PlatformTransactionManager 2. Properties

    • TransactionAttribute ์ •์˜ (ํŠธ๋žœ์žญ์…˜ ์†์„ฑ 4๊ฐœ ์ด์šฉ)

    • rollbackOn ๋ฉ”์„œ๋“œ : ์–ด๋–ค ์˜ˆ์™ธ ๋ฐœ์ƒ์‹œ ๋กค๋ฐฑํ•  ๊ฒƒ์ธ๊ฐ€๋ฅผ ๊ฒฐ์ •. ๋Ÿฐํƒ€์ž„-> ์ปค๋ฐ‹ ๋“ฑ ๋ณ€๊ฒฝํ•„์š”์‹œ ์ •์˜

      <bean id="transactionAdvice" class="org.springframework.transaction.interceptor.TransactionInterceptor">
          <property name="transactionManager" ref="transactionManger"/>
          <property name="transactionAttributes">
              <props>
                  <prop key="get*">PROPAGATION_REQUIRED,readOnly,timeout_30</prop>
                  <prop key="upgrade*">PROPAGATION_REQUIRES_NEW,ISOLATION_SERIALIZABLE</prop>
              </props>
          </property>
      </bean>
  • tx๋„ค์ž„์ŠคํŽ˜์ด์Šค ์‚ฌ์šฉ tx์Šคํ‚ค๋งˆ ์ „์šฉ ํƒœ๊ทธ -> ์œ„์˜ ํŠธ๋žœ์žญ์…˜ ์†์„ฑ ๋ช…์‹œ ์ž๋™์™„์„ฑ. ์˜คํƒ€์œจ ์ค„์ž„

      <tx:advice id="transactionAdvice" transaction-manager="transactionManger">
          <tx:attributes>
              <tx:method name="get*" propagation="REQUIRED" read-only="true" timeout="30"/>
              <tx:method name="upgrade*" propagation="REQUIRES_NEW" isolation="SERIALIZABLE"/>
              <tx:method name="*" propagation="REQUIRED"/>
          </tx:attributes>
      </tx:advice>

ํฌ์ธํŠธ์ปท๊ณผ ํŠธ๋žœ์žญ์…˜ ์†์„ฑ์˜ ์ ์šฉ ์ „๋žต

aop, tx ์Šค์นด๋งˆ์˜ ์ „์šฉํƒœ๊ทธ ์‚ฌ์šฉ, ํฌ์ธํŠธ์ปท์˜ execution ํ™œ์šฉ

  • ํŠธ๋žœ์žญ์…˜ ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹ -> ํƒ€์ž…ํŒจํ„ด or ๋นˆ์ด๋ฆ„์ด์šฉ -> execution(ํƒ€์ž…ํŒจํ„ด), bean(๋นˆ์ด๋ฆ„)

    ๊ฐ€๊ธ‰์  ํƒ€์ž…ํŒจํ„ด์€ ์ธํ„ฐํŽ˜์ด์Šคํƒ€์ž… ์‚ฌ์šฉ ๊ถŒ์žฅ

  • ๊ณตํ†ต๋œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„๊ทœ์น™ -> ์ตœ์†Œํ•œ์˜ ํŠธ๋žœ์žญ์…˜์–ด๋“œ๋ฐ”์ด์Šค์™€ ์†์„ฑ ์ •์˜ ํ•˜๋„๋ก... ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ ๋•Œ -> ์–ด๋“œ๋ฐ”์ด์Šค์™€ ํฌ์ธํŠธ์ปท ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€

      <tx:advice id="defaultAdvice">
          <tx:attributes>
              <tx:method name="get*" read-only="true"/> <!--์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๊ฒŒ, ์ค‘์š”!-->
              <tx:method name="*"/>                     <!--๋ชจ๋“ ๋ฉ”์„œ๋“œ์— ๊ธฐ๋ณธํŠธ๋žœ์žญ์…˜์†์„ฑ ์ ์šฉ-->
          </tx:attributes>
      </tx:advice>
    • tx:advice์™€ aop ์ด์šฉํ•œ ๋ฐฉ์‹

      <tx:advice id="defaultAdvice">
          <tx:attributes>
              <tx:method name="get*" read-only="true"/>
              <tx:method name="*"/>
          </tx:attributes>
      </tx:advice>
      
      <tx:advice id="batchAdvice">
          <tx:attributes>
              <tx:method name="addBatch*"/>
          </tx:attributes>
      </tx:advice>
      
      <aop:config>
          <aop:advisor advice-ref="defaultAdvice" pointcut="bean(*Service)"/>
          <aop:advisor advice-ref="defaultAdvice" pointcut="bean(*Bean)"/>
          <aop:advisor advice-ref="batchAdvice" pointcut="execution(* *..*Batch(..))"/>
      </aop:config>
  • ํ”„๋ก์‹œ ๋ฐฉ์‹ AOP๋Š” ๊ฐ™์€ ํƒ€๊นƒ์˜ค๋ธŒ์ ํŠธ ๋‚ด์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋Š” ์ ์šฉ ๋˜์ง€ ์•Š๋Š”๋‹ค... (์ฃผ์˜์‚ฌํ•ญ)

    1. ex) ๊ฐ™์€ ํƒ€๊นƒ ๋‚ด์˜ ๋‘๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด delete()๊ฐ€ update() ํ˜ธ์ถœํ•˜๋ฉด update()์— ์ ์šฉ ๋œ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ จ advice๊ฐ€ ์ ์šฉ ๋˜์ง€ ์•Š๊ณ , delete()์— ์ข…์†๋˜์–ด ์ ์šฉ์ด ๋œ๋‹ค. (delete๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ํ˜ธ์ถœ, ์‹ค์ œ๋กœ๋Š” ํŠธ๋žœ์žญ์…˜ Proxy๊ฐ€ ํƒ€๊นƒ์„ ํ™€์ถœํ• ๋•Œ ์ ์šฉ)

    2. ex) ์œ„ ์˜ˆ๋Š” delete๊ฐ€ ํŠธ๋žœ์žญ์…˜๊ด€๋ จ ์–ด๋“œ๋ฐ”์ด์Šค๋กœ ๋“ฑ๋ก๋œ ์ผ€์ด์Šค์ง€๋งŒ, ๋งŒ์•ฝ์— ํŠธ๋žœ์žญ์…˜ ์–ด๋“œ๋ฐ”์ด์Šค๊ฐ€ ์—†๋Š” ํƒ€๊นƒ๋ฉ”์„œ๋“œ๊ฐ€ update๋ฅผ ํ˜ธ์ถœ ํ•œ๋‹ค๋ฉด ์•„์— ํŠธ๋žœ์žญ์…˜ ์–ด๋“œ๋ฐ”์ด์Šค๊ฐ€ ์ ์šฉ์กฐ์ฐจ ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒ

    3. ๊ธฐ๋ณธ์ ์ธ ์ฝ๊ธฐ์ „์š”, REQUIRED ๊ฐ™์€ ์†์„ฑ์—์„œ๋Š” ๋ฌธ์ œ ๋˜์ง€ ์•Š์ง€๋งŒ, ๋ณต์žกํ•œ ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ์†์„ฑ์„ ๋ช…์‹œํ•ด์•ผํ•  ๊ฒฝ์šฐ์—๋Š” ๊ฐ๋ณ„ํ•œ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค!!

  • ์ •๋ฆฌ

    ์Šคํ”„๋ง์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋ก์‹œ๊ธฐ๋ฐ˜์˜ AOP๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ(ํ”„๋ก์‹œ์‚ฌ์šฉ์‹œ ๋ฌธ์ œ์ ์€ ์œ„์—์„œ ์–ธ๊ธ‰), ํ•„์š”ํ•˜๋‹ค๋ฉด AspectJ ๊ฐ™์€ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ฒ”์šฉ์ ์ธ AOP๊ธฐ์ˆ ์„ ์‚ฌ์šฉ ํ•˜๋ฉด๋œ๋‹ค. ๊ท€์ฐฎ์€ ์ž‘์—…๋„ ๋’ค๋”ฐ๋ฅด๊ธด ํ•˜์ง€๋งŒ ์ด๋งŒํ•œ ๊ธฐ์ˆ ์ด ์—†๋‹ค! ๋!

ํŠธ๋žœ์žญ์…˜ ์†์„ฑ ์ ์šฉ

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๊ณ  ์žˆ๋Š” ์„œ๋น„์Šค ๊ณ„์ธต ์˜ค๋ธŒ์ ํŠธ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„๋ฅผ ๋ถ€์—ฌํ•˜๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๋Œ€์ƒ ๋ถ€๊ฐ€๋กœ์ง ๋ฐ ํŠธ๋žœ์žญ์…˜ ์†์„ฑ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ.. ์„œ๋น„์Šค -> DAO๋กœ ์ ‘๊ทผํ•˜๋„๋ก ๊ตฌํ˜„ (์–ด๋–ป๊ฒŒ ๋ณด๋ฉด MVCํŒจํ„ด?) tx์Šคํ‚ค๋งˆ์—์„œ propagation ์†์„ฑ ์ƒ๋žต -> ๋””ํดํŠธ : REQUIRED

6.7 ์• ๋…ธํ…Œ์ด์…˜ ํŠธ๋žœ์žญ์…˜ ์†์„ฑ๊ณผ ํฌ์ธํŠธ์ปท

์„ค์ •ํŒŒ์ผ๋กœ ์ ์šฉํ•˜๋Š” ๊ฒƒ ๋Œ€์‹ ์— ํƒ€๊ฒŸ์— ํŠธ๋ž™์žฐ์…˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง„ ์• ๋…ธํ…Œ์ด์…˜์„ ์ง€์ • ํ•  ์ˆ˜ ์žˆ์Œ

ํŠธ๋žœ์žญ์…˜ ์• ๋…ธํ…Œ์ด์…˜

  • @Transactional

    • ํƒ€๊นƒ์€ ๋ฉ”์„œ๋“œ์™€ ํƒ€์ž… -> ๋ฉ”์„œ๋“œ, ํด๋ž˜์Šค, ์ธํ„ฐํŽ˜์ด์Šค์— ์ ์šฉ ๊ฐ€๋Šฅ

    • ํƒ€๊ฒŸ์˜ค๋ธŒ์ ํŠธ๋กœ ์ž๋™ ์ธ์‹ํ•จ

    • ํŠธ๋žœ์žญ์…˜ ์†์„ฑ์„ ์ •์˜ + ํฌ์ธํŠธ์ปท ์ž๋™๋“ฑ๋ก

    • TransactionAttributeSourcePointcut ์‚ฌ์šฉ

  • ํŠธ๋žœ์žญ์…˜ ์†์„ฑ์„ ์ด์šฉํ•˜๋Š” ํฌ์ธํŠธ์ปท

    • AnnotationTransactionAttributeSource ์‚ฌ์šฉ -> ํฌ์ธํŠธ์ปท + ํŠธ๋žœ์žญ์…˜์†์„ฑ ์ง€์ •

    • ๋ถ€๊ฐ€๊ธฐ๋Šฅ ์ ์šฉ ๋‹จ์œ„๋Š” ๋ฉ”์„œ๋“œ -> ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜ ์†์„ฑ์ด ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋‹ค... -> ์ง€์ €๋ถ„ํ•ด์ง ๋‹จ์ 

  • ๋Œ€์ฒด์ •์ฑ…

    • ์œ„์˜ ๋ฌธ์ œํ•ด๊ฒฐ -> ์Šคํ”„๋ง์—์„œ 4๋‹จ๊ณ„ ๋Œ€์ฒด ์ •์ฑ…

    • ํƒ€๊นƒ๋ฉ”์„œ๋“œ, ํƒ€๊นƒํด๋ž˜์Šค, ์„ ์–ธ๋ฉ”์„œ๋“œ, ์„ ์–ธํƒ€์ž…(ํด๋ž˜์Šค, ์ด๋„กํŽ˜์ด์Šค) ์ˆœ์„œ์— ๋”ฐ๋ผ @Transactional์ด ์ ์šฉ ๋๋Š”์ง€ ์ฐจ๋ก€๋กœ ํ™•์ธ -> ๊ฐ€์žฅ๋จผ์ € ๋ฐœ๊ฒฌ๋˜๋Š” ์†์„ฑ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•จ

    • ์ธํ„ฐํŽ˜์ด์Šค์— @Transactional ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋‚˜. ์Šคํ”„๋ง์˜ ํ”„๋ก์‹œ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ฌด์‹œ๊ฐ€ ๋œ๋‹ค.. ์ด๋Ÿด๋•Œ๋Š” ๊ตฌํ˜„ํด๋ž˜์Šค(ํƒ€๊นƒ)์— ๋ช…์‹œํ•ด์•ผํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋Ÿด ๊ฒฝ์šฐ ๊ตฌํ˜„ํด๋ž˜์Šค๋งˆ๋‹ค ๋ช…์‹œํ•ด์•ผํ•˜๋Š” ์ค‘๋ณต์„ฑ์ด ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋˜๋Š” ๋‹จ์ ์ด ์žˆ๊ธฐ๋Š”ํ•˜๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉ์„ ์œ„ํ•œ ์„ค์ •

    ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ์€ xml ์„ค์ •์— ๊ด€๋ จ ์‚ฌ์šฉ์—ฌ๋ถ€ ๋ช…์‹œ ํ•„์š”

    <tx:annotation-driven>

ํŠธ๋žœ์žญ์…˜ ์–ด๋…ธํ…Œ์ด์…˜ ์ ์šฉ

ํŠธ๋žœ์žญ์…˜ ์—†๋Š” ๊ฒฝ์šฐ DAO์—์„œ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ๋„ ํ•œ๋‹ค. JDBC๋Š” -> ํŠธ๋žœ์žญ์…˜์ด ์—†์–ด๋„ ์‹คํ–‰ ๋จ

6.8 ํŠธ๋žœ์žญ์…˜ ์ง€์› ํ…Œ์ŠคํŠธ

์„ ์–ธ์  ํŠธ๋žœ์žญ์…˜๊ณผ ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ ์†์„ฑ

A ๋ฉ”์„œ๋“œ์—์„œ ์‹œ์ž‘๋œ ํŠธ๋žœ์žญ์…˜.. B๊ฐ€ A์—์„œ ํ˜ธ์ถœ๋œ๋‹ค๋ฉด ์ „ํŒŒ ์†์„ฑ์— ๋”ฐ๋ผ A๋Š” B์˜ ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„์˜ ์ผ๋ถ€๋กœ ํ†ตํ•ฉ์ด ๋œ๋‹ค. ์ด๋Ÿฐ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ •๊ณผ ์ „ํŒŒ์— ์˜ํ•ด ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€๊ฒŒ ๋จ

  • ์„ ์–ธ์  ํŠธ๋žœ์žญ์…˜

    AOP๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฝ”๋“œ ์™ธ๋ถ€์—์„œ ํŠธ๋žœ์žญ์…˜ ๊ธฐ๋Šฅ์„ ๋ถ€์—ฌํ•ด์ฃผ๊ณ , ์†์„ฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•

ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”์™€ ํ…Œ์ŠคํŠธ

ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™”, AOP ๋“ฑ์˜ ๊ธฐ์ˆ ์ด ์žˆ์—ˆ๊ธฐ์— ๊ฐ€๋Šฅ -> ์„ ์–ธ์  ํŠธ๋žœ์žญ์…˜, ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ

  • ํŠธ๋žœ์žญ์…˜์˜ ์ถ”์ƒํ™” ํ•ต์‹ฌ๊ธฐ์ˆ  1. ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €

    • PlatformTransactionManager -> ์ผ๊ด€๋œ ํŠธ๋žœ์žญ์…˜ ์ œ์–ด, ํŠธ๋žœ์žญ์…˜ ์ฐธ์—ฌ

      1. ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”

    • ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ด์œ 

    • ํŠธ๋žœ์žญ์…˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•ด๋†“๋Š” ์ €์žฅ์†Œ ์—ญํ• 

  • ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฝ๊ณ„์„ค์ •(์‹œ์ž‘)๊ณผ ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ ์†์„ฑ์„ ํ†ตํ•ด ๋กค๋ฐฑ ๋ฐ ์ปค๋ฐ‹๋“ฑ ์ž‘์—… ์œ ์šฉ

  • ํ•˜์ด๋ฒ„๋„ค์ดํŠธ, JPA ๊ฐ™์€ ORM๋“ฑ์˜ ์—”ํ‹ฐํ‹ฐ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ๋„ ์œ ์šฉ / ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์กฐํ•ฉํ•ด์„œ ์‚ฌ์šฉํ•  ๋•Œ๋„ ์œ ์šฉ

  • ํŠธ๋žœ์žญ์…˜์„ ์ œ์–ดํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋กค๋ฐฑ ๋“ฑ ๋‹ค์–‘ํ•˜๊ฒŒ ์‘์šฉ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค!

    -> ํ…Œ์ŠคํŠธ ๋‚ด์˜ ๋ชจ๋“  DB ์ž‘์—…์„ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜ ์•ˆ์— ๋‘๊ณ  ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚˜๋ฉด ๋กค๋ฐฑ์„ ํ•ด๋ฒ„๋ฆฌ๋Š” ํ…Œ์ŠคํŠธ!

    // ๋กค๋ฐฑ ํ…Œ์ŠคํŠธ!! ์ข‹์€๊ฑฐ ๊ฐ™๋‹ค! ๊ฒ€์ฆํ• ๋•Œ ๊ดœ์ถ˜ํ•œ๋“ฏ
    @Test
    public void transactionRollback() {
      DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
      TransactionStatus status = transactionManager.getTransaction(txDefinition);
      try {
        System.out.println("1 : " + userService.getAll());
        userService.deleteAll();
        System.out.println("2 : " + userService.getAll());
        userService.add(users.get(0));
        userService.add(users.get(1));
        System.out.println("3 : " + userService.getAll());
      } finally {
        System.out.println("4 : " + userService.getAll());
        transactionManager.rollback(status);  // ํ…Œ์ŠคํŠธ ํ›„ ๋กค๋ฐฑ -> ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ฐ˜์˜ ์ทจ์†Œ!
        System.out.println("5 : " + userService.getAll());
      }
    }

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ํŠธ๋žœ์žญ์…˜ ์–ด๋…ธํ…Œ์ด์…˜

ํ…Œ์ŠคํŠธ์—๋„ @Transactional์„ ์ ์šฉ ํ•  ์ˆ˜ ์žˆ์Œ @ContextConfiguration -> ์Šคํ”„๋ง์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด์คŒ

  • @Transactional

    ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์— ๋ถ™์ด๋ฉด, ํƒ€๊นƒ ํด๋ž˜์Šค๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค ์ ์šฉ ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ๋ฉ”์„œ๋“œ์— ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„๊ฐ€ ์ž๋™ ์„ค์ • ๋จ

    ํ…Œ์ŠคํŠธ ๋‚ด์— ์„œ ์ง„ํ–‰ํ•˜๋Š” ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜ ๊ด€๋ จ ์ž‘์—…์„ ํ•˜๋‚˜๋กœ ๋ฌถ์Œ!

  • @Rollback

    @Transactional ์€ ๋กค๋ฐฑ์„ ๋‹ด์œผ๋ ค๊ณ  ๋งŒ๋“  ์–ด๋…ธํ…Œ์ด์…˜์€ ์•„๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋กค๋ฐฑ์ œ์–ด๋Š” @Rollback ์„ ํ†ตํ•ด ์„ค์ •

    ๋ฉ”์†Œ๋“œ ๋ ˆ๋ฒจ์—๋งŒ ์ ์šฉ ๊ฐ€๋Šฅ

  • @TransactionConfiguration (depreacted)

    ํด๋ž˜์Šค๋ ˆ๋ฒจ์—์„œ ๊ณตํ†ต ์†์„ฑ ์ •์˜๊ฐ€๋Šฅ

  • ํŠธ๋žœ์žญ์…˜ ํ…Œ์ŠคํŠธ์™€ ๋น„ํŠธ๋žœ์žญ์…˜ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•˜์—ฌ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋ฅผ ๊ถŒ์žฅ

  • propagation=Propagation.NEVER -> ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘์•ˆํ•จ

ํšจ๊ณผ์ ์ธ DB ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ๋Š” ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌํ˜„ DB ์ ‘๊ทผ์‹œ์—๋Š” @Transactional์„ ํ†ตํ•œ ํŠธ๋žœ์žญ์…˜ ์„ค์ •๊ณผ ๋กง๋ฐฑํ…Œ์ŠคํŠธ ํ™œ์šฉ ์ฝ”๋“œ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ํ•œ ํ…Œ์ŠคํŠธ ์ˆœ์„œ๊ฐ€ ๋ฐ”๊ปด๋„ ์ผ์ •ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค ๋กค๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์•„์ฃผ ์œ ์šฉํ•˜๊ฒŒ ์ž‘์šฉ ๋  ๊ฒƒ์ž„!! ๊ตฟ๊ตฟ ํŠนํžˆ ๋‹จ์œ„ํ…Œ์ŠคํŠธ์—์„œ

Last updated