Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1a3be46
docs: README 추가
guswns1659 Feb 25, 2023
578c69a
Merge pull request #32
guswns1659 Feb 25, 2023
888070c
7장 feat: BeanPostProcessor 학습테스트
guswns1659 Feb 25, 2023
e36c3b5
7장 feat: 커스텀 프록시 BeanPostProcessor 프로젝트에 적용
guswns1659 Feb 25, 2023
b5c4906
7장 chore: start-aop 의존성 추가
guswns1659 Feb 25, 2023
57f01e8
7장 chore: AspectJAutoProxyCreator 이용하여 프록시 생성
guswns1659 Feb 25, 2023
8f1602d
8장 feat: @Aspect 이용해 Advisor 생성
guswns1659 Feb 25, 2023
5000201
Merge pull request #33
guswns1659 Feb 25, 2023
bb06bdb
[스프링부트 - 이해와 원리] 2강 : 프로젝트 셋팅
guswns1659 Feb 26, 2023
37fcca2
Merge pull request #34
guswns1659 Feb 26, 2023
8f5440c
[스프링부트 - 이해와 원리] 3장 : 독립 실행형 서블릿 애플리케이션 실습
guswns1659 Feb 26, 2023
4b790f0
[스프링부트 - 이해와 원리] 4장 : ApplicationContext 이용한 DI 실습
guswns1659 Feb 26, 2023
3b36c98
[스프링부트 - 이해와 원리] 4장 : HttpServlet -> DispatcherServlet으로 변경
guswns1659 Feb 26, 2023
b39d6f3
[스프링부트 - 이해와 원리] 4장 : 자바 구성 정보 이용해 빈 초기화 진행
guswns1659 Feb 26, 2023
a7c0ae6
[스프링부트 - 이해와 원리] 4장 : @ComponentScan 적용
guswns1659 Feb 26, 2023
f0cf5d9
[스프링부트 - 이해와 원리] 4장 : MySpringApplication으로 스프링 부트 초기 코드 흉내내기
guswns1659 Feb 26, 2023
3b11ff0
[스프링부트 - 이해와 원리] 4장 : MySpringApplication -> 실제 SpringApplication으로 교체
guswns1659 Feb 26, 2023
77c235d
Merge pull request #35
guswns1659 Mar 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Spring-Internals

스프링 동작원리 및 다양한 기술을 이해하기 위한 실습 프로젝트.

## 내용
여러 강의를 수강하며 공부한 코드 or 개인적으로 관심있는 주제에 대해서 실습.

- [AssertJ](https://github.com/assertj/assertj) 동작원리 따라하며 구현하기
- 스프링 리액티브 프로그래밍
- 자바 비동기 프로그래밍
- RabbitMQ
- redis 이용한 동시성 제어
- Multi DataSource 라우팅 실습
- 스프링 DB : JDBC, @Transactional, ...
- 스프링 AOP

## 강의 출처
- [토비의 봄 TV - 스프링 리액티브 프로그래밍](https://www.youtube.com/watch?v=8fenTR3KOJo&list=PLOLeoJ50I1kkqC4FuEztT__3xKSfR2fpw)
- [스프링 DB 1편 - 데이터 접근 핵심 원리 스프링 DB 1편](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard)
- [스프링 DB 2편 - 데이터 접근 활용 기술](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard)
- [스프링 핵심 원리 - 고급편](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B3%A0%EA%B8%89%ED%8E%B8/dashboard)
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ include('spring-advanced-lecture:two')
include('springdb')
include('springdb2')
include('springtx')
include('toby-lecture')
include('toby-lecture:springboot-first')
include('webflux')
include('webmvc')
1 change: 1 addition & 0 deletions spring-advanced-lecture/two/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-aop")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.younghan.two;

import com.younghan.two.proxy.config.v3_proxyfactory.ProxyFactoryConfigV1;
import com.younghan.two.proxy.config.v5_autoproxy.AutoProxyConfig;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments1

import com.younghan.two.proxy.trace.logtrace.LogTrace;
import com.younghan.two.proxy.trace.logtrace.ThreadLocalLogTrace;
import org.springframework.boot.SpringApplication;
Expand All @@ -11,7 +11,9 @@
//@Import({AppV1Config.class, AppV2Config.class})
//@Import(DynamicProxyBasicConfig.class)
//@Import(DynamicProxyFilterConfig.class)
@Import(ProxyFactoryConfigV1.class)
//@Import(ProxyFactoryConfigV1.class)
//@Import(BeanPostProcessorConfig.class)
@Import(AutoProxyConfig.class)
@SpringBootApplication(scanBasePackages = "com.younghan.two.proxy.app")
public class TwoApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.younghan.two.proxy.config.v4_postprocessor;

import com.younghan.two.proxy.config.AppV1Config;
import com.younghan.two.proxy.config.AppV2Config;
import com.younghan.two.proxy.config.v3_proxyfactory.advice.LogTraceAdvice;
import com.younghan.two.proxy.config.v4_postprocessor.postprocessor.PackageLogTraceProxyPostProcessor;
import com.younghan.two.proxy.trace.logtrace.LogTrace;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Slf4j
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2

@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class BeanPostProcessorConfig {

@Bean
public PackageLogTraceProxyPostProcessor packageLogTraceProxyPostProcessor(LogTrace logTrace) {
String basePackage = "com.younghan.two.proxy.app";

// pointcut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

return new PackageLogTraceProxyPostProcessor(basePackage, advisor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.younghan.two.proxy.config.v4_postprocessor.postprocessor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

@Slf4j
public class PackageLogTraceProxyPostProcessor implements BeanPostProcessor {

private final String basePackage;
private final Advisor advisor;

public PackageLogTraceProxyPostProcessor(String basePackage, Advisor advisor) {
this.basePackage = basePackage;
this.advisor = advisor;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("param beanName={} bean={}", beanName, bean.getClass());

// proxy 생성 조건
String beanPackage = bean.getClass().getPackageName();
if (!beanPackage.startsWith(basePackage)) {
return bean;
}

ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvisor(advisor);
Object proxy = proxyFactory.getProxy();
log.info("create proxy: target={} proxy={}", bean.getClass(), proxy.getClass());
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3


return proxy;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.younghan.two.proxy.config.v5_autoproxy;

import com.younghan.two.proxy.config.AppV1Config;
import com.younghan.two.proxy.config.AppV2Config;
import com.younghan.two.proxy.config.v3_proxyfactory.advice.LogTraceAdvice;
import com.younghan.two.proxy.trace.logtrace.LogTrace;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Slf4j
@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class AutoProxyConfig {

@Bean
public Advisor advisor(LogTrace logTrace) {
// 정확하지 않은 pointcut
// NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
// pointcut.setMappedNames("request*", "order*", "save*");

// 정확한 pointcut
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.younghan.two.proxy.app..*(..)) && !execution(* com.younghan.two.proxy.app..noLog(..))");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

return new DefaultPointcutAdvisor(pointcut, advice);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.younghan.two.proxy.config.v6_aop;

import com.younghan.two.proxy.config.AppV1Config;
import com.younghan.two.proxy.config.AppV2Config;
import com.younghan.two.proxy.config.v6_aop.aspect.LogTraceAspect;
import com.younghan.two.proxy.trace.logtrace.LogTrace;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class AopConfig {

@Bean
public LogTraceAspect aspect(LogTrace logTrace) {
return new LogTraceAspect(logTrace);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.younghan.two.proxy.config.v6_aop.aspect;

import com.younghan.two.proxy.trace.TraceStatus;
import com.younghan.two.proxy.trace.logtrace.LogTrace;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LogTraceAspect {

private final LogTrace trace;

public LogTraceAspect(LogTrace trace) {
this.trace = trace;
}

@Around("execution(* com.younghan.two.proxy.app..*(..))")
public Object logTraceAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
TraceStatus status = null;
try {

String message = joinPoint.getSignature().toShortString();
status = trace.begin(message);

Object result = joinPoint.proceed();

trace.end(status);
return result;
} catch (Exception e) {
trace.exception(status, e);
throw e;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.younghan.two.proxy.postprocessor;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class BeanPostProcessorTest {

@Test
void beanPostProcessor() {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);

Assertions.assertThatThrownBy(() -> context.getBean("a", A.class))
.isInstanceOf(NoSuchBeanDefinitionException.class);
}

@Configuration(proxyBeanMethods = false)
static class BeanConfig {

@Bean
public A a() {
return new A();
}

@Bean
public AToBBeanPostProcessor aToBBeanPostProcessor() {
return new AToBBeanPostProcessor();
}
}

static class A {

}

static class B {

}

static class AToBBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof A) {
return new B();
}
return bean;
}
}
}


5 changes: 5 additions & 0 deletions toby-lecture/springboot-first/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package toby.lecture.springbootfirst;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {

private final HelloService helloService;

public HelloController(HelloService helloService) {
this.helloService = helloService;
}

@GetMapping
@ResponseBody
public String hello(String name) {
return helloService.sayHello(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package toby.lecture.springbootfirst;

public interface HelloService {

String sayHello(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package toby.lecture.springbootfirst;

import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class MySpringApplication {

public static void run(Class<?> applicationClass, String... args) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext() {
@Override
protected void onRefresh() {
super.onRefresh();

ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);

WebServer webServer = serverFactory.getWebServer(servletContext ->
servletContext.addServlet("dispatcherServlet", dispatcherServlet).addMapping("/"));
webServer.start();
}
};
context.register(applicationClass);
context.refresh();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package toby.lecture.springbootfirst;

import org.springframework.stereotype.Service;

@Service
public class SimpleHelloService implements HelloService{
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package toby.lecture.springbootfirst;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;

@Configuration
@ComponentScan
public class SpringbootFirstApplication {

@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}

@Bean
public ServletWebServerFactory serverFactory() {
return new TomcatServletWebServerFactory();
}

public static void main(String[] args) {
SpringApplication.run(SpringbootFirstApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading