-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
2 changed files
with
131 additions
and
5 deletions.
There are no files selected for viewing
21 changes: 20 additions & 1 deletion
21
study/src/test/java/di/stage4/annotations/ClassPathScanner.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,29 @@ | ||
package di.stage4.annotations; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
public class ClassPathScanner { | ||
|
||
public static Set<Class<?>> getAllClassesInPackage(final String packageName) { | ||
return null; | ||
InputStream stream = ClassLoader.getSystemClassLoader() | ||
.getResourceAsStream(packageName.replaceAll("[.]", "/")); | ||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); | ||
return reader.lines() | ||
.filter(line -> line.endsWith(".class")) | ||
.map(line -> getClass(line, packageName)) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
||
private static Class<?> getClass(String className, String packageName) { | ||
try { | ||
return Class.forName(packageName + "." | ||
+ className.substring(0, className.lastIndexOf('.'))); | ||
} catch (ClassNotFoundException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
115 changes: 111 additions & 4 deletions
115
study/src/test/java/di/stage4/annotations/DIContainer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,131 @@ | ||
package di.stage4.annotations; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Parameter; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
import org.reflections.Reflections; | ||
|
||
/** | ||
* 스프링의 BeanFactory, ApplicationContext에 해당되는 클래스 | ||
*/ | ||
class DIContainer { | ||
|
||
private final Set<Object> beans; | ||
|
||
private final Set<Object> beans = new HashSet<>(); | ||
private final Map<Class<?>, Object> beanBySuperTypeMap = new HashMap<>(); | ||
|
||
public DIContainer(final Set<Class<?>> classes) { | ||
this.beans = Set.of(); | ||
for (Class<?> aClass : classes) { | ||
createBean(aClass); | ||
} | ||
for (Object bean : beans) { | ||
injectBean(bean); | ||
} | ||
} | ||
|
||
public static DIContainer createContainerForPackage(final String rootPackageName) { | ||
return null; | ||
Set<Class<?>> allClassesInPackage = ClassPathScanner.getAllClassesInPackage(rootPackageName); | ||
Set<Class<?>> beanCandidate = findBeanCandidate(allClassesInPackage); | ||
return new DIContainer(beanCandidate); | ||
} | ||
|
||
private static Set<Class<?>> findBeanCandidate(Set<Class<?>> allClassesInPackage) { | ||
return allClassesInPackage.stream() | ||
.filter(it -> it.isAnnotationPresent(Repository.class) | ||
|| it.isAnnotationPresent(Service.class)) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
||
private void createBean(Class<?> aClass) { | ||
if (beanBySuperTypeMap.containsKey(aClass)) { | ||
return; | ||
} | ||
if (aClass.isInterface()) { | ||
createInterfaceBean(aClass); | ||
return; | ||
} | ||
Constructor<?> declaredConstructor = aClass.getDeclaredConstructors()[0]; | ||
declaredConstructor.setAccessible(true); | ||
if (isDefaultConstructor(declaredConstructor)) { | ||
createBeanWithDefaultCtor(declaredConstructor); | ||
} else { | ||
createBeanWithCtorParameters(declaredConstructor); | ||
} | ||
} | ||
|
||
private void createInterfaceBean(Class<?> aClass) { | ||
Set<Class<?>> subTypes = findAllSubTypes(aClass); | ||
for (Class<?> subType : subTypes) { | ||
createBean(subType); | ||
return; | ||
} | ||
} | ||
|
||
private Set<Class<?>> findAllSubTypes(Class<?> aClass) { | ||
return (Set<Class<?>>) | ||
new Reflections(aClass.getPackage().getName()).getSubTypesOf(aClass); | ||
} | ||
|
||
private boolean isDefaultConstructor(Constructor<?> declaredConstructor) { | ||
Parameter[] parameters = declaredConstructor.getParameters(); | ||
return parameters.length == 0; | ||
} | ||
|
||
private void createBeanWithDefaultCtor(Constructor<?> declaredConstructor) { | ||
try { | ||
Object o = declaredConstructor.newInstance(); | ||
storeBean(o); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private void storeBean(Object o) { | ||
beanBySuperTypeMap.put(o.getClass(), o); | ||
if (o.getClass().getInterfaces().length != 0) { | ||
beanBySuperTypeMap.put(o.getClass().getInterfaces()[0], o); | ||
} | ||
beans.add(o); | ||
} | ||
|
||
private void createBeanWithCtorParameters(Constructor<?> declaredConstructor) { | ||
Parameter[] parameters = declaredConstructor.getParameters(); | ||
Object[] parameterBeans = new Object[parameters.length]; | ||
for (int i = 0; i < parameters.length; i++) { | ||
Class<?> type = parameters[i].getType(); | ||
createBean(type); | ||
parameterBeans[i] = getBean(type); | ||
} | ||
try { | ||
Object o = declaredConstructor.newInstance(parameterBeans); | ||
storeBean(o); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private void injectBean(Object bean) { | ||
for (Field field : bean.getClass().getDeclaredFields()) { | ||
field.setAccessible(true); | ||
if (!field.isAnnotationPresent(Inject.class)) { | ||
continue; | ||
} | ||
try { | ||
field.set(bean, getBean(field.getType())); | ||
} catch (IllegalAccessException e) { | ||
System.out.println("Inject 오류!"); | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public <T> T getBean(final Class<T> aClass) { | ||
return null; | ||
return (T) beanBySuperTypeMap.get(aClass); | ||
} | ||
} |