Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9892844
:heavy_plus_sign: 리플렉션 cnrk
yuntasha Apr 30, 2026
ce97712
:sparkles: Car 추가
yuntasha Apr 30, 2026
dc5f9a4
:sparkles: 어노테이션 추가 (컴파일 이슈)
yuntasha Apr 30, 2026
0eea9eb
:sparkles: 요구사항 3까지 구현
yuntasha Apr 30, 2026
026cfae
:recycle: 이름 변경
yuntasha Apr 30, 2026
fc518f2
:heavy_plus_sign: assertThat가져오기
yuntasha Apr 30, 2026
670a24d
:sparkles: getter 추가
yuntasha Apr 30, 2026
a68fe59
:sparkles: 요구사항 4 해결
yuntasha Apr 30, 2026
4402540
:sparkles: 요구사항 5 해결
yuntasha Apr 30, 2026
d69fdfc
:sparkles: Lecture 요구사항 1, 2 해결
yuntasha Apr 30, 2026
9104d4e
:sparkles: Lecture 요구사항 3 해결
yuntasha Apr 30, 2026
081b01b
:sparkles: Lecture 요구사항 4 해결
yuntasha Apr 30, 2026
ba30f34
:sparkles: Lecture 요구사항 5 해결
yuntasha Apr 30, 2026
8b136ae
:sparkles: Lecture 요구사항 6 해결
yuntasha Apr 30, 2026
c482f02
:sparkles: 컴포넌트 어노테이션 생성
yuntasha Apr 30, 2026
aeacaa9
:sparkles: Component 어노테이션 생성
yuntasha May 1, 2026
08b15a4
:sparkles: 스캐너가 실행되도록 작성
yuntasha May 1, 2026
2095347
:recycle: 빈 스토리지로 변경
yuntasha May 1, 2026
da39f2e
:sparkles: 컴포넌트 레포지토리 생성
yuntasha May 1, 2026
39351a7
:sparkles: autowired 적용
yuntasha May 5, 2026
f1dcf50
:sparkles: 위상정렬을 통한 만드는 순서 조정 및 예외처리
yuntasha May 5, 2026
cc636ac
Merge pull request #4 from yuntasha/week3
yuntasha May 5, 2026
d0eacac
:recycle: Autowired 요구사항에 맞게 변경
yuntasha May 16, 2026
7bb520a
Merge pull request #5 from yuntasha/week3-refactor
yuntasha May 16, 2026
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
7 changes: 7 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.gradle.internal.impldep.org.junit.Assert.assertThat

plugins {
id("java")
kotlin("jvm")
Expand All @@ -24,11 +26,16 @@ dependencies {

implementation(group = "org.json", name = "json", version = "20160810")

// aop
implementation("org.reflections:reflections:0.10.2")

// 톰캣
implementation("org.apache.tomcat.embed:tomcat-embed-core:8.5.42")
implementation("org.apache.tomcat.embed:tomcat-embed-jasper:8.5.42")

implementation(kotlin("stdlib-jdk8"))

implementation("org.assertj:assertj-core:3.24.2")
}

tasks.test {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/diy/app/Main.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.diy.app;

import com.diy.app.business.repository.LectureRepository;
import com.diy.framework.beans.factory.BeanStorage;
import com.diy.framework.web.server.TomcatWebServer;

public class Main {
public static void main(String[] args) {
BeanStorage beanStorage = BeanStorage.getInstance();
TomcatWebServer tomcatWebServer = new TomcatWebServer();
tomcatWebServer.start();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,31 @@
import com.diy.app.infra.dto.ModelAndView;
import com.diy.app.infra.httpSpec.HttpMethod;
import com.diy.app.infra.port.Controller;
import com.diy.framework.beans.annotations.Autowired;
import com.diy.framework.beans.annotations.Component;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component
public class LectureController implements Controller {

private LectureService service;
private ObjectMapper objectMapper;
private final ObjectMapper objectMapper;

@Autowired
public LectureController(LectureService service) {
objectMapper = new ObjectMapper();
this.service = service;
this.objectMapper = new ObjectMapper();
}

// public LectureController(LectureService service) {
// this.service = service;
// this.objectMapper = new ObjectMapper();
// }

@Override
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String uri = req.getRequestURI();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.diy.app.business.repository;

import com.diy.app.business.domain.Lecture;
import com.diy.framework.beans.annotations.Component;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Component
public class LectureRepository {
static LectureRepository instance;

AtomicLong nextId;
Map<Long, Lecture> lectureDB;
Expand All @@ -19,10 +20,6 @@ private LectureRepository() {
lectureDB = new ConcurrentHashMap<>();
}

public static LectureRepository getInstance() {
return instance == null ? instance = new LectureRepository() : instance;
}

public List<Lecture> getAll() {
return lectureDB.values().stream().toList();
}
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/com/diy/app/business/service/LectureService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@

import com.diy.app.business.domain.Lecture;
import com.diy.app.business.repository.LectureRepository;
import com.diy.framework.beans.annotations.Autowired;
import com.diy.framework.beans.annotations.Component;

import java.util.List;

@Component
public class LectureService {
private static LectureService instance = null;

private static LectureRepository repository = null;
private final LectureRepository repository;

private LectureService(LectureRepository repository) {
@Autowired
public LectureService(LectureRepository repository) {
this.repository = repository;
}

public static LectureService getInstance() {
return instance == null ? instance = new LectureService(LectureRepository.getInstance()) : instance;
}

public List<Lecture> getAllLectures() {
return repository.getAll();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.diy.app.business.service.LectureService;
import com.diy.app.infra.port.Controller;
import com.diy.app.infra.viewRender.ViewResolver;
import com.diy.framework.beans.factory.BeanStorage;

import java.util.Comparator;
import java.util.Map;
Expand All @@ -14,7 +15,7 @@ public class UrlControllerMapper {
private static UrlControllerMapper instance;

public UrlControllerMapper() {
uriToController.put("/lectures", new LectureController(LectureService.getInstance()));
uriToController.put("/lectures", BeanStorage.getInstance().getBean(LectureController.class).get());
}

public Controller findController(String uri) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/diy/app/infra/viewRender/JspView.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public void render(final HttpServletRequest req, final HttpServletResponse resp,
.getFile().split("resources/")[1];

final RequestDispatcher requestDispatcher = req.getRequestDispatcher(filePath);
for (String key : modelAndView.getModel().keySet()) {
req.setAttribute(key, modelAndView.getModel().get(key));
}
requestDispatcher.forward(req, resp);
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/diy/framework/beans/annotations/Autowired.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.diy.framework.beans.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
11 changes: 11 additions & 0 deletions src/main/java/com/diy/framework/beans/annotations/Component.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.diy.framework.beans.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}
35 changes: 35 additions & 0 deletions src/main/java/com/diy/framework/beans/factory/BeanScanner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.diy.framework.beans.factory;

import com.diy.framework.beans.annotations.Autowired;
import org.reflections.Reflections;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.stream.Collectors;

public class BeanScanner {

private final Reflections reflections;

public BeanScanner(final String... basePackages) {
reflections = new Reflections(basePackages);
}

public Set<Class<?>> scanClassesTypeAnnotatedWith(final Class<? extends Annotation> annotation) {
return reflections.getTypesAnnotatedWith(annotation)
.stream()
.filter(type -> (!type.isAnnotation() && !type.isInterface()))
.collect(Collectors.toSet());
}

public Constructor<?> scanConstructor(final Class<?> clazz) throws NoSuchMethodException {
Optional<Constructor<?>> autowired = Arrays.stream(clazz.getDeclaredConstructors())
.filter(constructor -> Objects.nonNull(constructor.getDeclaredAnnotation(Autowired.class)))
.findAny();
if (autowired.isPresent()) {
return autowired.get();
}
return clazz.getDeclaredConstructor();
}
}
67 changes: 67 additions & 0 deletions src/main/java/com/diy/framework/beans/factory/BeanStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.diy.framework.beans.factory;

import com.diy.framework.beans.annotations.Component;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

public class BeanStorage {

private static BeanStorage instance;

private final Map<String, Object> beans = new HashMap<>();
private final BeanScanner bc = new BeanScanner("com.diy.app");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

음.. 이걸 하드코딩 해도 괜찮을까요?


private BeanStorage() {
Set<Class<?>> classes = bc.scanClassesTypeAnnotatedWith(Component.class);
makeBeans(classes);
}

public static BeanStorage getInstance() {
if (Objects.isNull(instance)) instance = new BeanStorage();
return instance;
}

private void makeBeans(Set<Class<?>> classes) {
for (Class<?> clazz : classes) {
makeBean(clazz);
}
}

private Object makeBean(Class<?> clazz) {
Constructor<?> constructor = null;
try {
constructor = bc.scanConstructor(clazz);

Object[] params = Arrays.stream(constructor.getParameterTypes())
.map(paramType -> findBean(paramType).orElseGet(() -> makeBean(paramType)))
.toArray();

constructor.setAccessible(true);
Object bean = constructor.newInstance(params);
beans.put(clazz.getName(), bean);
return bean;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
} finally {
if (constructor != null) {
constructor.setAccessible(false);
}
}
}

private Optional<Object> findBean(final Class<?> classType) {
return beans.values().stream()
.filter(classType::isInstance)
.findAny();
}

public <T> Optional<T> getBean(final Class<T> classType) {
return beans.values().stream()
.filter(classType::isInstance)
.map(classType::cast)
.findAny();
}
}
37 changes: 37 additions & 0 deletions src/test/java/study/reflection/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package study.reflection;

public class Car {

private String name;
private int price;

public String getName() {
return name;
}

public int getPrice() {
return price;
}

public Car() {

}

public Car(String name, int price) {
this.name = name;
this.price = price;
}

@PrintView
public void printView() {
System.out.println("자동차 정보를 출력 합니다.");
}

public String testGetName() {
return "test : " + name;
}

public String testGetPrice() {
return "test : " + price;
}
}
8 changes: 8 additions & 0 deletions src/test/java/study/reflection/PrintView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package study.reflection;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface PrintView {
}
Loading