[신세계I&C KDT][Spring Boot] #36 로깅 처리, 빈 생성, 의존성 주입, AOP (0531)

박현아·2024년 6월 4일
0

신세계아이앤씨 KDT

목록 보기
40/42

1. Spring Boot 등장 배경

  • 2016년에 등장
  • 기존의 framework에서는 개발자가 처리해야되는 많은 설정이 있었기 때문에 설정 자체가 매우 복잡했음
  • 실제 비즈니스 로직에 집중하지 못 함 -> Spring Boot라는 서브 프로젝트 생김
  • 많은 설정들을 자동화해서 실제 비즈니스 로직에 집중할 수 있도록 도와줌

2. Spring Boot 장점, 특징

1) 설정 자동화

pom.xml에 의존성 설정하면 자동으로 지정된 의존성에 맞는 환경을 설정해줌

2) 라이브러리 자동 관리

maven + starter

3) 웹 어플리케이션 프로젝트인 경우에도 jar 실행 가능

cf) 어플리케이션 개발 후 배포 방법

  • 비웹 어플리케이션
    일반적인 Java SE 환경 : jar
    Spring Framework 환경 : jar
    Spring Boot 환경 : jar

  • 웹 어플리케이션
    기본 Servlet/JSP 환경 : war
    Spring Framework 환경 : war
    Spring Boot 환경 : jar/war (톰캣이 내장되어 있어서 jar를 실행 가능)
    jar 실행 : java -jar 파일명.jar

4) boot 프로젝트의 설정 정보

: src/main/resources의 application.properties (application.yml 야물) 이용해서 전반적인 환경 설정을 함
- application.properties

    	server.error.whitelabel.enabled=false
        server.port=8090
  • application.yml
		server:
	  		error:
	    		whitelabel:
	      			enabled: false
	      
	 		 port: 8090

둘이 형식이 다르다

3. Spring Boot Starter

https://docs.spring.io/spring-boot/docs/2.7.18/reference/htmlsingle/#using.build-systems.starters

1) starter 개념

  • 필요한 jar 파일들의 묶음

2) 참조 사이트

http://mvnrepository.com에서 starter 사용 가능

4. XXXApplication.java

https://docs.spring.io/spring-boot/docs/2.7.18/reference/htmlsingle/#getting-started.first-application.code.spring-boot-application

@SpringBootApplication
public class Application {
	// 필수
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

1) 특징

  • 스프링 부트에서 필수 코드
  • 시작점 역할
  • @SpringBootApplication 어노테이션 필수

2) 3가지 어노테이션 포함

(1) @SpringBootConfiguration

  • 개발자가 필요에 의해 추가적인 Configuration을 설정할 수 있도록 지원
  • 클래스를 작성하고 @Configuration 지정
  • 대표적으로 Spring Security

(2) @EnableAutoConfiguration

  • pom.xml에 starter같은 의존성을 설정하면 거의 자동으로 필요한 설정을 해줌. 자동 구성 매커니즘 활성화
  • 예> spring-boot-starter-web 지정하면 자동으로 tomcat 설치되고 404 발생시 자동으로 Whitelabel~ 페이지를 제공

(3) @ComponentScan

  • 자동으로 빈생성하는 방법. 기본적으로 패키지 단위로 설정해서 자동으로 생성하도록 가이드
  • scan 방법 두 가지
    - 패키지 지정하지 않는 경우
    @SpringBootApplication 가진 Application.java의 패키지와 같거나 서브 패키지로 작성하면 자동으로 scan 됨 (권장 방법)
    - 패키지 지정한 경우
    명시적으로 생성할 빈의 패키지명을 알려줘야된다
    예> Application.java에서 @SpringBootApplication(scanBasePackages = {"com.exam2"})

5. 로깅 처리

https://docs.spring.io/spring-boot/docs/2.7.18/reference/htmlsingle/#features.logging

1) 개요

  • System.out.println 대신 특정 값(로그값)을 상황에 맞게 콘솔(파일)에 출력

2) 로그처리를 전문적으로 해주는 라이브러리

  • log4J 라이브러리 (framework)

  • logback 라이브러리 (boot 기본 로깅 담당)

  • 로깅 처리 구조

SLF4J (인터페이스, 스펙) - log()
	  |
      | 구현
      |
log4J   logback

3) 로깅 레벨

trace
debug
info (기본)
warn
error

=> application.properties에 로깅 레벨을 설정
=> 동작 방식은 지정된 레벨 포함한 하위 레벨까지 로깅 처리됨

4) boot에서 로깅처리를 담당하는 의존성이 있음

spring-boot-starter의 서브로
spring-boot-starter-logging이 담당
log4J
logback
slf4j

5) 적용

  • application.properties에 로깅 레벨을 설정
  • 문법:
    logging.level.관심있는패키지명 = 로그레벨
  • 로깅레벨
    logging.level.org.springframework=debug
    logging.level.com.exam=info

  • 파일에 저장1 (경로지정만 함)
    logging.file.path=c://log ( spring.log 파일이 생성됨 )

  • 파일에 저장2 (경로지정 + 파일명 같이 지정)
    logging.file.name=c:\temp\test2.log

6) 사용자 지정 로그 출력

  • application.properties
    logging.level.com.exam=trace

  • java
    Logger logger = LoggerFactory.getLogger(getClass());

  • 로그 출력

logger.trace("trace:{},{}", "trace1","trace2");
logger.debug("debug:{}", "debug");
logger.info("info:{}", "info");
logger.warn("warn:{}", "warn");
logger.error("error:{}", "error");

6. 빈 생성 방법

  • 항상 Application.java의 패키지와 같거나 서브 패키지로 빈을 작성하자 !!!!!!!! ★★★★★

1) 명시적으로 생성

  • @Configuration + @Bean 이용
    - @Configuration을 통해서 @Bean으로 지정한 빈을 생성
    - @Bean은 메서드 레벨만 가능
    @Configuration은 클래스 레벨만 가능

2) 다른 패키지로 되어있는 경우

  • 명시적으로 패키지를 알려줘야됨
@SpringBootApplication (scanBasePackages = {"com.exam2"})
        public class Application { }

3) 자동으로 생성 (권장 패키지 구조)

https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.structuring-your-code.locating-the-main-class

  • (1) @SpringBootApplication과 같은 패키지이거나 서브 패키지로 작성한다
  • (2) 클래스에 어노테이션을 지정한다
    (@Configuration,@Component,@Repository,@Service,@Controller,@RestController)
  • 예>
    com.exam
@SpringBootApplication(  ,  , @ComponentScan)
Application.java
xxx
	// @Bean으로 빈 생성시 빈 정보를 설정하는 빈에서 사용
	@Configuration (빈으로 생성됨)
    Test.java
    
    // 범용적으로 사용
    @Component
    Hello.java
    
    // DAO 역할의 빈에서 사용
    @Repository
    World.java
    
    // Service 역할의 빈에서 사용
    @Service
    World2.java
    
    // @RestController
    @Controller
    World3.java

7. 의존성 설정

1) 구조

DeptSevice
@Service					   @Repository
DeptServiceImpl -------------> DeptDAO

// @Repository 만들어주고 생성자에 파라미터로 넣어주면 의존성 주입이 됨

DeptDAO dao;
public DeptServiceImpl(DeptDAO dao) {
	this.dao = dao;
}

2) 묵시적 설정 방법

(1) 생성자 이용 (권장 방법)

  • 기본 생성자는 없어야됨
  • 권장하는 이유는 하나의 블럭에서 모든 주입이 완료되기 때문. 또 주입받는 시점이 생성 시점이기 때문에 @Autowired 보다 훨씬 빠르다
DeptDAO dao;
// 생성자
public DeptServiceImpl(DeptDAO dao){
	this.dao = dao;
}

(2) 어노테이션 이용

  • @Autowired
@Autowired
DeptDAO deptDAO;

3) 주입 가능한 타입이 여러 개인 경우

  • 기본적으로 에러가 발생됨
  • 해결 방법 :
    @Primary
    @Qualifier("빈이름")
@Repository("empDAO")
@Primary
public class EmpDAO

// 생성자 주입 이용
public DeptServiceImpl(@Qualifier("deptDAO") CommonDAO commonDAO) {}

// @Autowired 이용
@Autowired
@Qualifier("empDAO")
CommonDAO commonDAO;

4) 생성자 주입과 @Autowired 혼합 가능

5) 명시적 설정 방법
은 skip. 거의 안 쓴다

8. 생성된 빈 접근하는 방법

: MVC 환경에서는 쓸 일 거의 없음. SE 환경에서 사용

// IoC Container 얻기 (얘도 빈)
ApplicationContext ctx;

public 생성자 (ApplicationContext ctx) {
	this.ctx = ctx;
}

또는 
@Autowired
ApplicationContext ctx;

ctx.getBean("xxx", 클래스명.class); // @Service("xxx") public class DeptServiceImpl

9. 빈의 scope

1) 개념

  • 빈 생성 후에 ctx.getBean()을 여러 번 했을 때 반환되는 빈의 스코프를 의미한다
  • 기본적으로 bean은 한 번만 생성되고 getBean()을 여러 번 했을 때 동일한 인스턴스를 반환함 (싱글톤)
  • 예>
DeptServiceImpl s = ctx.getBean("xxx", DeptServiceImpl.class);
DeptServiceImpl s2 = ctx.getBean("xxx", DeptServiceImpl.class);

2) scope 값 종류

@Scope(value=상수값)

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope("prototype")
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) // 기본
@Scope("singleton")
  • singleton (기본, 단 하나의 빈으로 서비스, thread-unsafe)

  • prototype (getBean 할 때마다 매번 생성해서 서비스, thread-safe)

  • request (web 사용 가능. 요청~응답 사이에서만 사용 가능)

  • session (web 사용 가능. 기본적으로 web 브라우저가 open 되어있는 동안 사용 가능)

  • application (web 사용 가능. 기본적으로 Tomcat 컨테이너가 start 되어있는 동안 사용 가능)

10. 초기화 및 cleanup 작업 처리

https://docs.spring.io/spring-framework/docs/5.2.25.RELEASE/spring-framework-reference/core.html#beans-factory-lifecycle

1) 개요

  • 빈이 생성되고 의존성 주입 이후의 초기화 작업 및 자원 반납 작업 처리가 가능하도록 지원한다

2) @PostConstruct 와 @PreDestroy 이용

예>

@PostConstruct
public void init() {
	// 초기화 작업
}

@PreDestroy
public void clean() {
	// cleanup 작업
}

11. 프로파일 (Profile)

https://docs.spring.io/spring-boot/docs/2.7.18/reference/htmlsingle/#features.external-config.files.profile-specific

1) 개요

  • 실제로 개발할 때는 개발 환경, Q/A 환경, .. , production 환경
    다양한 환경을 개발자가 선택적으로 정해서 환경을 맞출 수 있는 개념

2) profile에 따라서 properties 파일 선택하는 방법

  • 여러 개의 application.properties 필요

  • 문법
    : application-프로파일명.properties (yml)

  • application.properties (기본)
    에서 동작할 프로파일명 지정
    - spring.profiles.active = prod
    (지정한 프로파일명에 해당하는 application-프로파일.properties가 실제로 실행됨)

  • application-dev.properties (개발용)
    application-prod.properties (product용)

3) profile에 따라서 빈 파일 선택하는 방법

  • application.properties (기본) 에서 동작할 프로파일명 지정
spring.profiles.active = prod 

@Profile("dev")
public class DevBean{ }

@Profile("prod")
public class ProdBean{ }

12. AOP (Aspect Oriented Programming : 관점 지향 프로그래밍)

https://docs.spring.io/spring-framework/docs/5.2.25.RELEASE/spring-framework-reference/core.html#aop

cf) OOP (Object Orietned Programming : 객체 지향 프로그래밍)

1) 개념

  • 핵심 기능과 부수 기능을 분리하고 필요시 부수기능을 주입 받아서 구현하는 개발 방법
  • 각 layer가 달라도 공통적으로 사용되는 코드들이 있음 (부수 기능)
  • @Transactional이 AOP 개념을 활용한 기능
    예> 로그 처리
브라우저 ----------------> A서블릿 -----> 서비스 -----> DAO ------> DB
                    (핵심기능:필수)     (핵심기능)    (핵심기능)
			       		 +                +            +
			          부수기능)        부수기능)       부수기능)
			      
브라우저 ----------------> B서블릿 -----> 서비스 -----> DAO ------> DB
                    (핵심기능:필수)     (핵심기능)    (핵심기능)
			       		 +                +            +
			          부수기능)        부수기능)       부수기능)

2) AOP 기술

(1) AOP 원천 기술

  • AspectJ (1995년)
  • 굉장히 무겁다
    startup 시간이 많이 걸림
  • target class의 많은 이벤트가 발생시 AOP 적용될 수 있다
    예> 변수값이 변경,
    생성자 호출,
    메서드 호출,
    ...

2) Spring AOP

  • 원천기술인 AspectJ에서 일부분의 기술만 빌려와서 만듦
  • Spring 기반의 AOP 프레임워크
  • target class에서 메서드 호출(*)되는 이벤트에서만 AOP가 적용됨

3) 용어 정리

(1) Aspect

  • 여러 빈에 공통적으로 사용되는 부수 기능을 구현한 빈을 의미
  • @Aspect 어노테이션 사용

(2) JoinPoint

  • 핵심 기능에 Aspect가 적용되는 시점을 의미
    Spring AOP에서는 메서드 호출되는 시점만을 의미한다
  • 이벤트로 적용됨
    예> 핵심 기능에서 발생 가능한 이벤트 종류 ?
  • 핵심 기능 (타겟 클래스: target class)
@Service
public class DeptServiceImpl{

	int num;  // 값 변경 이벤트

	public void setNum(int n){ } // 메서드 호출 이벤트
	public int getNum(){ }       // 메서드 호출 이벤트
	public DeptServiceImpl(){ } // 생성자 호출 이벤트
	..
}
  • 부가기능(로깅처리)
@Aspect
public class MyAspect{
	public void log_print(){
		s.o.p("로그출력");
	}
}

(3) PointCut

https://docs.spring.io/spring-framework/docs/5.2.25.RELEASE/spring-framework-reference/core.html#aop-pointcuts-examples

  • JoinPoint는 AOP가 주입되는 시점인 메서드 호출 시점을 의미하고 PointCut 는 메서드들 중에서 어떤 메서드를 호출했을 때 주입할 것인지를 알려주는 표현식이다
execution("public int getNum()")
execution("public int get*()")
execution("public * get*()")
execution("public * get*(**)")

(4) Advice

  • JoinPoint는 AOP가 주입되는 시점인 메서드 호출시점을 의미하고 PointCut 는 메서드들 중에서 어떤 메서드를 호출했을 때 주입할 것인지를 알려주는 표현식이고
    Advice 호출된 메서드 전/후/성공/에러/(전,후,성공,에러)/ 시점을 의미

전 : @Before
후 : @After
성공 : @AfterReturning
실패 : @AfterThrowing
(전,후,성공,에러) : @Around

예>

  • 사용
DeptServiceImpl service = ctx.getBean();

//전
int n = service.getNum();
//후

(5) weaving

  • target object 와 aspect 연결 의미

4) 구현

(1) 의존성 설정

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

==> aspectjweaver-1.9.7.jar 다운로드됨

(2) Aspect 작성

  • 부가 기능을 구현한 빈
  • @Aspect 어노테이션 지정

(3) Aspect 내에서 advice와 pointcut을 설정

  • @Before(pointcut 설정)
    - target object의 필수 기능인 메서드가 호출하기 전에 위빙
    • 예> @Before("execution(public say(..))")
  • @After(pointcut 설정)
    - target object의 필수 기능인 메서드가 호출한 후에 위빙
    • 예> @After("execution(public say(..))")
  • @AfterReturning(pointcut="pointcut 설정", returning=리턴값저장변수설정)
    - https://docs.spring.io/spring-framework/docs/5.2.25.RELEASE/spring-framework-reference/core.html#aop-advice-after-returning
    - target object의 필수 기능인 메서드가 리턴한 값을 얻을 수 있다
    • 예> @AfterReturning(pointcut="execution(public say(..))", returning="xxx")
  • @AfterThrowing(pointcut="pointcut 설정", returning=발생된예외저장변수설정)
    - target object의 필수 기능인 메서드가 예외 발생되었을 때
    - 예> @AfterThrowing(pointcut="execution(public say(..))", throwing="ex")
  • @Around(pointcut설정)
    - @Before + @After + @AfterReturning + @AfterThrowing 모두 포함하는 기능
    • 예>
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
	Object retVal = pjp.proceed();
	return retVal;
}

5) AOP 패턴

(1) Pointcut 정의한 빈 작성

public class CommonPointcutConfig {

@Pointcut("execution(public say(..))")
public void businessService() {}

@Pointcut("execution(public aa(..))")
public void businessService2() {}
}

(2) Aspect에서 빈의 메서드 호출해서 pointcut 적용

0개의 댓글