• AOP 2020.05.20

https://engkimbs.tistory.com/746

 

[Spring] 스프링 AOP (Spring AOP) 총정리 : 개념, 프록시 기반 AOP, @AOP

| 스프링 AOP ( Aspect Oriented Programming ) AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다. 관점 지향은 쉽게 말해 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으..

engkimbs.tistory.com

 

OOP(자바의 기본방식 :  각체지향 ) 에서 Aspect 만 바뀌였다.

특정 한 타이밍에 어느 위치에 어떤 메소드를 실행 시킬 것인지에 대한 프로그래밍 기법

 

 Aspect: 기존 객체 지향 프로그램에서 모듈화 기법으로

추가된 중복 코드(공통 처리 부분)을 별도의 독립된 클래스(Aspect)로 만들어 놓은 것

 

AOP : 공통(공용), 공유 할 내용, 일종의 기법

 

핵심모듈 : 반드시 구현할 기능

예) 로그인 여부 확인(회원 수정, 삭제 등에 필요함)

 

위와 같은 기능을 할 코드들을 따로 클래스로 만들어준다.

이것을 공통 관심사 모듈(Aspect)이라고 한다.

 

공통 관심사 모듈

예) 로그인 처리부분, 보안, 공통으로 사용할 수 없는 코딩

-> 스프링에서는 Aspect는 Advice라고 한다. Angular에서는 서비스라고 한다.

 

AOP는 언제 불러다 사용할 것이고, 언제 실행 할 것인지가 중요하다.

이렇게 실행 위치를 지정해주는 것은 joinPoint, PointCut라고 한다.

 

JoinPoint :  실행 위치를 지정(실행 위치만 지정한다.)

예) before, after

 

PointCut : 어떤 메소드 앞, 뒤에서 실행을 지정

어느 메소드를 사용할 것인지도 같이 설정해준다.

ex) before에 startMethod 실행지정.

 

이러한 지정 법은 Weaving이라고 한다.

핵심클래스의 특정위치에 넣어주는 것

 

이러한 모든 것을 통틀어 Aspect라고 한다.

 

또한 Aspect와 Advice를 합쳐진 것을 보고 Advisior라고도 한다.


AOP를 실행 시키는 방법

 

1. 프록시 기반의 AOP지원(AOP객체를 생성해주는 클래스)

default(메소드 중심)->빈즈 클래스로 구성.

2. <aop:config>태그를 사용

3. AspectJ이용 (@Aspect Annotation을 이용하는 방법)

 

프로젝트 생성하기

맨 밑에 있는 mvc를 선택해도 되지만(Spring MVC Project),

자동으로 만들어주는 프로젝트이기 때문에 수정하기가 쉽지않다.

따라서, 수동으로 프로젝트를 설계하기 위해 위와 같은 프로젝트로 설정한다.

 

프로젝트 생성시 체크해볼 것

 


POM.xml 수정하기

 

AOP -> springFrame(스프링 프레임워크이 필요하고, 스프링-익스프레션, 스프링-빈즈 라는 라이브러리가 필요하다.)

AOP연습에서는 위와 같은 lib가 필요하다.

 

변경 전

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.dod</groupId>
	<artifactId>dko</artifactId>
	<name>fvdsafds</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>3.1.1.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>        
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

변경 후

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.hjs</groupId>
   <artifactId>springAop</artifactId>
   <name>SpringAop</name>
   <packaging>war</packaging>
   <version>1.0.0-BUILD-SNAPSHOT</version>
   <properties>
      <!-- Generic properties -->
      <java-version>1.6</java-version>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      
      <!-- Spring -->
      <org.springframework-version>4.2.5.RELEASE</org.springframework-version>
      
      
      
      <!-- Hibernate / JPA -->
      <hibernate.version>4.2.1.Final</hibernate.version>
      
      <!-- Logging -->
      <logback.version>1.0.13</logback.version>
      <slf4j.version>1.7.5</slf4j.version>
      
      <!-- Test -->
      <junit.version>4.11</junit.version>
      
      <org.aspectj-version>1.6.10</org.aspectj-version>
      <org.slf4j-version>1.6.6</org.slf4j-version>
   </properties>
   <dependencies>
      
      <!-- Spring -->
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>${org.springframework-version}</version>
         <exclusions>
            <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusion>
               <groupId>commons-logging</groupId>
               <artifactId>commons-logging</artifactId>
             </exclusion>
         </exclusions>
      </dependency>
      
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-webmvc</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-expression</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-beans</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
   </dependencies>
</project>

샘플 스프링 메이븐으로 만들어보기

 

샘플 스프링 메이븐으로 만들게 되면 pom.xml의 내용이 필요한 내용만 들어가게 된다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples</groupId>
  <artifactId>AOPSpring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>3.2.3.RELEASE</spring-framework.version>

		<!-- Hibernate / JPA -->
		<hibernate.version>4.2.1.Final</hibernate.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

		<!-- Test -->
		<junit.version>4.11</junit.version>

	</properties>
	
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		
		<!-- Test Artifacts -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

	</dependencies>	
</project>

https://blog.naver.com/hojysoo/221971341519

 

20200520 - 스프링 프로젝트 관점지향 프로그래밍 (AOP - Aspect Oriented Programming)

OOP에서 Aspect만 바뀌었다.​특정 한 타이밍에 어느 위치에 어떤 메서드를 실행시킬 것인지에 대한 프...

blog.naver.com

버전 정보를 수정해준다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples</groupId>
  <artifactId>AOPSpring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.2.5.RELEASE</spring-framework.version>

		<!-- Hibernate / JPA -->
		<hibernate.version>4.2.1.Final</hibernate.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

		<!-- Test -->
		<junit.version>4.11</junit.version>

	</properties>
	
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		
		<!-- Test Artifacts -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

	
	<!-- 1. 핵심 Class 빈즈 등록 -->
<bean id="testServiceImpl" class="sp.aop.TestServiceImpl" />

<!-- 2. Advice Class 빈즈 등록 -->
<bean id="beforeLog" class="sp.aop.BeforeLogAdvice" />

<!-- 3.PointCut 생성 -->
<bean id="" class="org.springframework.aop.support.JdkRegexpMethodPointcut" />

	</dependencies>	
</project>

 

package sp.aop;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice; // 이후라고하면 MethodAfterAdvice 구현받으면 된다.

//추가
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

//Advice : 모든 Class에 공통으로 사용할 기능( 소스코드 -> method 중심 )
//interface 대신(OOP 방식) 에 Advice Class 를 작성해서 구현(AOP 방식) -> Aspect

//실행 위치를 특정 Method 의 앞에서 실행 -> MethodBeforeAdvice 를 구현
public class BeforeLogAdvice implements MethodBeforeAdvice { //공통관심 모듈 클래스를 만든다.
	private Log log = LogFactory.getLog(getClass()); //Log 객체를 얻어오는 문장
	
	//1) Spring의 AOP(method 중심) -> 핵심 CLass의 Method
	//2) 생성된 객체를 배열로 받아온다.
	//3) target Class(핵심 Class의 객체를 얻어온다.)
	
	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		//TODO auto-generated method stub
		log.info(method.toString()+" Method : "+target+"에서 호출 전!");
	}//before() END

}//BeforeLogAdvice CLASS END

 

package sp.aop;
//모든 핵심 class 에서 공통으로 사용할 목적으로의 Method 작성, 인터페이스는 메소드 옆에 {} 지정하면 안된다.
public interface TestService {
    // 해당 메소드들은 public abstract void 와 같이 추상메소드로 작성된다.
	public void save(String msg);// 입력
	public void write(); //출력
}//TestService INTERFACE END

 

 

app.xml

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">


<!-- 1. 핵심 Class 빈즈 등록 -->
<bean id="testServiceImpl" class="sp.aop.TestServiceImpl" />

<!-- 2. Advice Class 빈즈 등록 -->
<bean id="beforeLog" class="sp.aop.BeforeLogAdvice" />


<!-- 3.PointCut 생성 -> 어느 위치에서 AOP Method 를 지정해서 실행
	value="접근 지정 반환명 package 명... Class 명 하위  package 명(..) 특정 Method명 0개 이상"
	        (*) 매개변수 한 개 표시, (*,*) 매개변수 2개 표시 -->
	        
<bean id="writePointcut"
 class="org.springframework.aop.support.JdkRegexpMethodPointcut">
	<property name="pattern" value=".*write.*" />
</bean>


<!-- 4. Advice + PointCut(Advisor) 설정 -->
<bean id="testAdvisor" 
class="org.springframework.aop.support.DefaultPointcutAdvisor">
	<property name="advice" ref="beforeLog" /> 
	<property name="pointcut" ref="writePointcut" />
</bean>


</beans>

package sp.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; // xml문서를 찾을 수 있게 하는 lib

public class ResultMain {

	public static void main(String[] args) {
		String path="sp/aop/app.xml";
		ApplicationContext context = new ClassPathXmlApplicationContext(path);
		
		//TestService service= (TestService)context.getBean("testServiceImpl");
		//원래는 위의 것이 일반적이지만, AOP 객체를 얻어오기 위해서는, 밑에처럼 AOP객체를 얻는다.
		
		//AOP객체를 생성 -> Advisor 작동 -> Advice + pointcut 실행
		TestService service = (TestService)context.getBean("testService");
		service.save("AOP 적용 연습");
		//before advice(before() 작동 실행) -> 실행상태에서 처리
		service.write();
		
	}//main()END

}//CLASS END

 

 

 

package sp.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class AfterLogAdvice implements AfterReturningAdvice {

	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		 System.out.println(method.toString()+"method:"+target+"에서 호출 후!");
	}

  /* @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
      
       * 1. 추가된 객체
       * 2.핵심클래스의 method명
       * 3.생성된 객체들
       * 4.targetClass의 객체
       
      System.out.println(method.toString()+"method:"+target+"에서 호출 후!");
   }*/

}

app.xml

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">


<!-- 1. 핵심 Class 빈즈 등록 -->
<bean id="testServiceImpl" class="sp.aop.TestServiceImpl" />

<!-- 2. Advice Class 빈즈 등록 -->
<bean id="beforeLog" class="sp.aop.BeforeLogAdvice" />
<bean id="AfterLog" class="sp.aop.AfterLogAdvice" />


<!-- 3.PointCut 생성 -> 어느 위치에서 AOP Method 를 지정해서 실행
	value="접근 지정 반환명 package 명... Class 명 하위  package 명(..) 특정 Method명 0개 이상"
	        (*) 매개변수 한 개 표시, (*,*) 매개변수 2개 표시 -->
	        
<bean id="writePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
	<property name="pattern" value=".*write.*" />
</bean>

<bean id="savePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
	<property name="pattern" value=".*save.*" />
</bean>


<!-- 4. Advice + PointCut(Advisor) 설정 -->
<bean id="testAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
	<property name="advice" ref="beforeLog" />
	<property name="pointcut" ref="writePointcut" />
</bean>

<!-- 4-1. Advice + PointCut(Advisor) 설정 -->
<bean id="testAfterAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
	<property name="advice" ref="AfterLog" />
	<property name="pointcut" ref="savePointcut" />
</bean>

<!-- 5. AOP를 적용(ProxyFactoryBean 객체를 생성) target(핵심 Class) -->
<bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="target" ref="testServiceImpl" />
	<property name="interceptorNames">
		<list>
			<value>testAdvisor</value>
			<value>testAfterAdvisor</value>
		</list>
	</property>
</bean>
<!-- ///////END AOP 환경설정 부분 -->

</beans>

+ Recent posts