-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[4주차] 정건우 박지현 홍수진 #2
Comments
1. 의존과 DI를 통한 의존처리DI는 'Dependency Injection"의 약자로 의존성 주입이라고 합니다. 그렇다면 의존이란 무엇일까요? 간단한 코드로 의존을 설명할 수 있습니다.
위 코드는 Car 클래스가 Engine 클래스에 강하게 결합되어 있습니다. 따라서 의존이란, 변경에 따른 영향이 전파되는 관계를 의미합니다.
위의 코드에서 Car 클래스는 이제 Engine 인터페이스에 의존하고, 이렇게 하면 Car 클래스는 특정 Engine 구현체에 강하게 결합되지 않으며, 2. 객체 조립기main 메소드에서 의존 대상 객체를 생성하고 주입하는 방법이 나쁘지는 않습니다. 위에서 사용한 코드에서 객체 조립기를 활용하여 코드를 확장해보았습니다.
Engine 인터페이스 및 구현 클래스는 Engine 인터페이스와 두 가지 구현체(GasolineEngine 및 ElectricEngine)를 정의합니다. Car 클래스는 Engine 인터페이스를 의존성으로 받아서 사용합니다. 이를 통해 Car 클래스는 특정 엔진 구현체에 의존하지 않습니다. CarAssembler 클래스는 Car 객체를 조립하고 필요한 Engine 객체를 생성합니다. assembleCar 메서드는 주어진 엔진 타입에 따라 적절한 Engine 구현체를 생성하고, 이를 Car 객체에 주입합니다. Main 클래스에서는 CarAssembler를 사용하여 Car 객체를 생성합니다. 엔진 타입을 문자열로 전달하여 다양한 조합의 Car 객체를 쉽게 생성할 수 있습니다. 이렇게 DI와 객체 조립기를 사용하면 코드의 유연성과 재사용성을 크게 향상시킬 수 있습니다. 또한, 객체 생성과 의존성 주입 로직을 분리함으로써 코드의 가독성과 유지보수성을 높일 수 있습니다. 3. 스프링의 DI 설정스프링은 앞서 구현한 객체 조립기와 유사한 기능을 제공합니다.
DI 방식 1 : 생성자 주입 방식
DI 방식 2 : 세터 주입 방식
뭐가 더 낫나?일반적으로는 생성자 주입 방식 이 더 권장됩니다. 4. @configuration 설정 클래스의 @bean 설정과 싱글톤스프링 컨테이너가 생성한 빈은 싱글톤 객체입니다. 스프링 컨테이너는 @bean 이 붙은 메소드에 대해 단 1개의 객체만을 생성합니다.
@bean 애노테이션이 붙은 메소드는 기본적으로 싱글톤 스코프를 가집니다.
실행결과를 보면 carWithGasolineEngine1과 carWithGasolineEngine2는 동일한 인스턴스임을 확인할 수 있습니다. @Autowired ?스프링 컨테이너는 설정 클래스에서 사용한 @Autowired에 대해 자동 주입 처리를 해줍니다. 간단한 예시 코드를 살펴봅시다.
|
Chapter 6. 빈 라이프사이클과 범위1. 컨테이너 초기화와 종료// 1. 컨테이너 초기화
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppContext.class);
// 2. 컨테이너에서 빈 객체를 구해서 사용
Greeter g = ctx.getBeen("greeter", Greeter.class);
String msg = g.greet("스프링");
System.out.println(msg);
// 3. 컨테이너 종료
ctx.close();
2. 스프링 빈 객체의 라이프사이클스프링 컨테이너는 빈 객체의 라이프사이클을 관리한다. 빈 객체의 초기화와 소멸 : 스프링 인터페이스public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
void destroy() throws Exception;
} 스프링에서 두 인터페이스에 이 메서드를 정의하고 있다면?
- 채팅 클라이언트 : 초기화 과정에서 서버와의 연결을 생성하고, 소멸 과정에서 끊는 작업을 수행한다. 빈 객체의 초기화와 소멸 : 커스텀 메서드만약 InitializingBean, DisposableBean 인터페이스를 구현할 수 없거나 사용하고 싶지 않을 때는 어떻게 해야할까? -> @bean 태그에서 initMethod 속성과 destroyMethod 속성을 사용해서 초기화 메서드와 소멸 메서드의 이름을 지정하면 된다! // Client2 클래스를 빈으로 사용하는 경우
@Bean(initMethod = "connect", destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
return client;
} 그럼 initMethod 속성을 사용하는 대신 빈 설정 메서드에서 직접 초기화를 해도 될까? // 설정 코드에서 초기화 메서드를 직접 실행한 경우
@Bean(destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
client.connect();
return client;
} ! 주의해야할 점 !" 초기화 메서드가 두 번 호출되지 않도록 해야한다. " @Bean
public Client client() {
Client client = new Client();
client.setHost("host");
client.afterPropertiesSet();
return client;
}
3. 빈 객체의 생성과 관리 범위싱글톤한 식별자에 대해 한 개의 객체만 존재하는 빈의 범위를 말한다. Client client1 = ctx.getBean("client", Client.class);
Client client2 = ctx.getBean("client", Client.class);
// client1 == client2 -> true @scope특정 빈을 프로토타입 범위로 지정하려면 이 애노테이션을 사용해야 한다. (생략)
.
.
@Bean
@Scope("prototype")
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
Client client1 = ctx.getBean("client", Client.class);
Client client2 = ctx.getBean("client", Client.class);
// client1 != client2 -> true 한계
Chapter 7. AOP 프로그래밍1. AOP를 구현하기 위한 build.gradledependencies {
(생략)
.
.
implementation 'org.springframework:spring-context:5.3.9' // 버전은 필요에 따라 조정
implementation 'org.aspectj:aspectjweaver:1.9.6' // 버전은 필요에 따라 조정
.
.
} 스프링이 AOP를 구현할 때 사용하는 모듈이다.
2. 프록시 (proxy)기존 코드를 수정하지 않고 코드 중복도 피할 수 있는 방법이다.
3. AOP (Aspect Oriented Programming)여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 재사용성을 높여주는 프로그래밍 기법이다. -> 분리를 통해, 핵심 기능을 구현한 코드의 수정 없이 공통 기능을 추가할 수 있게 한다.
- 클래스 로딩 시점에 바이트 코드에 공통 기능을 삽입 - **런타임에 프록시 객체를 생성해서 공통 기능을 삽입** 프록시 기반의 AOP
AOP 주요 용어
Advice의 종류스프링은 프록시를 이용해서 메서드 호출 시점에 Aspect를 적용하기 때문에 구현 가능한 Advice가 여러 개 존재한다.
4. 스프링 AOP 구현
(생략)
.
.
@Aspect
public class ExeTimeAspect {
@Pointcut("execution(public * chap07..*(..))")
private void publicTarget() {
}
@Around("publicTarget()")
public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.nanoTime();
try {
Object result = joinPoint.proceed();
return result;
} finally {
long finish = System.nanoTime();
.
.
(생략)
.
.
}
}
}
@EnableAspect@aspect 애노테이션을 붙인 클래스를 공통 기능으로 적용하기 위해 설정 클래스에 추가해야 하는 애노테이션이다. 5. 프록시 생성 방식스프링은 AOP를 위한 프록시 객체를 생성할 때 실제 생성할 빈 객체가 인터페이스를 상속하면 인터페이스를 이용해서 프록시를 생성한다. // 수정 전
Calculator cal = ctx.getBean("calculator", Calculator.class);
// 수정 후
RecCalculator cal = ctx.getBean("calculator", RecCalculator.class);
// 자바 설정 파일
(생략)
.
.
@Bean
public Calculator calculator() {
return new RecCalculator();
}
.
. getBean() 메서드에 Calculator 타입 대신에 RecCalculator 타입을 사용하도록 수정한 이후에 메인 클래스를 실행했다고 하자. 과연 정상 실행될까? ->
그럼 빈 객체가 인터페이스를 상속할 때 인터페이스가 아닌 클래스를 이용해서 프록시를 생성할 수 있을까? @EnableAspectJAutoProxy@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppCtx {
.
.
}
execution 명시자 표현식excution 명시자는 Aspect를 적용할 메서드를 지정할 때 사용된다. 기본형식 :
Advice 적용 순서
@orderimport org.springframework.core.annotation.Order;
@Aspect
@Order(1)
public class ExeTimeAspect {
...
}
@Aspect
@Order(2)
public class CacheAspect {
...
}
@around의 Pointcut 설정과 @pointcut 재사용@around 애노테이션 역시 execution 명시자를 직접 지정할 수 있다. @Aspect
public class CacheAspect {
@Around("execution(public*chap07..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
} @Aspect
public class ExeTimeAspect {
@Pointcut("execution(public*chap07..*(..))")
private void publicTarget() {
...
}
@Around("publicTarget()")
public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
} 만약, 이 상황에서 CacheAspect 클래스에서 ExeTimeAspect 클래스에 위치한 publicTarget() 메서드의 Pointcut을 사용하고 싶다면? (두 클래스는 같은 패키지에 위치한다고 하자.) @Aspect
public class CacheAspect {
@Around("ExeTimeAspect.publicTarget()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
}
|
제 4장 - 의존 자동 주입직접 주입 : 설정 클래스에서 의존 대상을 생성자나 메서드를 이용해서 주입
1. @Autowired를 이용한 의존 자동 주입자동주입기능을 사용하면 @bean 메서드에서 의존을 주입하지 않아도(의존 객체를 직접 명시하지 않아도) 의존 객체가 주입됨!! 사용 방법 : 의존을 주입할 대상에 @Autowired 애노테이션을 붙이기만 하면 됨1) 필드에 붙이기필드에 @Autowired애노테이션이 붙어 있으면 스프링이 해당 타입의 빈 객체를 찾아서 필드에 할당한다 2)세터 메서드에 붙이기클래스의 세터메서드에 @Autowired를 붙이면 다른 설정클래스에서 세터 메서드를 호출하지 않아도 정상동작이 된다 정리 : @Autowired 애노테이션을 필드나 세터 메서드에 붙이면 스프링은 타입이 일치하는 빈 객체를 찾아서 주입한다.
만약 일치하는 빈이 없는 경우에는??익셉션이 발생하면서 제대로 실행되지 않는다. 콘솔에는 에러메시지가 출력됨 -> 'ㅇㅇ'빈을 생성하는데 에러가 발생했다, 'ㅇㅇㅇ'필드에 대한 의존을 충족하지 않는다, 'ㅇㅇㅇ' 타입의 빈이 없다 라는 내용이 나온다. 주입 대상에 일치하는 빈이 두 개 이상이면??이 경우에도 스프링은 자동 주입에 실패하고 익셉션을 발생시킴 2. @qualifier 애노테이션을 이용한 의존 객체 선택위의 경우 처럼 자동 주입 가능한 빈이 두 개 이상일때 (이 애노테이션은 두 위치에서 사용 가능하다)
setMemberPrinter()메서드에 @Autowired 애노테이션을 붙였으므로 MemberPrinter타입의 빈을 자동 주입한다. @Autowired 애노테이션을 필드와 메서드에 모두 적용할 수 있으므로 @qualifier 애노테이션도 필드와 메서드에 적용할 수 있다. 빈 이름과 기본 한정자빈 설정에 @qualifier 애노테이션이 없으면 빈의 이름을 한정자로 지정한다. 빈이름 ----------@Qualifier--------한정자 3. 상위/하위 타입 관계와 자동 주입상속관계일 경우에는 빈의 타입을 변경해도 에러가 발생한다 이를 해결할 수 있는 두 가지 방법
4. @Autowired 애노테이션의 필수 여부
이렇게 하면 매칭되는 빈이 없어도 익셉션이 발생하지 않으며 자동 주입을 수행하지않는다.
1번과 3번의 차이는 5. 자동 주입과 명시적 의존 주입 간의 관계설정 클래스에서 세터 메서드를 통해 의존을 주입해도 해당 세터 메서드에 @Autowired 애노테이션이 붙어 있으면 자동 주입을 통해 일치하는 빈을 주입한다. 제 5장 - 컴포넌트 스캔컴포넌트 스캔이란? 1. @component 애노테이션으로 스캔 대상 지정클래스에 붙여야함 빈 이름 설정애노테이션에 값을 주지 않았다면 클래스 이름의 첫 글자를 소문자로 바꾼 이름을 빈 이름으로 사용한다 값을 주면 그 값을 빈 이름으로 사용한다.
2. @componentscan 애노테이션으로 스캔 설정@component 애노테이션을 붙인 클래스를 스캔에서 스프링 빈으로 등록하려면 설정 클래스에 @componentscan 애노테이션을 적용해야한다. @componentscan(basePackages = {"클래스가 있는 패키지 이름"}) 3. 스캔 대상에서 제외하거나 포함하기excludeFilters 속성을 사용하면 스캔할 때 특정 대상을 자동 등록 대상에서 제외할 수 있다.
해석 -> spring으로 시작하고 Dao로 끝나는 정규표현식을 지정했으므로 spring.MemberDao 클래스를 컴포넌트 스캔 대상에서 제외한다. 2)특정 애노테이션을 붙인 타입을 컴포넌트 대상에서 제외할 수도 있다.
해석->FilterTypeANNOTATION을 사용하면 애노테이션을 붙인 클래스를 스캔대상에서 제외함 3)특정 타입이나 그 하위 타입을 컴포넌트 스캔 대상에서 제외하려면 ASSIGNALBLE_TYPE을 FilterType으로 사용한다
@component 뿐만아니라 4. 컴포넌트 스캔에 따른 충돌 처리컴포넌트 스캔 기능을 사용해서 자동으로 빈을 등록할 때는 충돌에 주의해야 한다. 빈 이름 충돌서로 다른 패키지에 동일한 이름의 클래스가 존재하고 두 클래스에 모두 @component 애노테이션을 붙이면 익셉션이 발생함 수동 등록한 빈과 충돌스캔할 때 사용하는 빈 이름과 수동 등록한 빈 이름이 같은 경우 수동 등록한 빈이 우선이다. 즉 수동 등록한 빈 하나만 존재한다고 볼 |
3장. 스프링 DI1. 의존과 DI를 통한 의존처리DI는 'Dependency Injection"의 약자로 의존성 주입이라고 합니다. 그렇다면 의존이란 무엇일까요? 간단한 코드로 의존을 설명할 수 있습니다.
위 코드는 Car 클래스가 Engine 클래스에 강하게 결합되어 있습니다. 따라서 의존이란, 변경에 따른 영향이 전파되는 관계를 의미합니다.
위의 코드에서 Car 클래스는 이제 Engine 인터페이스에 의존하고, 이렇게 하면 Car 클래스는 특정 Engine 구현체에 강하게 결합되지 않으며, 2. 객체 조립기main 메소드에서 의존 대상 객체를 생성하고 주입하는 방법이 나쁘지는 않습니다. 위에서 사용한 코드에서 객체 조립기를 활용하여 코드를 확장해보았습니다.
Engine 인터페이스 및 구현 클래스는 Engine 인터페이스와 두 가지 구현체(GasolineEngine 및 ElectricEngine)를 정의합니다. Car 클래스는 Engine 인터페이스를 의존성으로 받아서 사용합니다. 이를 통해 Car 클래스는 특정 엔진 구현체에 의존하지 않습니다. CarAssembler 클래스는 Car 객체를 조립하고 필요한 Engine 객체를 생성합니다. assembleCar 메서드는 주어진 엔진 타입에 따라 적절한 Engine 구현체를 생성하고, 이를 Car 객체에 주입합니다. Main 클래스에서는 CarAssembler를 사용하여 Car 객체를 생성합니다. 엔진 타입을 문자열로 전달하여 다양한 조합의 Car 객체를 쉽게 생성할 수 있습니다. 이렇게 DI와 객체 조립기를 사용하면 코드의 유연성과 재사용성을 크게 향상시킬 수 있습니다. 또한, 객체 생성과 의존성 주입 로직을 분리함으로써 코드의 가독성과 유지보수성을 높일 수 있습니다. 3. 스프링의 DI 설정스프링은 앞서 구현한 객체 조립기와 유사한 기능을 제공합니다.
DI 방식 1 : 생성자 주입 방식
DI 방식 2 : 세터 주입 방식
뭐가 더 낫나?일반적으로는 생성자 주입 방식 이 더 권장됩니다. 4. @configuration 설정 클래스의 @bean 설정과 싱글톤스프링 컨테이너가 생성한 빈은 싱글톤 객체입니다. 스프링 컨테이너는 @bean 이 붙은 메소드에 대해 단 1개의 객체만을 생성합니다.
@bean 애노테이션이 붙은 메소드는 기본적으로 싱글톤 스코프를 가집니다.
실행결과를 보면 carWithGasolineEngine1과 carWithGasolineEngine2는 동일한 인스턴스임을 확인할 수 있습니다. @Autowired ?스프링 컨테이너는 설정 클래스에서 사용한 @Autowired에 대해 자동 주입 처리를 해줍니다. 간단한 예시 코드를 살펴봅시다.
4장. 의존 자동 주입자동 주입이 아닌 의존주입 방법: @Bean
public ChangePasswordService changePwdSvc(){
ChangePasswordService pwdSvc = new ChangePasswordService();
psdSvc.setMemberDao(memberDao()); //의존 주입
return pwdSvc;
} 설정 클래스에서 의존 대상을 생성자나 메서드를 이용해서 주입 1. @Autowired를 이용한 의존 자동 주입자동주입기능을 사용하면 @bean 메서드에서 의존을 주입하지 않아도(의존 객체를 직접 명시하지 않아도) 의존 객체가 주입됨!! 사용 방법 : 의존을 주입할 대상에 @Autowired 애노테이션을 붙이기만 하면 됨1) 필드에 붙이기필드에 @Autowired애노테이션이 붙어 있으면 스프링이 해당 타입의 빈 객체를 찾아서 필드에 할당한다 2)세터 메서드에 붙이기빈 객체의 메서드에 @Autowired 애노테이션을 붙이면 스프링은 해당 메서드를 호출한다. 이때 메서드 파라미터 타입에 해당하는 빈 객체를 찾아 인자로 주입한다. 예시를 보자. @Configuration
public class AppCtx{
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public ChangePasswordService changePwdSvc(){
ChangePasswordService pwdSvc =
new ChangePasswordService();
return pwdSvc
}
@Bean
public MemberPrinter memberPrinter(){
return new MemverPrinter();
}
>
@Bean
public MemberInfoPrinter infoPrinter(){
MemberInfoPrinter infoPrinter =
new MemberInfoPrinter();
return infoPrinter;
}
}
public class ChangePasswordService{
//필드타입 -> MemberDao이므로 일치하는 타입을 가진 memberDao 빈이 주입됨
@Autowired
private MemberDao memberDao;
--생략
public class MemberInfoPrinter{
private MemberDao memDao;
private MemberPrinter printer;
public void printMemberInfo(String email){
--생략
}
//파라미터타입 -> MemberDao이므로 일치하는 타입을 가진 memberDao 빈이 주입됨
@Autowired
public void setMemberDao(MemberDao memberDao){
this.memDao = memberDao;
}
//파라미터타입 -> MemberPrinter이므로 일치하는 타입을 가진 memberPrinter 빈이 주입됨
@Autowired
public void setPrinter(MemeberPrinter printer){
this.printer = printer;
}
} 정리 : @Autowired 애노테이션을 필드나 세터 메서드에 붙이면 스프링은 타입이 일치하는 빈 객체를 찾아서 주입한다. 만약 일치하는 빈이 없는 경우에는??익셉션이 발생하면서 제대로 실행되지 않는다. 주입 대상에 일치하는 빈이 두 개 이상이면??이 경우에도 스프링은 자동 주입에 실패하고 익셉션을 발생시킴 2. @qualifier 애노테이션을 이용한 의존 객체 선택위의 경우 처럼 자동 주입 가능한 빈이 두 개 이상일때 (이 애노테이션은 두 위치에서 사용 가능하다)
@Bean
@Qualifier("printer") <- 이부분
public MemberPrinter memberPrinter1(){
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2(){
return new MemberPrinter();
}
@Autowired
@Qualifier("printer") <- 이부분
public void setMemberPrint(MemberPrinter printer){
this.printer = printer;
} 동작과정:
빈 이름과 기본 한정자빈 설정에 @qualifier 애노테이션이 없으면 빈의 이름을 한정자로 지정한다. 빈이름 ----------@Qualifier--------한정자 3. 상위/하위 타입 관계와 자동 주입상속관계일 경우에는 빈의 타입을 변경해도 에러가 발생한다 이를 해결할 수 있는 두 가지 방법
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2(){
return new MemberSummaryPrinter();
}
1.
@Autowired
@Qualifier("summaryPrinter") //애노테이션 붙이기
public void setMemberPrinter(MemberPrinter printer){
this.printer = printer;
}
2.
@Autowired
//파라미터 타입 변경
public void setMemberPrinter(MemberSummaryPrinter printer){
this.printer = printer;
} 4. @Autowired 애노테이션의 필수 여부
@Autowired(required = false)
public void 블라블라.... 이렇게 하면 매칭되는 빈이 없어도 익셉션이 발생하지 않으며 자동 주입을 수행하지않는다.
@Autowired
public void setDateFormatter(Optional</DateTimeFormatter>formatterOpt){
if(formatterOpt.isPresent()){
this.dateTimeFormatter = formatterOpt.get();
} else{
this.dateTimeFormatter = null;
}
}
@Autowired
public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter){
this.dateTimeFormatter = dateTimeFormatter;
}
1번과 3번의 차이는 5. 자동 주입과 명시적 의존 주입 간의 관계설정 클래스에서 세터 메서드를 통해 의존을 주입해도 따라서 @Autowired 애노테이션을 사용했다면 설정 클래스에서 객체를 주입하기보다는 스프링이 제공하는 자동 주입 기능을 사용하는게 낫다!! 5장. 컴포넌트 스캔컴포넌트 스캔이란? 스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능 1. @component 애노테이션으로 스캔 대상 지정클래스에 붙여야함 빈 이름 설정애노테이션에 값을 주지 않았다면 클래스 이름의 첫 글자를 소문자로 바꾼 이름을 빈 이름으로 사용한다 값을 주면 그 값을 빈 이름으로 사용한다. @Component
public class MemberDao{
블라블라,.,.
}
@Component("listPrinter")
public class MemberInfoPrinter{
블라블라,.,.
} 2. @componentscan 애노테이션으로 스캔 설정@component 애노테이션을 붙인 클래스를 스캔에서 스프링 빈으로 등록하려면 @componentscan(basePackages = {"클래스가 있는 패키지 이름"}) -> 스캔 대상 패키지 목록을 지정하는 것 , 해당 패키지와 그 하위 패키지에 속한 클래스를 스캔 대상으로 설정하는 것이다.
3. 스캔 대상에서 제외하거나 포함하기excludeFilters 속성을 사용하면 스캔할 때 특정 대상을 자동 등록 대상에서 제외할 수 있다. 1) 정규표현식을 사용해서 제외 대상을 지정@ComponentScan(basePackages = {"spring"},
excludeFilters = @Fiter(type = FilterType.REGEX,pattern = "spring\\..*Dao")) @fiter 애노테이션의 type 속성값으로 FilterType.REGEX가 주어졌다 이는 정규표현식을 사용해서 제외대상을 지정하는것을 의미함. 2)AspectJ 패턴을 사용해서 대상을 지정@ComponentScan(backPackages = {"spring"},
excludeFilteers = @Filteer(type = FilterType.ASPECTJ, pattern
= "spring.*Dao")) spring 패키지의 Dao로 끝나는 클래스를 컴포넌트 스캔 대상에서 제외한다 3)특정 애노테이션을 붙인 타입을 컴포넌트 대상에서 제외@ComponentScan(basePackages = {"spring","spring2"},
excludeFilters = @Fiter(type = FilterType.ANNOTATION, classes = {NoProdeuct.class, ManualBean.class })) FilterTypeANNOTATION을 사용하면 애노테이션을 붙인 클래스를 스캔대상에서 제외함 4)특정 타입이나 그 하위 타입을 컴포넌트 스캔 대상에서 제외하려면 ASSIGNALBLE_TYPE을 FilterType으로 사용한다@ComponentScan(basePackages = {"spring"},
excludeFilters = @Fiter(type = FilterType.ASSIGNALBLE_TYPE, classes = MemberDao.class )) 설정할 필터가 두개 이상이면 @componentscan의 excludeFilters 속성에 배열의 사용해서 @filter 목록을 전달하면된다@ComponentScan(basePackages = ({"spring"},
excludeFilters = {
@Fiter(type = FilterType.ANNOTATION, classes = ManualBean.class),
@Fiter(type = FilterType.REGEX,pattern = "spring\\..*") }) 컴포넌트 스캔 대상은 @component이 붙은 클래스 뿐만아니라 이런식으로 @controller가 붙은 클래스에서 @controller 애노테이션을 누르게되면 위에 @component가 사용이 되는걸 보아 4. 컴포넌트 스캔에 따른 충돌 처리컴포넌트 스캔 기능을 사용해서 자동으로 빈을 등록할 때는 충돌에 주의해야 한다. 빈 이름 충돌서로 다른 패키지에 동일한 이름의 클래스가 존재하고 두 클래스에 모두 @component 애노테이션을 붙이면 익셉션이 발생함 수동 등록한 빈과 충돌스캔할 때 사용하는 빈 이름과 수동 등록한 빈 이름이 같은 경우 수동 등록한 빈이 우선이다. 즉, 수동 등록한 빈 하나만 존재한다고 볼 수 있다. 다른이름을 사용한다면. 스캔을 통한 빈1 , 수동 등록한 빈2 모두 존재한다. 같은 타입의 빈이 두개가 생성되므로 자동 주입하는 코드는 @qualifier 애노테이션을 사용해서 알맞은 빈을 선택해야한다. 6장. 빈 라이프사이클과 범위1. 컨테이너 초기화와 종료// 1. 컨테이너 초기화
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppContext.class);
// 2. 컨테이너에서 빈 객체를 구해서 사용
Greeter g = ctx.getBeen("greeter", Greeter.class);
String msg = g.greet("스프링");
System.out.println(msg);
// 3. 컨테이너 종료
ctx.close();
2. 스프링 빈 객체의 라이프사이클스프링 컨테이너는 빈 객체의 라이프사이클을 관리한다. 빈 객체의 초기화와 소멸 : 스프링 인터페이스public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
void destroy() throws Exception;
} 스프링에서 두 인터페이스에 이 메서드를 정의하고 있다면?
- 채팅 클라이언트 : 초기화 과정에서 서버와의 연결을 생성하고, 소멸 과정에서 끊는 작업을 수행한다. 빈 객체의 초기화와 소멸 : 커스텀 메서드만약 InitializingBean, DisposableBean 인터페이스를 구현할 수 없거나 사용하고 싶지 않을 때는 어떻게 해야할까? -> @bean 태그에서 initMethod 속성과 destroyMethod 속성을 사용해서 초기화 메서드와 소멸 메서드의 이름을 지정하면 된다! // Client2 클래스를 빈으로 사용하는 경우
@Bean(initMethod = "connect", destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
return client;
} 그럼 initMethod 속성을 사용하는 대신 빈 설정 메서드에서 직접 초기화를 해도 될까? // 설정 코드에서 초기화 메서드를 직접 실행한 경우
@Bean(destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
client.connect();
return client;
} ! 주의해야할 점 !" 초기화 메서드가 두 번 호출되지 않도록 해야한다. " @Bean
public Client client() {
Client client = new Client();
client.setHost("host");
client.afterPropertiesSet();
return client;
}
3. 빈 객체의 생성과 관리 범위싱글톤한 식별자에 대해 한 개의 객체만 존재하는 빈의 범위를 말한다. Client client1 = ctx.getBean("client", Client.class);
Client client2 = ctx.getBean("client", Client.class);
// client1 == client2 -> true @scope특정 빈을 프로토타입 범위로 지정하려면 이 애노테이션을 사용해야 한다. (생략)
.
.
@Bean
@Scope("prototype")
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
Client client1 = ctx.getBean("client", Client.class);
Client client2 = ctx.getBean("client", Client.class);
// client1 != client2 -> true 한계
7장. AOP 프로그래밍1. AOP를 구현하기 위한 build.gradledependencies {
(생략)
.
.
implementation 'org.springframework:spring-context:5.3.9' // 버전은 필요에 따라 조정
implementation 'org.aspectj:aspectjweaver:1.9.6' // 버전은 필요에 따라 조정
.
.
} 스프링이 AOP를 구현할 때 사용하는 모듈이다.
2. 프록시 (proxy)기존 코드를 수정하지 않고 코드 중복도 피할 수 있는 방법이다.
3. AOP (Aspect Oriented Programming)여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 재사용성을 높여주는 프로그래밍 기법이다. -> 분리를 통해, 핵심 기능을 구현한 코드의 수정 없이 공통 기능을 추가할 수 있게 한다.
- 클래스 로딩 시점에 바이트 코드에 공통 기능을 삽입 - **런타임에 프록시 객체를 생성해서 공통 기능을 삽입** 프록시 기반의 AOP
AOP 주요 용어
Advice의 종류스프링은 프록시를 이용해서 메서드 호출 시점에 Aspect를 적용하기 때문에 구현 가능한 Advice가 여러 개 존재한다.
4. 스프링 AOP 구현
(생략)
.
.
@Aspect
public class ExeTimeAspect {
@Pointcut("execution(public * chap07..*(..))")
private void publicTarget() {
}
@Around("publicTarget()")
public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.nanoTime();
try {
Object result = joinPoint.proceed();
return result;
} finally {
long finish = System.nanoTime();
.
.
(생략)
.
.
}
}
}
@EnableAspect@aspect 애노테이션을 붙인 클래스를 공통 기능으로 적용하기 위해 설정 클래스에 추가해야 하는 애노테이션이다. 5. 프록시 생성 방식스프링은 AOP를 위한 프록시 객체를 생성할 때 실제 생성할 빈 객체가 인터페이스를 상속하면 인터페이스를 이용해서 프록시를 생성한다. // 수정 전
Calculator cal = ctx.getBean("calculator", Calculator.class);
// 수정 후
RecCalculator cal = ctx.getBean("calculator", RecCalculator.class);
// 자바 설정 파일
(생략)
.
.
@Bean
public Calculator calculator() {
return new RecCalculator();
}
.
. getBean() 메서드에 Calculator 타입 대신에 RecCalculator 타입을 사용하도록 수정한 이후에 메인 클래스를 실행했다고 하자. 과연 정상 실행될까? ->
그럼 빈 객체가 인터페이스를 상속할 때 인터페이스가 아닌 클래스를 이용해서 프록시를 생성할 수 있을까? @EnableAspectJAutoProxy@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppCtx {
.
.
}
execution 명시자 표현식excution 명시자는 Aspect를 적용할 메서드를 지정할 때 사용된다. 기본형식 :
Advice 적용 순서
@orderimport org.springframework.core.annotation.Order;
@Aspect
@Order(1)
public class ExeTimeAspect {
...
}
@Aspect
@Order(2)
public class CacheAspect {
...
}
@around의 Pointcut 설정과 @pointcut 재사용@around 애노테이션 역시 execution 명시자를 직접 지정할 수 있다. @Aspect
public class CacheAspect {
@Around("execution(public*chap07..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
} @Aspect
public class ExeTimeAspect {
@Pointcut("execution(public*chap07..*(..))")
private void publicTarget() {
...
}
@Around("publicTarget()")
public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
} 만약, 이 상황에서 CacheAspect 클래스에서 ExeTimeAspect 클래스에 위치한 publicTarget() 메서드의 Pointcut을 사용하고 싶다면? (두 클래스는 같은 패키지에 위치한다고 하자.) @Aspect
public class CacheAspect {
@Around("ExeTimeAspect.publicTarget()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
}
|
The text was updated successfully, but these errors were encountered: