Spring/Spring

23-03-23 Spring

모건이삼촌 2023. 3. 23. 18:20

※ 복습

강력한 4가지 특징 중 2가지를 배움

Spring web을 하게 되었을 때 컨트롤러 서비스 래퍼 등 사전에 배워야 할 것들을 배우고 잇음.

 

※ 수업

AspectJ 포인트 컷 표현식을 화용한 포인트 컷

JDK 정규식보다 많이 사용되며

AspectJExpressionPointcut클래스를 제공,

aspectjrt.jar, aspectjweaver.jar 두 라이브러리 파일이 필요함.

 

라이브러리 추가

https://mvnrepository.com/artifact/org.aspectj/aspectjrt/1.9.19

https://mvnrepository.com/artifact/org.aspectj/aspectjweaver/1.9.19

 

예제) aop3

package aop.aop3;

import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.aop.framework.ProxyFactory;

public class AspectJMain {
	public static void main(String[] args) {
		First first = new First();
		Second second = new Second();
		
		first.one();
		first.two();
		second.one();
		second.two();
		
		System.out.println("==================");
		
		AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
		advisor.setAdvice(new SimpleAdv());
		// AspectJ식 표현식을 사용하게됨
		advisor.setExpression("execution(* one(..))");
		
		ProxyFactory pf = new ProxyFactory();
		pf.addAdvisor(advisor);
		pf.setTarget(first);
		
		First first2 = (First)pf.getProxy();
		
		pf = new ProxyFactory();
		pf.addAdvisor(advisor);
		pf.setTarget(second);
		Second second2 = (Second)pf.getProxy();
		
		
		first2.one();
		first2.two();
		second2.one();
		second2.two();
		
	}
}

실행 결과

First.one()
First.two()
Second.one()
Second.two()
==================

전처리
First.one()
후처리
First.two()
전처리
Second.one()
후처리
Second.two()

==================

위 예제에서 execution("execution(* one(..))")은 AspectJ식 표현식이다. (가장 많이 활용할 예정)

 *은 반환타입

그 옆은 메서드 명

.. 은 파라미터 갯수제한이 없다는 뜻이다.

 

※ 선언적 AOP 설정

 

* bean을 등록하기 위한 설정 2가지

xml을 통한 방법

컴포넌트 스캔을 써서 탐색을 시킴

 

선언적 AOP라는것은 xml에 정의한다는 뜻 (위와 목적이 비슷)

전역설정이다.

어플리케이션 설정에서 어드바이스 적용 프록시를 생성하고 이를 타겟빈에 주입할 수 있는 서비스를 제공

 

 - ProxyFactoryBean을 사용 :  스프링 애플리케이션 컨텍스트를 선언적으로 선언하여 빈 정의를 기반으로 aop프록시를 생성한다

 - Spring aop 네임스페이스 : aop 네임스페이스를 이용하여 애스펙트 및 di요구사항을 간단히 정의, aop네임스페이스도 내부적으로 프록시팩토리빈을 사용한다

- @AspectJ Annotation : @AspectJ방식의 어노테이션을 사용하여 클래스 내에서 aop설정이 가능하다.

 

1. ProxtFactoryBean 사용

 - 익명의 빈을 사용, 어플리케이션이 어드바이스 적용 대상이 아닌 ㅅ빈에 실수로 접근하는것을 막을 수 있다 (캡슐화)

 

1-1 AOP 프록시를 생성하기 위한 ProxyFactoryBean 사용

 - IoC컨테이너를 사용한다면 그리고 사용해야한다면 AOP FactoryBean중 하나를 사용하기 원할것이다

   Spring AOP 프록시를 생성하는 기본 방법은 org.srpringframework.aop.framework.ProxyFactoryBean을 사용하는 것

이것은 적용할 pointcut과 advice의 완벽한 제어능력을 부여한다.

proxtInterfaces는 사용안함

interceptorNames는 가장 중요, 순서를 의미함

 

예제)

package aop.aop4;

public class MyDependency {
	public void hello() {
		System.out.println("hello");
	}
	public void bye() {
		System.out.println("bye");
	}
}

package aop.aop4;

import lombok.Setter;

public class MyBean {
	@Setter
	private MyDependency dependency;
	
	public void run() {
		dependency.hello();
		dependency.bye();
	}
}

package aop.aop4;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println(method.getName() + "에 대해 before()");
	}
	
}
package aop.aop4;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyMain {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("aop4.xml");
		MyBean myBean = (MyBean)ctx.getBean("myBean");
		MyBean myBean1 = (MyBean)ctx.getBean("myBean1");
		MyBean myBean2 = (MyBean)ctx.getBean("myBean2");
		System.out.println("=============== target ===============");
		myBean.run();
		System.out.println("=============== advice 적용 ===============");
		myBean1.run();
		System.out.println("=============== advisor 적용 ===============");
		myBean2.run();
		
		ctx.close();
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<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 class="aop.aop4.MyDependency" id="myDependency" />
	
	<bean class="aop.aop4.MyBean" id="myBean">
		<property name="dependency" ref="myDependency"/>
	</bean>
	
	<bean class="aop.aop4.MyBean" id="myBean1">
		<property name="dependency" ref="proxy1"/>
	</bean>
	
	<bean class="aop.aop4.MyBean" id="myBean2">
		<property name="dependency" ref="proxy2"/>
	</bean>
	
	<!-- advice -->
	<bean class="aop.aop4.MyAdvice" id="myAdvice" />
	
	<!--  advisor -->
	<bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="myAdvisor">
		<!-- advice -->
		<property name="advice" ref="myAdvice"></property>
		<!-- pointcut -->
		<property name="pointcut">
			<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
				<property name="expression" value="execution(* hello*(..))" />
			</bean>
		</property>
	</bean>
	
	<!-- proxy 생성 target타입으로 칼같이 적용됨  -->
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxy1">
		<property name="interceptorNames">
			<list>
				<value>myAdvice</value>
			</list>
		</property>
		<!-- target 설정 -->
		<property name="target" ref="myDependency" />
	</bean>
	<!-- advisor에 대한 proxy 생성 -->
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxy2">
		<property name="interceptorNames">
			<list>
				<value>myAdvisor</value>
			</list>
		</property>
		<!-- target 설정 -->
		<property name="target" ref="myDependency" />
	</bean>
</beans>

실행결과

=============== target ===============
hello
bye
=============== advice 적용 ===============
hello에 대해 before()
hello
bye에 대해 before()
bye
=============== advisor 적용 ===============
hello에 대해 before()
hello
bye

=========================================

 

예제2) smallMart

package aop.small3;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SmallMartApp {
	public static void main(String[] args) throws Exception {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("small3.xml");
		SmallMart mart = (SmallMart)ctx.getBean("smallMart");
		
		mart.getProduct("츄르");
		mart.getProduct2("사료");
		
		System.out.println("===============");
		
		SmallMart mart1 = (SmallMart)ctx.getBean("smallMart1");
		mart1.getProduct("츄르");
		mart1.getProduct2("사료");
		
		System.out.println("===============");
		SmallMart mart2 = (SmallMart)ctx.getBean("smallMart2");
		mart2.getProduct("캣타워");
		mart2.getProduct2("사료");
		
		ctx.close();
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<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 class="aop.small3.SmallMartImpl" id="smallMart" />
	
	<bean class="aop.small3.BeforeLoggingAdv" id="advice" />
	<bean class="aop.small3.AfterLoggingAdv" id="advice2" />
	
<!-- 	<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor" id="pointcutAdvisor">
		<property name="advice" ref="advice" />
		<property name="expression" value="execution(* *2(..))" />
	</bean> -->
	
	<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcut" id="pc">
		<property name="expression" value="execution(* *2(..))"></property>
	</bean>
	
	<bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="advisor">
		<property name="advice" ref="advice" />
		<property name="pointcut" ref="pc" />
	</bean>
	
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="smallMart1">
		<property name="interceptorNames">
			<list>
				<value>advice</value>
			</list>
		</property>
		<property name="target" ref="smallMart"></property>
	</bean>
	
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="smallMart2">
		<property name="interceptorNames">
			<list>
				<value>pointcutAdvisor</value>
				<value>advice2</value>
			</list>
		</property>
		<property name="target" ref="smallMart"></property>
	</bean>
</beans>

 

*read

에제)byte기반 outputStream

package aop.small3;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class ReaderTest {
	public static void main(String[] args) throws IOException {
    		// ascii code 입력(아스키로 해석함)
		byte[] bytes = {65, 66, 67, 68, 97, 98, 99, 48, 49, 50};
		ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
		BufferedInputStream bis = new BufferedInputStream(bais);
		
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("abcd.txt"), 5);
		
		int i = 0;
		byte[] readUnit = new byte[5];
		i = bis.read(readUnit);
		bos.write(readUnit);
		i = bis.read(readUnit);
		bos.write(readUnit);
		
		
		// read는 1byte 씩 읽음 / -1는 더이상 읽을것이 없을 때 출력
		// 인덱스를 몇개 읽었는지 출력
//		i = bis.read(readUnit);
		
		// 몇번 인덱스부터, 몇개까지 읽는다
//		i = bis.read(readUnit, 1, 2);
		
		System.out.println(Arrays.toString(readUnit));
		System.out.println(i);

		// close 사용하는게 좋다.
//		bos.flush();
		bos.close();
	}
}

 

보조스트림 사용시 Buffered가 붙은 애들을 적절히 사용해주면 편하게 사용할 수 있다.

 

※ AOP namespace

 

1. aop 네임스페이스 사용

 - beans태그 내에 aop 네임스페이스를 선언해야 한다.

 

예제)

package aop.aop5;

public class MyDependency {
	public void hello(int intValue) {
		System.out.println("hello : " + intValue);
	}
	public void bye() {
		System.out.println("bye");
	}
}

package aop.aop5;

import lombok.Setter;

public class MyBean {
	@Setter
	private MyDependency dependency;
	
	public void run() {
		dependency.hello(5500);
		dependency.hello(4500);
		dependency.bye();
	}
}

package aop.aop5;

import org.aspectj.lang.JoinPoint;

public class MyAdvice {
	public void simple(JoinPoint joinPoint, int intValue) {
    	// intValue값이 5000 이상일때 advice 실행
		if(intValue > 5000) {
			System.out.println("advice 적용 :: " + joinPoint.getSignature().getName() + " : " + intValue);
		}
	}
}

package aop.aop5;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyMain {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("aop5.xml");
		MyBean myBean = (MyBean)ctx.getBean("myBean");
		myBean.run();
		
		ctx.close();
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<bean class="aop.aop5.MyDependency" id="myDependency" />
	<bean class="aop.aop5.MyBean" p:dependency-ref="myDependency" id="myBean" />
	<bean class="aop.aop5.MyAdvice" id="myAdvice" />
	<aop:config>
		<aop:aspect ref="myAdvice">
			<aop:pointcut expression="execution(* hello(..)) and args(intValue)" id="pc"/>
			<aop:before method="simple" pointcut-ref="pc"/>
			<aop:after-returning method="simple" pointcut-ref="pc"/>
		</aop:aspect>
	</aop:config>

</beans>

 

'Spring > Spring' 카테고리의 다른 글

23-04-27 Spring (Spring Web Security)  (0) 2023.04.27
23-03-29 Spring  (0) 2023.03.30
23-03-22 Spring  (0) 2023.03.22
23-03-21 Spring 비밀글  (0) 2023.03.21
23-03-17 Spring  (0) 2023.03.17