<repo_name>byeungoo/spring-main-technology<file_sep>/spring-main-tech02/src/main/java/com/hoon/scope/Proto.java
package com.hoon.scope;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) //빈을 받아올때 마다 새로운 인스턴스. 클래스 기반의 프록시로 감싸라. 감싸는 프록시 빈을 사용하게함
                                                                      //매번 바꿀 수 있도록 프록시 라이브러리로 감싸줌
public class Proto {
}
<file_sep>/spring-main-tech04/src/main/java/com/hoon/validation/NewEventRunner.java
package com.hoon.validation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import java.util.Arrays;


@Component
public class NewEventRunner implements ApplicationRunner {

    @Autowired
    LocalValidatorFactoryBean validatorFactoryBean;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println(validatorFactoryBean.getClass());

        Event event = new Event();
        event.setLimit(-1);
        event.setEmail("testsdfd");
        Errors errors = new BeanPropertyBindingResult(event, "event");  //Errors 타입의 구현체는 볼 일이 별로없음. spring mvc에서 자동으로 생성해서 제공

        validatorFactoryBean.validate(event, errors);

        System.out.println(errors.hasErrors());

        errors.getAllErrors().forEach(e -> {
            System.out.println("==== error code ====");
            Arrays.stream(e.getCodes()).forEach(System.out::println);
            System.out.println(e.getDefaultMessage());
        });
    }
}
<file_sep>/spring-main-tech02/src/main/resources/application.properties
app.name=spring
app.test=test<file_sep>/spring-main-tech-06/src/main/java/com/hoon/aop/ProxySimpleEventService.java
package com.hoon.aop;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Primary   //같은 타입의 빈이 있다면 그 중 한개 선택
@Service
public class ProxySimpleEventService implements EventService{  //AOP로 감싸는 클래스와 같은 인터페이스를 구현해야함

    @Autowired
    EventService simpleEventService;

    @Override
    public void createEvent() {
        long begin = System.currentTimeMillis();
        simpleEventService.createEvent();
        System.out.println(System.currentTimeMillis() - begin);
    }

    @Override
    public void publishEvent() {
        long begin = System.currentTimeMillis();
        simpleEventService.publishEvent();
        System.out.println(System.currentTimeMillis() - begin);
    }

    @Override
    public void deleteEvent() {
        simpleEventService.deleteEvent();
    }
}
<file_sep>/spring-main-tech-06/src/main/java/com/hoon/springaop/PerfAspect.java
package com.hoon.springaop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect //Aspect 클래스임을 알려줌
@Component  //빈으로 등록해줌
public class PerfAspect {

    //@Around("execution(* com.hoon.springaop..*.*(..))") //어디에 적용할지. 저렇게 하면 저 아래 모든 패키지의 모든 메소드에 적용됨
    @Around("@annotation(PerLoggin)")
    //@Around("bean(simpleAopEventService)") //그 빈이 가지고 있는 모든 public 메소드에 적용
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{ //pjp -> Advice가 적용되는 대상.
        long begin = System.currentTimeMillis();           //advice 정의
        Object retVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return retVal;
   }

   @Before("bean(simpleAopEventService)") //어떤 메소드가 실행되기 이전에 무언가를 하고 싶을 때
   public void hello(){
       System.out.println("hello");
   }

}
<file_sep>/src/main/java/com/hoon/Application.java
package com.hoon;

import com.hoon.beanReg.BeanReg;
import com.hoon.beanReg.BeanRegConfig;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanRegConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));
        BeanReg beanReg = (BeanReg) applicationContext.getBean("beanReg");
        System.out.println(beanReg.beanRegRepository != null);
    }
}
<file_sep>/README.md
스프링 메인 기술 학습.<file_sep>/spring-main-tech02/src/main/java/com/hoon/profile/TestBookRepository.java
package com.hoon.profile;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;

@Repository
@Profile("test") //테스트에서 사용할 repository로 정의 가능
public class TestBookRepository implements BookRepository {
}
<file_sep>/spring-main-tech-06/src/main/java/com/hoon/springaop/SimpleAopEventService.java
package com.hoon.springaop;

import org.springframework.stereotype.Service;

@Service
public class SimpleAopEventService implements AopEventService{

    @Override
    @PerLoggin
    public void createEvent() {
        try {
            Thread.sleep(1000);
            System.out.println("Created an Aop event");
        } catch(InterruptedException e){
            e.printStackTrace();
        }

    }

    @Override
    @PerLoggin
    public void publishEvent() {
        try {
            Thread.sleep(2000);
        } catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("Published an Aop event");
    }

    public void deleteEvent(){
        System.out.println("Delete an Aop event");
    }
}
<file_sep>/spring-main-tech04/src/main/java/com/hoon/databind/EventController.java
package com.hoon.databind;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EventController {

    @InitBinder //컨트롤러에서 사용할 바인더 등록
    public void init(WebDataBinder webDataBinder){  //데이터 바인더의 구현체 중 하나
        webDataBinder.registerCustomEditor(Event.class, new EventEditor());
    }

    @GetMapping("/event/{event}")
    public String getEvent(@PathVariable Event event){
        System.out.println(event);
        return event.getId().toString();
    }

    @GetMapping("/event/eventNm/{eventNm}")
    public String getEvent(@PathVariable String eventNm){   //스프링이 기본적으로 컨버터를 등록하지 않아도 String, Integer 이런거는 자동으로 변환해줌.
        System.out.println(eventNm);
        return eventNm;
    }

}
<file_sep>/src/main/java/com/hoon/beanReg/BeanRegRepository.java
package com.hoon.beanReg;

public class BeanRegRepository {
}
<file_sep>/spring-main-tech03/src/main/java/com/hoon/eventpublisher/AnotherHandler.java
package com.hoon.eventpublisher;

import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class AnotherHandler {

    @EventListener
    //@Order(Ordered.HIGHEST_PRECEDENCE+2)  //동일한 이벤트를 여러개 발생시킬 때 순서를 줄 수 있음
    @Async //비동기로 실행 순서 보장 x, order가 의미없음
    public void handle(MyEvent myEvent){
        System.out.println(Thread.currentThread().toString());
        System.out.println("Another" + myEvent.getData());
    }

}
<file_sep>/spring-main-tech-06/src/main/java/com/hoon/springaop/PerLoggin.java
package com.hoon.springaop;

import java.lang.annotation.*;
/*
 * 이 어노테이션을 사용하면성능을 로깅해 줍니다.
 */
@Retention(RetentionPolicy.CLASS) //이 어노테이션 정보를 어디까지 유지할꺼인지. default가 class임. 구지 런타임까지도 필요없고 기본값으로 해도 됨. source로 하면 컴파일하면 사라짐. class 이상 줌
@Documented  //java doc 만들 때
@Target(ElementType.METHOD) //타겟은 method 라고 명시하는거 정도는 괜찮음
public @interface PerLoggin {
}
<file_sep>/src/main/java/com/hoon/book/BookStatus.java
package com.hoon.book;

public enum BookStatus {

    DRAFT;

}
