- Spring IoC 컨테이너가 관리하는 자바 객체
- 생성 방법만 명시하면 스프링이 알아서 객체를 생성하고 유지하고 소멸시킨다
- @Bean - 외부 라이브러리 객체
- @Component - 내가 만든 객체
- @Configuration - 설정
- @Controller - 주소 매핑
- @Service - 비지니스 로직
- @Repository - DB, 데이터 소스
- @ComponentScan
@ComponentScan 어노테이션이 붙은 패키지 하위의 모든 @Bean과 @Component를 스캔하여
객체를 생성
객체의 생성과 관리를 개발자가 아닌 프레임워크 또는 컨테이너가 담당하는 디자인 패턴
- 개발자가 어떤 클래스를 사용하고 싶다면, 그 클래스가 필요로 하는 의존성들을 스프링 컨테이너에 알려주면 됨. 그러면 스프링 컨테이너가 필요한 의존성을 생성하고 객체를 관리
객체가 필요로 하는 다른 객체를 직접 생성하는 것이 아니라, 외부에서 해당 객체를 주입하여 사용하는 것
- @Autowired - 타입으로 주입 (없으면 이름으로)
- @Inject - 타입으로 주입 (없으면 이름으로)
- @Resource - 이름으로 주입 (없으면 타입으로)
클래스의 인스턴스를 하나만 생성하도록 보장하는 디자인 패턴
- 어디서든 동일한 인스턴스 접근 가능, 자원의 낭비 방지
- 설정값, 로깅, 데이터베이스 연결 등 전역적으로 사용되는 객체에 많이 사용
public class AppConfig {
private static AppConfig instance;
private AppConfig() {} // private 생성자로 외부에서 인스턴스 생성 방지
public static AppConfig getInstance() {
// 인스턴스가 없을 때만
if (instance == null) {
// 생성
instance = new AppConfig();
}
return instance;
}
}
객체 생성을 캡슐화하여 객체를 생성하는 방식을 유연하게 만드는 디자인 패턴
- 인터페이스를 통해 객체를 요청하고, 팩토리는 요청에 맞는 객체를 생성하여 반환
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle.");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing a square.");
}
}
// 팩토리 패턴을 이용해 Shape 인터페이스 구현
// createShape("(타입명)")을 통해 원하는 객체로 생성 후 반환
class ShapeFactory {
public Shape createShape(String type) {
if (type.equals("circle")) {
return new Circle();
} else if (type.equals("square")) {
return new Square();
} else {
throw new IllegalArgumentException("Invalid shape type: " + type);
}
}
}
복잡한 객체의 생성 과정을 캡슐화하여 객체를 조립하는 방식을 제공하는 디자인 패턴
- 객체의 생성과 속성 설정을 분리하여 가독성을 높이고, 다양한 옵션을 설정할 수 있게 함
- 복잡한 생성자 대체, 코드의 가독성 높이기, 유지 보수를 용이하게 함
class Car {
private String brand;
private String model;
private String color;
private int year;
private Car(Builder builder) {
this.brand = builder.brand;
this.model = builder.model;
this.color = builder.color;
this.year = builder.year;
}
// Getter 메서드들...
// Builder 클래스 정의
static class Builder {
private String brand;
private String model;
private String color;
private int year;
public Builder brand(String brand) {
this.brand = brand;
return this;
}
public Builder model(String model) {
this.model = model;
return this;
}
public Builder color(String color) {
this.color = color;
return this;
}
public Builder year(int year) {
this.year = year;
return this;
}
public Car build() {
return new Car(this);
}
}
}
public class Main {
public static void main(String[] args) {
// 빌더 패턴으로 Car 객체 생성
Car car = new Car.Builder()
.brand("Toyota")
.model("Corolla")
.color("Blue")
.year(2022)
.build();
// 생성된 Car 객체의 정보 출력
System.out.println(car.getBrand());
System.out.println(car.getModel());
System.out.println(car.getColor());
System.out.println(car.getYear());
}
}
다른 객체에 대한 대리자 역할을 하는 객체를 제공하여 접근을 제어하는 디자인 패턴
- 원래 객체에 대한 접근을 제어하거나 보조 작업을 수행하고, 필요한 경우에만 원래 객체를 생성
: display() 메서드를 호출할 때, 실제로 이미지를 로드하는 것이 아니라 프록시를 통해 이미지를 로드하여 필요한 경우에만 RealImage를 생성하고 display() 메서드를 호출
interface Image {
void display();
}
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}
@Override
public void display() {
System.out.println("Displaying " + filename);
}
}
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
잘 읽었습니다. 좋은 정보 감사드립니다.