// 설정정보를 엮어줄 Configuration 클래스를 생성한다.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
// 사용 예시
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
IoC 컨테이너의 가장 기초적인 역할을 오브젝트를 생성하고 이를 관리하는 것이다.
스프링 컨테이너가 관리하는 이런 오브젝트는 빈이라 부른다.
설정 메타 정보는 바로 이 빈을 어떻게 만들고 어떻게 동작하게 할 것인가에 관한 정보이다. ex. config.class
스프링 컨테이너는 자바 코드, XML, Groovy 등 다양한 형식의 설정 정보를 받아들일 수 있도록 유연하게 설계되어 있다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
}
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://
www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository"/>
</bean>
</beans>
컴파일 타임 적용
-> 컴파일 시점에 바이트 코드를 조작하여 AOP가 적용된 바이트 코드를 생성하는 방법.
로드 타임 적용
-> 순수하게 컴파일한 뒤, 클래스를 로딩하는 시점에 클래스 정보를 변경하는 방법
런타임 적용
-> 스프링 AOP가 주로 사용하는 방법. A라는 클래스 타입의 Bean을 만들 때 A 타입의 Proxy Bean을 만들어 Proxy Bean이 Aspect 코드를 추가하여 동작하는 방법.
// 타켓 메서드의 실행 시간을 측정해주는 로직 작성
@Component // AOP는 @Bean에서만 동작하기 때문에 Bean으로 등록 해준다.
@Aspect // AOP로 쓸거라는 의미
public class PerfAspect {
@Around("execution(* com.example..*.EventService.*(..))") // 적용범위
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
Object reVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - begin);
return reVal;
}
}
ex. Transactional 도 AOP의 예시
// Transaction를 Low level로 구현
try (
Connection conn = DriverManager.getConnection(
"jdbc:coco://127.0.0.1:5432/test", "coco", "password");
Statement statement = conn.createStatement();
) {
//start transaction block
conn.setAutoCommit(false); //default true
String SQL = "INSERT INTO Employees " +
"VALUES (101, 20, 'Rita', 'Tez')";
stmt.executeUpdate(SQL);
String SQL = "INSERTED INT Employees " +
"VALUES (107, 22, 'Kita', 'Tez')";
stmt.executeUpdate(SQL);
// end transaction block, commit changes
conn.commit();
// good practice to set it back to default true
conn.setAutoCommit(true);
} catch(SQLException e) {
System.out.println(e.getMessage());
conn.rollback();
}
@Transactional(readOnly = true)
Employees findById(Integer id);
// 순수한 POJO
public class User {
private int id;
private String name;
private String email;
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
}
public class ExampleListener implements MessageListener {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
}
catch (JMSException ex) {
throw new RuntimeException(ex);
}
}
else {
throw new IllegalArgumentException("Message must be of type TextMessage");
}
}
}
@Component
public class ExampleListener {
@JmsListener(destination = "myDestination")
public void processOrder(String message) {
System.out.println(message);
}
}
https://steady-coding.tistory.com/600
https://www.youtube.com/watch?v=Hm0w_9ngDpM
https://code-lab1.tistory.com/193
https://dev-coco.tistory.com/83
https://ch4njun.tistory.com/270
https://happyer16.tistory.com/entry/POJOplain-old-java-object%EB%9E%80
https://velog.io/@galaxy/Spring%EC%9D%98-%EA%B8%B0%EB%B3%B8-%ED%8A%B9%EC%A7%95-POJO
IoC가 무엇인가요?
IoC(Inversion of Control)이란 "제어의 역전"이란 의미로, 메서드나 객체의 호출작업을 개발자가 하는 것이 아닌, 외부에서 결정되는 것을 의미합니다. 즉 인스턴스의 생성부터 소멸까지를 IoC 컨테이너가 대신 관리해줍니다.이 과정에서 DI(의존성 주입)를 통해 IoC컨테이너에 주입시킵니다.
new Repository() 처럼 직접 생성하는게 아니라, 스프링이 직접 생성해주고 연결을 해줍니다.
스프링에서 AOP가 뭔가요?
AOP(Aspect Oriented Programming) 는 관점 지향 프로그래밍으로, 로직을 기준으로 중복된 코드들(공통 관심사항)을 뽑아서 Aspect로 모듈화하여 재사용하는 것입니다.
PSA가 뭔가요?
스프링 PSA는 "Portable Service Abstraction"의 약어로, 다양한 서비스 프로바이더들과의 통합을 편리하게 하기 위한 추상화 계층을 의미합니다. 스프링 PSA는 서로 다른 백엔드 시스템과의 통합을 위한 일관된 인터페이스를 제공하여 애플리케이션의 이식성을 높이고 유연성을 제공합니다.
PSA가 적용된 대표적인 곳은 JDBC, JPA, Transaction Manager 등이 존재합니다.
PSA에 어떤 서브프로젝트가 포함되어 있나요?
Spring JDBC: 데이터베이스와의 통합을 위한 추상화 계층을 제공합니다.
Spring JMS: 메시징 시스템과의 통합을 지원합니다.
Spring JPA: Java Persistence API를 지원하며 ORM 프레임워크와의 통합을 위한 추상화 계층을 제공합니다.
Spring Transactions: 트랜잭션 관리를 위한 표준 인터페이스와 추상화 계층을 제공합니다.
Spring Cache: 캐싱을 위한 추상화 계층을 제공하여 다양한 캐시 프로바이더와 통합합니다.
PSA의 장점과 단점은 무엇인가요?
장점
다양한 백엔드 시스템과의 통합이 용이하고 일관된 방법을 제공합니다.
개발자가 여러 시스템 간의 차이점을 다루는 복잡성을 줄여줍니다.
유연성과 이식성을 높여 애플리케이션의 유지보수와 확장성을 개선합니다.
단점
모든 백엔드 시스템과의 특정 기능을 모두 추상화하기는 어려울 수 있습니다.
일부 기능이나 설정이 백엔드 시스템마다 다르게 적용될 수 있습니다.
POJO란 무엇인가요?
스프링에서의 POJO는 "Plain Old Java Object"의 약어로, 특정 프레임워크나 라이브러리에 의존하지 않는 순수한 자바 객체를 말합니다. 스프링은 이러한 POJO들을 사용하여 애플리케이션을 구성하고 관리하는데 중점을 둡니다.
참고: 개발자는 스프링 POJO, IOC, AOP, PSA를 사용하여 어떻게 개발해야할까?
스프링은 개발자가 POJO 형태로 객체를 만들고 IOC와 AOP를 통해 의존성을 주입하며, PSA를 사용하여 이러한 POJO 객체들을 다양한 백엔드 서비스들과 통합하는 방식을 지향합니다.
스프링은 POJO를 사용하여 개발자가 일반적인 자바 객체를 만들도록 유도합니다.
POJO는 순수하게 비즈니스 로직에 집중할 수 있도록 하며, 스프링의 IOC를 통해 컨테이너에서 관리됩니다.
스프링의 IOC 컨테이너는 POJO 객체들을 생성하고, 객체 간의 의존성을 주입합니다.
개발자는 객체 간의 의존성을 설정하는 데 집중할 필요 없이, 컨테이너에 위임할 수 있습니다.
AOP는 POJO의 핵심 비즈니스 로직과는 별개로 공통 관심사를 분리하여 모듈화합니다.
개발자는 POJO에 공통 기능을 중복하지 않고도 적용할 수 있습니다.
PSA는 POJO 객체들을 다양한 백엔드 서비스와 통합하는 추상화 계층을 제공합니다.
스프링의 다양한 PSA 구현체를 사용하여 POJO 객체들이 다양한 백엔드 시스템과 상호작용할 수 있습니다.
스프링의 이러한 방식은 개발자에게 유연하고 효율적인 개발 환경을 제공하며, 모듈화와 재사용성을 높이고 높은 유지보수성을 확보할 수 있도록 돕습니다.