Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions boa/src/main/java/beans/BeansException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package beans;

/**
* Beans 패키지에서 최상위 예외 클래스입니다.
* @author jungbin97
*/
public class BeansException extends RuntimeException {

public BeansException(String msg) {
super(msg);
}

public BeansException(String msg, Throwable cause) {
super(msg, cause);
}
}
40 changes: 40 additions & 0 deletions boa/src/main/java/beans/PropertyValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package beans;

import java.util.Objects;

/**
* PropertyValue 클래스는 빈의 속성 이름과 값을 저장하는 단순한 데이터 구조입니다.
* 이 클래스는 빈 정의에서 속성을 나타내며, 빈의 속성 설정에 사용됩니다.
*
* @author jungbin97
*/
public class PropertyValue {
private final String name;
private final Object value;

public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}

public String getName() {
return name;
}

public Object getValue() {
return value;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
PropertyValue that = (PropertyValue) obj;
return Objects.equals(name, that.name) && Objects.equals(value, that.value);
}

@Override
public int hashCode() {
return Objects.hash(name, value);
}
}
51 changes: 51 additions & 0 deletions boa/src/main/java/beans/PropertyValues.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package beans;

import java.util.ArrayList;
import java.util.List;

/**
* 하나 이상의 PropertyValue 객체를 담는 컨테이너 클래스 입니다.
* BeanDefinition 내에서 빈이 가질 모든 속성 값들을 관리합니다.
* @author jungbin97
*/
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();

/**
* 새로운 PropertyValue 객체를 추가합니다.
* @param propertyValue 추가할 PropertyValue 객체
*/
public void addPropertyValue(PropertyValue propertyValue) {
propertyValueList.add(propertyValue);
}

/**
* 이 PropertyValues 객체에 저장된 모든 PropertyValue 객체를 반환합니다.
* @return PropertyValue 객체의 리스트
*/
public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}

/**
* 주어진 이름에 해당하는 PropertyValue 객체를 반환합니다.
* @param propertyName 찾을 PropertyValue의 이름
* @return 해당 이름의 PropertyValue 객체, 없으면 null
*/
public PropertyValue getPropertyValue(String propertyName) {
for (PropertyValue pv : this.propertyValueList) {
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}

/**
* 하나라도 PropertyValue 객체가 존재하는지 확인합니다.
* @return 비어있으면 true, 그렇지 않으면 false
*/
public boolean isEmpty() {
return this.propertyValueList.isEmpty();
}
}
13 changes: 13 additions & 0 deletions boa/src/main/java/beans/factory/Aware.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package beans.factory;

/**
* 프레임워크의 특정 구성 요소에 대한 의존성을 주입받고자 하는 빈들이 구현하는
* 촤상위 마커(marker) 인터페이스 입니다.
* <p>
* 이 인터페이스 자체는 메서드를 가지고 있지 않으며, Aware 관련 콜백 인터페이스들을
* 그룹화하는 역할을 합니다. 빈이 이 인터페이스의 하위 인터페이스를 구현하면,
* 컨테이너는 해당 빈에 필요한 프레임워크 객체를 주입해 줍니다.
* @author jungbin97
*/
public interface Aware {
}
19 changes: 19 additions & 0 deletions boa/src/main/java/beans/factory/BeanFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package beans.factory;

import beans.BeansException;

/**
* 빈 컨테이너 루트 인터페이스
* <p>
* 빈 인스턴스를 조회하는 getBean 메서드를 제공하며, 빈 이름과 타입을 기반으로 빈을 조회할 수 있는 메서드도 포함되어 있습니다.
* @author jungbin97
*/
public interface BeanFactory {
Object getBean(String beanName) throws BeansException;

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

<T> T getBean(Class<T> requiredType) throws BeansException;

boolean containsBeans(String name);
}
24 changes: 24 additions & 0 deletions boa/src/main/java/beans/factory/BeanFactoryAware.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package beans.factory;

import beans.BeansException;

/**
* 빈(Bean)이 자신을 생성한 {@link BeanFactory}를 인식(aware)하기 위해 구현하는 콜백 인터페이스입니다.
* <p>
* 이 인터페이스는 주로 빈이 다른 빈을 프로그래밍 방식으로 조회(lookup)하거나
* 팩토리의 다른 기능에 접근해야 하는 고급 시나리오에서 사용됩니다.
* <p>
* <b>참고:</b> 이 콜백은 빈의 속성(property)이 모두 설정된 후, 그리고
* {@code @PostConstruct}나 {@code init-method} 같은 초기화 콜백이 호출되기 전에 실행됩니다.
*
* @author jungbin97
*/
public interface BeanFactoryAware extends Aware {

/**
* 이 빈을 생성한 BeanFactory의 인스턴스를 콜백으로 제공합니다.
* @param beanFactory 이 빈을 소유하는 BeanFactory (null이 아님).
* @throws BeansException 콜백 메서드 실행 중 예외가 발생한 경우
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
11 changes: 11 additions & 0 deletions boa/src/main/java/beans/factory/FactoryBean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package beans.factory;

public interface FactoryBean<T> {
T getObject() throws Exception;

Class<T> getObjectType();

default boolean isSingleton() {
return true;
}
}
17 changes: 17 additions & 0 deletions boa/src/main/java/beans/factory/InitializingBean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package beans.factory;

/**
* InitializingBean 인터페이스는 빈의 속성이 설정된 후에 추가적인 초기화 작업을 수행할 수 있는 메서드를 정의합니다.
* <p>
* 이 인터페이스를 구현하는 클래스는 afterPropertiesSet 메서드를 오버라이드하여 초기화 로직을 작성할 수 있습니다.
* @author jungbin97
*/
public interface InitializingBean {
/**
* 빈의 속성이 설정된 후에 호출되는 메서드입니다.
* <p>
* 이 메서드는 빈의 모든 속성이 설정된 후에 추가적인 초기화 작업을 수행하는 데 사용됩니다.
* @throws Exception 초기화 과정에서 오류가 발생할 경우
*/
void afterPropertiesSet() throws Exception;
}
21 changes: 21 additions & 0 deletions boa/src/main/java/beans/factory/NoSuchBeanDefinitionException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package beans.factory;

import beans.BeansException;

public class NoSuchBeanDefinitionException extends BeansException {
private final String beanName;

public NoSuchBeanDefinitionException(String name) {
super("No bean named '" + name + "' is defined");
this.beanName = name;
}

public NoSuchBeanDefinitionException(String beanName, String message) {
super("No bean named '" + beanName + "' available: '" + message);
this.beanName = beanName;
}

public String getBeanName() {
return this.beanName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package beans.factory;

import beans.BeansException;

import java.util.Collection;

/**
* 타입으로 빈을 조회할 때, 유일한 빈을 결정할 수 없는 경우 발생하는 예외입니다.
* <p>
* 예를 들어, 같은 타입을 구현하는 빈이 두 개 이상 등록되어 있을 때 발생합니다.
*
* @author jungbin97
*/
public class NoUniqueBeanDefinitionException extends BeansException {
private final Class<?> beanType;
private final int numberOfBeansFound;

public NoUniqueBeanDefinitionException(Class<?> beanType, Collection<String> beanNamesFound) {
super("No unique bean of type '" + beanType.getName() + "' is defined: " +
"expected single bean but found " + beanNamesFound.size() + ": " +
String.join(", ", beanNamesFound));
this.beanType = beanType;
this.numberOfBeansFound = beanNamesFound.size();
}

public Class<?> getBeanType() {
return this.beanType;
}

public int getNumberOfBeansFound() {
return this.numberOfBeansFound;
}
}
119 changes: 119 additions & 0 deletions boa/src/main/java/beans/factory/config/BeanDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package beans.factory.config;

import beans.PropertyValues;

import java.util.Objects;

/**
* 빈(Bean)의 설계 정보를 담는 클래스 (Bean Metadata) 입니다.
* <p>
* 빈의 클래스 타입, 프로퍼티, 스코프, 생명주기 콜백 메서드 등의 메타정보를 관리합니다.
* @author jungbin97
*/
public class BeanDefinition {
public static final String SCOPE_SINGLETON = "singleton";
public static final String SCOPE_PROTOTYPE = "prototype";

private final Class<?> beanClass;

private final PropertyValues propertyValues;

private String initMethodName;
private String destroyMethodName;
private String scope = SCOPE_SINGLETON;
private boolean lazyInit = false;

public BeanDefinition(Class<?> beanClass) {
this(beanClass, null);
}

public BeanDefinition(Class<?> beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}

// --- Getter ---
public Class<?> getBeanClass() {
return this.beanClass;
}

public PropertyValues getPropertyValues() {
return propertyValues;
}

public String getInitMethodName() {
return initMethodName;
}

public String getDestroyMethodName() {
return destroyMethodName;
}

public String getScope() {
return scope;
}

public String getBeanClassName() {
return beanClass.getName();
}

public boolean isLazyInit() {
return lazyInit;
}

// --- Setter ---
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}

public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}

public void setScope(String scope) {
this.scope = scope;
}

public void setLazyInit(boolean lazyInit) {
this.lazyInit = lazyInit;
}

public boolean isSingleton() {
return SCOPE_SINGLETON.equals(scope);
}

public boolean isPrototype() {
return SCOPE_PROTOTYPE.equals(scope);
}

@Override
public boolean equals(Object other) {
if (this == other) return true;

if (other == null || getClass() != other.getClass()) return false;

BeanDefinition that = (BeanDefinition) other;
return Objects.equals(beanClass, that.beanClass) &&
Objects.equals(propertyValues, that.propertyValues) &&
Objects.equals(initMethodName, that.initMethodName) &&
Objects.equals(destroyMethodName, that.destroyMethodName) &&
Objects.equals(scope, that.scope) &&
lazyInit == that.lazyInit;
}

@Override
public int hashCode() {
return Objects.hash(beanClass, propertyValues, initMethodName, destroyMethodName, scope, lazyInit);
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("class [");
sb.append(getBeanClassName()).append("]");
sb.append("; scope=").append(scope);
sb.append("; lazyInit=").append(lazyInit);
sb.append("; initMethodName=").append(initMethodName);
sb.append("; destroyMethodName=").append(destroyMethodName);
return sb.toString();
}
}
20 changes: 20 additions & 0 deletions boa/src/main/java/beans/factory/config/BeanReference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package beans.factory.config;

/**
* 다른 빈에 대한 참조를 나타내는 클래스입니다.
* <p>
* 이 객체는 빈의 프로퍼티 값으로 사용되며,
* 런타임에 IoC 컨테이너가 해당 빈을 찾아 주입해야하는 것을 나타냅니다.
* @author jungbin97
*/
public class BeanReference {
private final String beanName;

public BeanReference(String beanName) {
this.beanName = beanName;
}

public String getBeanName() {
return beanName;
}
}
Loading