spring5 정리

이봐요이상해씨·2021년 12월 12일
0

의존 전이

한 대상을 다운로드 할때 그 대상이 의존하고 있는 대상까지도 함께 다운로드함

Ch2

package ch02;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppContext {

	@Bean
	public Greeter greeter() {
		Greeter g = new Greeter();
		g.setFormat("%s, 안녕하세요!");
		return g;
	}
}
package ch02;

public class Greeter {

	private String format;

	public String greet(String guest){
		return String.format(format, guest);

	}

	public void setFormat(String format) {
		this.format = format;
	}
}
package ch02;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

	public static void main(String[] args) {

		//이 객체는 자바 설정에서 정보를 읽어옴
		AnnotationConfigApplicationContext ctx =
			//AppContext.class 생성자를 파라미터로 전달 -> 여기서 @Bean으로 설정한 정보를 읽어와
			//Gretter 객체를 생성하고 초기화한다
			new AnnotationConfigApplicationContext(AppContext.class);
		//getBean 메서드는 빈 객체를 검색할 떄 사용
		//첫번째 인자는 빈 객체 이름, 두 번쨰 인자는 검색할 빈 객체 타입
		Greeter g = ctx.getBean("greeter", Greeter.class);
		String msg = g.greet("스프링");
		System.out.println(msg);
		ctx.close();
	}
}

스프링은 객체 컨테이너

빈을 등록하는 객체를 생성하고 → 거기에 빈을 담음 → 해당 빈을 네이밍 태깅하여 →해당 빈을 불러옴

즉 위의 코드에서는 greeter의 이름의 빈이 스프링 컨테이너(ApplicationContext)에 들어있고, 이게 Greeter객체와 연결되어 있다.

package ch02;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main1 {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext ctx =
			new AnnotationConfigApplicationContext(AppContext.class);

		Greeter g1 = ctx.getBean("greeter", Greeter.class);
		Greeter g2 = ctx.getBean("greeter", Greeter.class);
		System.out.println("(g1 == g2) = " + (g1 == g2));
		ctx.close();
	}
}

싱글톤

위의 값은 true를 반환, 즉 스프링은 한개의 빈 객체만을 생성 → 싱글톤 객체

이 말은 @Bean 어노테이션에 대해 한개의 빈 객체만을 생성

@Configuration은 스프링 설정 클래스로 지정한다는 뜻

Ch3

스프링 DI

의존 : 한 클래스가 다른 클래스의 메서드를 실행할 때를 말함

생성자 주입 하는 이유 : 변경의 유연함

package ch03;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainForSpring {

	private static ApplicationContext ctx = null;

	public static void main(String[] args) throws IOException {
		ctx = new AnnotationConfigApplicationContext(Appctx.class);

		BufferedReader reader =
			new BufferedReader(new InputStreamReader(System.in));

		while (true) {
			System.out.println("명령어를 입력하세요");
			String command = reader.readLine();
			if (command.equalsIgnoreCase("exit")) {
				System.out.println("종료합니다");
				break;
			}
			if (command.startsWith("new")) {
				proccessNewCommand(command.split(" "));
				continue;
			} else if (command.startsWith("change")) {
				processChangeCommand(command.split(" "));
				continue;
			}
		}
		printHelp();
	}

	private static Assembler assembler = new Assembler();

	private static void proccessNewCommand(String[] arg){
		if (arg.length != 5) {
			printHelp();
			return;
		}
		MemberRegisterService regSvc = ctx.getBean("memberRegSvc", MemberRegisterService.class);
		//MemberRegisterService regSvc = assembler.getRegSvc();
		RegisterRequest req = new RegisterRequest();
		req.setEmail(arg[1]);
		req.setName(arg[2]);
		req.setPassword(arg[3]);
		req.setConfirmaPassword(arg[4]);

		if(!req.isPasswordEqualToConfirmPassword()) {
			System.out.println("암호가 일치하지 않습니다 \n");
			return;
		}
		try {
			regSvc.regist(req);
			System.out.println("register complete \n");
		} catch (DuplicateMemberException ex) {
			System.out.println("Email already exist");
		}
	}

	private static void processChangeCommand(String[] arg){
		if(arg.length != 4){
			printHelp();
			return;
		}
		// ChangePasswordService changePasswordService =
		// 	assembler.getPwdSvc();

		ChangePasswordService changePasswordService = ctx.getBean("changePwdSvc", ChangePasswordService.class);
		try {
			changePasswordService.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호를 변경했습니다");
		} catch (MemberNotFoundException ex) {
			System.out.println("존재하지 않은 이메일 \n");
		} catch (WrongIdPasswordException ex) {
			System.out.println("email,and password not match \n");
		}
	}

	private static void printHelp() {
		System.out.println();
		System.out.println("Wrong command check command below");
		System.out.println("how to use command");
		System.out.println("new : check email, password check");
		System.out.println("change : change email current change pass");
		System.out.println();
	}
}
package ch03;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Appctx {

	//각 @Bean 어노테이션마다 한개의 객체를 생성한다
	@Bean
	public MemberDao memberDao(){
		return new MemberDao();
	}

	//memberDao가 생성한 객체를 memberregisterservice 생성자를 통해 주입
	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService(memberDao());
	}

	//set메소드를 통해 의존 객체 주입
	@Bean
	public ChangePasswordService changePwdSvc(){
		ChangePasswordService pwdSvc = new ChangePasswordService();
		pwdSvc.setMemberDao(memberDao());
		return pwdSvc;
	}
}

위의 코드는 스프링컨테이너 객체를 선언하고 각 클래스를 빈으로 생성한 클래스를 불러와서 DI 한 코드이다

DI 방식

생성자 방식 : 빈 객체를 생성하는 시점에서 모든 의존 객체가 주입된다.

public MEmberListPrinter(MemberDao memberDao){
	this.memberDao = memberDao;
}

설정 메서드 방식 :세터 메서드 이름을 통해 어떤 의존 객체가주입되는지 알 수 있다.

public void setMemberDao(MemberDao memberdao) {
	this.memeberdao = memberDao;
}

@Autowired

: 자동주입기능ㅇ 위한 어노테이션 → 스프링 빈에 의존하는 다른 빈을 자동으로 주입하고 싶을 떄 사용

스프링은 @Configuration빈이 붙은 클래스를 내부적으로 스프링 빈으로 등록한다 그리고 @Autowired가 붙은 대상에 대해 알맞은 빈을 자동으로 주입한다.

2개이상의 설정파일 사용

@Autowired사용

@configuration
public class App1{
	@Bean
	mehtod1

	@Bean
	method2
}

@Configuation
public class App2{
	@Autowired
	method1 method1;

	@Autowired
	metthod2 method2;

	@Bean
	method3(method1){}

	@Bean
	method4(method20 {}
}

이렇게 @Autowired를 통해 이미 등록된 빈을 다른 설정파일에 의존성 자동주입을 통해 주입시킴

@Import 어노테이션을 사용

@Configuration
@Import(App2.class)
public class impport() {
	
	@Bean 
	method1(){}

	@Bean
	method2(){}
}

이렇게 @Import(설정 클래스)를 하게 되면 스프링 컨테이너 생성시 한번에 초기화 시킨다

Ch4

@Bean
@Qualifier("printer)
public printer printer() {};

//빈의 이름을 printer로 지정해서 등록

----------------------------------

@Autowired
@Qualifier("printer")
public void setMember(Printer printer) {};

//printer로 등록된 객체를 찾아서 자동 주입함 
@Autowired(required = false)
public void setDate(Datetime datetime) {}

-----------------------------------

@Autowired
public void setDate(Optional<Datetime> datetime){}

------------------------------------

@Autowired
public void setDate(@Nullable Datetime datetime){}

1.위와 같이 필수 주입 항목이 아닌 경우 required = false로 주게되면 자동주입을 하지 않는다.

2. 만약 null값이 들어오게되면 nullpointException이 발생함으로 이렇게 처리하면되는데, 자바 8부턴 
optional을 이용해서 널값이 들어오면 optional을 인자로 전달하고 값이 있으면 해당값전달

3. 마지막은 @nullable 어노테이션 지정, 있으면 해당값 없으면 Null을 전달
@Autowired requried 값 지정과의 차이점은, @Nullable로 지정하면 빈이 존재하지 않아도 메서드는 호출됨

Ch5

컴포넌트 스캔

컴포넌트 스캔은 스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능

@Component("list")
public class name() {}

//클래스도 빈으로 등록 할 수 있다

@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppCtx{}

//basepackage는 스캔 대상패키지 목록을 spring으로 지정한다 
//즉 com.xxxx 으로 지정한 (여기서는 spring으로 예시) 패키지를 기준으로 하위 클래스에서
//@Component가 붙은 클래스를 찾아 빈 객체로 등록 

스캔 대상에서 제외하거나 포함하기

@Configuration
@componentScan(basePackages = {com.xxx},
excludeFilters = @Filter(type = FilterType.REGEX, pattern ="com\\..*Dao"))
public class AppCtx{

	@Bean
	public method1 method() {}

	@Bean
	public MemberDao memberDao() {}

}

정규표현식을 사용해서 제외 대상을 설정한다
com으로 시작하고 dao로 끝나는 정규표현식 -> com.MemberDao class를 컴포넌트 스캔 대상에서 제외 

---------------------------하위 코드는 FilterType.ASPECTJ를 이용함----------------

@Configuration
@componentScan(basePackages = {com.xxx},
excludeFilters = @Filter(type = FilterType.ASPECTJ, pattern ="com.*Dao"))
public class AppCtx{

	@Bean
	public method1 method() {}

	@Bean
	public MemberDao memberDao() {}

}

위의 코드와 같게 동작 그런데 이 기능을 사용할려면 aspectjwever를 디펜던시 추가해야함 

----------------------------특정 어노테이션이 붙은 타입을 컴포넌트 대상에서 제외 가능 -------

@Retention(RUNTIME)
@Target(TYPE)
public @interface NoProduct {}

@Retention(RUNTIME)
@Target(TYPE)
public @interface ManualBean {}

어노테이션을 지정해 놓고, 이 어노테이션이 붙은 클래스는 컴포넌트 스캔에서 제외

@Configuration
@componentScan(basePackages = {com.xxx},
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = {NoProduct.class, ManualBean.class}))
public class AppCtx{

	@Bean
	public method1 method() {}

	@Bean
	public MemberDao memberDao() {}

}

@ManualBean
@Component
public class class1{}

위의 클래스는 제외된다.

------------------------------------------------------------------------

@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MemberDao.class))와 같이

ASSIGNABLE_TYPE을 통해 제외할 타입목록 설정을 할 수 있다.

만이 여러 필터를 적용시 배열로 작성

excludeFilters = {
			@Filter(type = FilterType),
			@Filter(type = FilterType)
})

Ch6

빈 라이프사이클과 범위

1. 컨테이너 초기화
AnnotationConfigApplicationContext ctx = 
	new AnnotationConfigApplicationContext(AppContext.class)

2. 컨테이너에서 빈 객체를 구해서 사용
Gretter g = ctx.getBean("greeter" , Greeter.class);
String msg = g.greet("스프링")
System.out.println(msg);

3.컨테이너 종료
ctx.close()

AnnotationConfigApplicationContext를 이용해서 컨텍스트 객체 생성 및 컨테이너 초기화

greeter 이라는 이름의 빈으로 컨테이너 안에 등록하고, 이 빈을 Greeter.class와 연결 시킴

빈 객체의 라이프사이클

객체 생성 → 의존 설정 → 초기화 → 소멸

  1. 가장먼저 빈 객체를 생성한다
  2. 의존설정을 한다(의존 자동 주입을 통해서)
  3. 초기화를 수행한다
  4. 메서드를 호출한다(지정된)
1.
public interface InitializingBean{
	void afterPropertiesSEt()throws Exception;
}

2.
public interface DisposalBean{
	void destory() throws Exception;
}
  1. InitializingBean 인터페이스를 구현하면 초기화 과정에서 빈 객체의 afterpropertiesSet()실행, → 이 메서드에서 초기화과정 메소드를 구현하면 된다

  2. DisposalBean인터페이스 구현시 destroy()메서드 실행 → 빈 소멸과정시 이 메소드를 구현

package ch06;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Client implements InitializingBean, DisposableBean {

	private String host;

	public void sethost(String host){
		this.host = host;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("Client, afterPorpertiseSet() 실행");
	}

	public void send() {
		System.out.println("Client,send() to" + host);
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("Client.destroy()실행");
	}
}
package ch06;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppCtx {

	@Bean
	public Client client() {
		Client client = new Client();
		client.sethost("host");
		return client;
	}
}
package ch06;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

public class Main {

	public static void main(String[] args) {
		AbstractApplicationContext ctx =
			new AnnotationConfigApplicationContext(AppCtx.class);

		Client client = ctx.getBean(Client.class);
		client.send();
		ctx.close();
	}

}
  1. 가장 먼저 afterProperties실행
  2. 객체 생성 마무리 뒤 초기화 메서드 실행
  3. 마지막에 destroy메서드 실행 → 이건 ctx.close()실행했기 때문에 호출됨

커스텀 메서드 추가

  1. 외부에서 제공받은 클래스를 스프링 빈 객체로 설정
  2. InitializingBean, DisposableBean인터페이스를 상속 받지 않고 구현할 수 있음
package ch06;

public class Client2 {
	private String host;

	public void setHost(String host) {
		this.host = host;
	}

	public void connect() {
		System.out.println("Client2.connect() 실행");
	}

	public void send(){
		System.out.println("Client2.send()to" + host);
	}

	public void close() {
		System.out.println("Client2.close() 실행");
	}
}
@Bean(initMethod = "connect", destroyMethod = "close")
	public Client2 client2(){
		Client2 client2 = new Client2();
		client2.setHost("host");
		return client2;
	}

Client2를 클래스 빈으로 사용시 초기화과정에서 connect 메소드를 사용하고, 소멸과정에서 close()를 실행해야 한다면

@Bean(initMethod = "connect", destroyMethod = "close")

와 같이 설정한다

주의!

afterPropertieseSet()은 빈 설정 메서드에서 호출된다. 그런데 스프링은 빈 객체 생성 이후 이 메서드를 실행함으로 이 메서드가 두번 반복적으로 호출되지 않도록 주의해야 한다

Client client1 = ctx.getBean("client", Client.class);
Client client2 = ctx.getBean("client", Client.class);
		if (client1 == client2)
			System.out.println("its same");
AbstractApplicationContext ctx =
			new AnnotationConfigApplicationContext(AppCtx.class);

스프링 컨테이는 빈 객체를 한개만 생성한다(AppCtx.class)

AppCtx.class의 객체 안에 여러개 설정해도 스프링은 기본 싱글톤 이기 때문이다.

빈 객체의 생성과 관리범위

빈의 범위 → 프로토타입의 경우 빈 객체를 구할때마다 매번 새로운 객체 리턴

특정 빈을 프로토타입으로 범위 지정하는 법

@Configuration
public class AppCtxWithPrototype {
	@Bean
	@Scope("prototype")
	public Client client(){
		Client client = new Client();
		client.sethost("host");
		return client;
	}
}

이렇게 설정파일을 프로토타입으로 범위를 지정하게되면 빈 객체마다 새로운 객체가 생성됨으로

같지 않음으로 출력

이렇게 서로 다른 범위를 지정해주면

서로 같지 않은 객체로 출력

둘다 싱글톤 타입이면

서로 같은 객체 반환으로 출력

Ch07

AOP 프로그래밍

				<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>

dependenc추가 → AOP 어노테이션 사용을 위한 목적

계산기 인터페이스 하나만들고

첫번째는 단순 계산, 두번째는 재귀 로 구현하는 클래스 2개를 구현

package ch07;

public interface Calculator {

	public long factorial(long  num);
}
package ch07;

public class ImpCalculator implements Calculator {
	@Override
	public long factorial(long num) {
		long result = 1;
		for (long i = 1; i <= num; i++){
			result +=1;
		}
		return result;
	}
}
package ch07;

public class RecCalculator implements Calculator {

	@Override
	public long factorial(long num) {
		if (num ==0)
			return 1;
		else
			return num * factorial(num - 1);
	}
}

두 구현 클래스의 계산 시간을 측정할클래스를 AOP로 구현 → 프록시 객체 이용

package ch07;

public class ExeTimeCal implements Calculator{

	//Calculator 주입받음 
	private Calculator delegate;

	//생성자로 필드에 할당
	public ExeTimeCal(Calculator delegate) {
		this.delegate = delegate;
	}

	@Override
	public long factorial(long num) {
		long start = System.nanoTime();
		long result = delegate.factorial(num);
		long end = System.nanoTime();
		System.out.printf("%s.factorial(%d) 실행시간 = %d\n",
			delegate.getClass().getSimpleName(),
			num, (end -start));
		return result;
	}
}

이 클래스는 생성자를 통해 Calculator 객체를 전달받아 delegate에 할당함

package ch07;

public class Main {

	public static void main(String[] args) {
		ExeTimeCal cal1 = new ExeTimeCal(new ImpCalculator());
		System.out.println(cal1.factorial(20));

		ExeTimeCal cal2 = new ExeTimeCal(new RecCalculator());
		System.out.println(cal2.factorial(20));
	}
}

객체 생성시 시간 측정 클래스안에 각각 Imp와 Rec로 객체를 생성함

→ 기존 코드 변경 없이 공통 코드를 빼냄

여기서 핵심 기능

	long result = delegate.factorial(num)

을 통해 핵심기능을 다른 객체에 위임함

이 코드를 통해 factorial로 계산하는 부분은 각각

ImpCalculator() 와 RecCalculator() 가 실행하게되고 ExeTimeCal안의 factorial 메소드는 시간만 측정하면 된다

AOP

여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 재사용성을 높여주는 프로그래밍 기법

기본개념 :

핵심 기능에 공통 기능을 삽입하는 것

이러한 방법엔 3가지가 있다

  1. 컴파일 시점에 코드에 공통 기능을 삽입

  2. 클래스 로딩 시점에 바이트 코드에 공통 기능 삽입

    → 위 2개는 AspectJ와 같은 AOP전용 도구필요

  1. 런타임에 프록시 객체를 생성해서 공통 기능을 삽입 → 스프링이 제공하는 방식

Client -> AOP프록시 → 공통기능 모듈 → 실제 객체

AOP에서 사용되는 용어

  • Advice : 언제 공통 관심 기능을 핵심 로직에 적용할 지를 정의
  • JoinPoint : Advice를 적용 가능한 지점을 의미. 메서드 호출, 필드값 변경 등이 여기에 해당(스프링은 메서드 호출에 관련된 것만 지원
  • Pointcut : Jointpoint의 부분 집합 실제 Advice가 적용되는 JointPoint 나타냄
  • Weaving : Advice 핵십 로직 코드에 적용하는 것
  • Aspect : 여러 객체에 공통으로 적용 되는 기능(트랜젝션, 보안등)

스프링에서 구현가능한 Advice종류

  • Before : 대상 객체 메서드 호출 전에 공통 기능 실행
  • After Returning : 대상 객체 메서드가 Exception 없이 실행된 이후 에 공통기능 실행
  • After Throwing : 대상 객체의 메서드를 실행하는 도중 Exception이 발생 한 경우에 실행
  • After : Exception 여부와 상관 없이 메서드 실행 후 실행
  • Around : 대상 객체의 메서드 실행 전 후 또는 Exception 발생 시점에 실행

구현하기

  1. Aspect로 사용할 클래스에 @Aspect 어노테이션 설정
  2. @Pointcut 어노테이션 공통 기능을 적용할 pointcut 정의
  3. 공통 기능을 구현한 메서드에 @Around 어노테이션 적용
package ch07;

import java.util.Arrays;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class ExeTimeAspect {

	@Pointcut("execution(public * ch07..*(..))")
	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();
			Signature sig = joinPoint.getSignature();
			System.out.printf("%s.%s(%s)실행시간 : %d ns\n",
				joinPoint.getTarget().getClass().getSimpleName(),
				sig.getName(), Arrays.toString(joinPoint.getArgs()),
				(finish - start));
		}
	}
}

@Pointcut : 공통 기능 적용할 대상 설정 → 여기서는 Ch07 패키지에 위치한 public 타입 메서드만 설정

@Around : Around Advice를 설정한다. 여기서는 publicTarget()로 해당 값을 지정하였는데,

publicTarget 메소드 안에 정의한 pointcut에 공통 기능을 저으이한다는 뜻이다

그런데 publicTarget()은 ch07과 그 하위 패키지에 public 메서드를 pointcut으로 정의함

따라서 여기서는

  1. ch07하위 패키지
  2. public 메소드
  3. @Around가 붙은 measure()메서드
  4. 이 메소드가 적용된다
 package ch07;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppCtx {

	@Bean
	public ExeTimeAspect exeTimeAspect(){
		return new ExeTimeAspect();
	}

	@Bean
	public Calculator calculator() {
		return new RecCalculator();
	}
}

@ EnableAspectJAutoProxy : @Aspect 어노테이션 기능 적용을 위해 선언

위에서

  1. @Around 어노테이션은 publicTarget에 설정함

  2. 이 메서드의 pointcut은 ch07하위 패키지에 있는 빈 객체 public 메서드를 설정함

  3. 아래 설정한 calculator 타입이 위의 2조건에 맞음으로 ExeTimespect 클래스에서 정의한

    meaure()가 아래 정의된 빈에 적용됨

    	@Bean
    	public Calculator calculator() {
    		return new RecCalculator();
    	}

빈 순환참조 발생(왜 생겼는지는 모르겠음)

책에서는 @Autowired 대신 @Bean으로 주입받음

@Autowired로 바꿔서 자동주입시킴(일반적으론 @Lazy로딩처리한다고한다)

package ch07;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainAspect {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx =
			new AnnotationConfigApplicationContext(AppCtx.class);

		Calculator cal = ctx.getBean("calculator", Calculator.class);
		long fiveFact = cal.factorial(5);
		System.out.println("cal.factorial(5) =" + fiveFact);
		System.out.println(cal.getClass().getName());
		ctx.close();
	}
}

Appctx에 정의된

	@Bean
	public ExeTimeAspect exeTimeAspect(){
		return new ExeTimeAspect();
	}

에서 스프링 빈 순환참조 에러 일어남 어디서 터지는지 모르겠음

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppCtx {

	@Bean
	public ExeTimeAspect exeTimeAspect(){
		return new ExeTimeAspect();
	}

	@Bean
	public Calculator calculator() {
		return new RecCalculator();
	}
}

proxyTargetClass = True

인터페이스가 아닌 자바 클래스를 상속받아 프록시를 생성함

@Pointcut("execution(public * ch07..*(..))")

Execution 명시자는 Advice를 적용할 메서드를 지정할 때 사용

기본형

excution(수식어 패턴? 리턴타입 패턴 클래스 이름패턴? 메서드 이름패턴(파라미터 패턴))

@Around의 Pointcut 설정과 @Pointcut 재사용

@Aspect
public class {

	@Around("execution(public * ))")
	public Object execute(ProceedingJoinPoint joinpoint)

}

@Pointcut 이 아닌 @Around 어노테이션에 execution 명시자 직접 지정 할 수 있다

같은 pointcut을 여러 advie가 사용시 재사용 할 수 있음

Asepct 클래스가 공통으로 사용할 pointcut 선언

public class CommonPointcut {

	@Pointcut("execution(public * ch07))")
	public void commonTarget(){

		}
}
@Aspect
public Class class1 {
	
@Around("CommonPointcut.commonTarget()")
public method

}

@Aspect
public Class class2 {
	
@Around("CommonPointcut.commonTarget()")
public method

}

위와 같이 선언

0개의 댓글