본문 바로가기

Spring

221125_Spring_국비_암호화/AOP

  • 동일한 타입을 가진 bean 객체가 2개가 있을때  : 스프링을 초기화하는 과정에서 Exception을 발생시킴
      → @Autowired의 injection의 대상이 1개여야하는데 2개이상의 빈이 존재해 주입할 때 사용할 객체를 선택 불가
      해결 : @Qualifier 사용
                → 사용할 의존객체를 선택할 수 있게 해줌
                     @Autowired적용한곳에 @Qualifier를 적용해주고 주입 할 id값을 (name="")로 적용시킴
  • @Autowired 적용시 의존 객체 찾는 순서
    동일 타입의 bean객체 검색 → 1개면 bean객체 사용
    타입이 같은 bean객체가 두개 이상이면서 @Qualifier이 없는 경우 → 이름이 같은 빈 객체 검색
    타입이 같은 bean객체가 두개 이상이면 @Qualifier로 지정한 bean객체를 찾음
    → 모두 해당되지 않으면 Exception 발생

암호화

알고리즘 종류

1. AES

  • 블록 암호 알고리즘
  • DES를 대체한 알고리즘으로 대칭키 알고리즘
  • 블록크기 128비트

2. SHA

  • HASH함수를 적용한 단방향 암호화 알고리즘으로 복호화 불가능
  • MD5보다 느리지만 강화됨

 

암호화를 사용하기 위한 설정
Maven Repository: Search/Browse/Explore (mvnrepository.com)

spring security core검색

본인에 버전에 맞는 것을 복사해서 pom.xml(35번째줄) <dependency>로 넣기

 

spring security web 검색

본인에 버전에 맞는 것을 복사해서 붙여넣기한곳 밑에 다시 붙여넣기

 

spring security config검색

 

 

com.korea.crypto패키지에

CryptoUtil.java생성

package com.korea.crypto;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class CryptoUtil {
   //MD5로 해시
   
   public static String md5(String msg) throws NoSuchAlgorithmException {
      MessageDigest md = MessageDigest.getInstance("MD5");
      md.update(msg.getBytes());
      return CryptoUtil.byteToHexString(md.digest());
      
      //Java에서 MD5, SHA를 이용한 알고리즘을 사용하려면 MessageDigest 클래스를 이용한다.
      //MessageDigest 클래스에는 update() 메소드가 있는데, 이 메소드를 호출할 때마다 객체 내에 저장된 digest값이 계속해서 갱신 된다.
      //최종적으로 digest() 메소드를 호출하면 그 값을 가져올 수 있다.
      //Hash 함수를 통과 하기 전 원본 데이터를 메시지(message)라고 부르고, 통과된 이후 데이터를 다이제스트(digest)라고 부른다.
   }
   
   //SHA-256으로 해시
   public static String sha256(String msg) throws NoSuchAlgorithmException {
      MessageDigest md = MessageDigest.getInstance("SHA-256");
      md.update(msg.getBytes());
      return CryptoUtil.byteToHexString(md.digest());
   }
   
   //바이트 배열을 HEX 문자열로 변환
   public static String byteToHexString(byte[] data) {
      StringBuilder sb = new StringBuilder();
      for(byte b : data) {
         sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
      }
      return sb.toString();
   }
   
   //AES 256으로 암호화
   public static String encryptAES256(String msg, String key) throws NoSuchAlgorithmException, 
                              InvalidKeySpecException, NoSuchPaddingException,
                              InvalidKeyException, InvalidParameterSpecException,
                              UnsupportedEncodingException, BadPaddingException,
                              IllegalBlockSizeException {
      SecureRandom random = new SecureRandom();
      byte bytes[] = new byte[20];
      random.nextBytes(bytes);
      byte[] saltBytes = bytes;
      
      //Password-Based Key Derivation function 2
      //지정된 암호 알고리즘의 SecretKeyFactory 오브젝트를 생성
      SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
      
      //70000번 해시하여(돌려서) 256bit 길이의 키를 만든다.
      //Iteration count => 해쉬의 횟수를 의미
      //Iteration count가 1000이면 1000번을 해쉬한다는 의미
      PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, 70000, 256);
      
      SecretKey secretKey = factory.generateSecret(spec);
      SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
      
      
      /* 
        Salt : 패스워드를 해쉬하기 전에 랜덤값을 추가하여 키 스페이스를 늘린다.
        salt는 암호문과 함께 저장된다. 복호화할 때는 암호화된 데이터로부터 salt를 분리해야 한다.
        salt는 매번 다르게 생성되며 동일한 문장에 대해서도 다른 값이 생성된다. 
      */
      
      //알고리즘 / 모드 / 패딩
      //CBC : Cipher Block chaining Mode
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      cipher.init(Cipher.ENCRYPT_MODE, secret);
      AlgorithmParameters params = cipher.getParameters();
      
      //Initial Vector(1단계 암호화 블록용), 복호화 : Decoding(암호화 하기전으로 되돌림) / 암호화 : Encoding
      byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
      
      byte[] encryptedTextBytes = cipher.doFinal(msg.getBytes("UTF-8"));
      
      byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
      System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
      System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
      System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
      
      return Base64.getEncoder().encodeToString(buffer);
   }
   
   public static String decryptAES256(String msg, String key) throws NoSuchPaddingException, NoSuchAlgorithmException,
                                          InvalidKeySpecException, InvalidAlgorithmParameterException,
                                          InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      ByteBuffer buffer = ByteBuffer.wrap(Base64.getDecoder().decode(msg));
      
      byte[] saltBytes = new byte[20];
      buffer.get(saltBytes, 0, saltBytes.length);
      byte[] ivBytes = new byte[cipher.getBlockSize()];
      buffer.get(ivBytes, 0, ivBytes.length);
      byte[] encryptedTextBytes = new byte[buffer.capacity() - saltBytes.length - ivBytes.length];
      buffer.get(encryptedTextBytes);
      
      SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
      PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, 70000, 256);
      
      SecretKey secretKey = factory.generateSecret(spec);
      SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
      
      cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));
      
      byte[] decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
      return new String(decryptedTextBytes);
   }
}

 

com.korea.myapp.cryptomain패키지에

CryptoTest.java생성

package com.korea.myapp.cryptomain;

import com.korea.crypto.CryptoUtil;

public class CryptoTest {
	
	public static void main(String[] args) throws Exception{
		String plainText = "Hello, World";
		String key ="secret key2";
		
		//md5와 sha-256은 단방향 암호화로 비밀번호를 암호화하거나 데이터 전송등에서 무결성을 체크하는데 사용
		//md5는 128bit로 서로 다른 값에 같은 해시가 발생하는 충돌이 확인되었고
		//빠르게 해시가 가능하므로 비밀번호를 만드는데 안전하지 않음
		//이제 sha-256 사용 권장
		
		System.out.println("MD5 :"+plainText+" - "+CryptoUtil.md5(plainText));
		System.out.println("SHA-256 :"+plainText+" - "+CryptoUtil.sha256(plainText));
		
		//-AES 256은 키가 256bit 즉 32bit문자열 이어야함
		//-salt를 사용하므로 동일한 값을 암호화 하더라도 암호된 값이 동일하지 않음
		//-결과값에는 salt와  iv값을 추가하여 Base64로 엔코딩해 반환
		
		String encrypted = CryptoUtil.encryptAES256("Hello, World", key);
		System.out.println("AES-256 : enc - "+ encrypted);
		System.out.println("AES-256 : dec - "+ CryptoUtil.decryptAES256(encrypted, key));
	}
}

 

↓결과

MD5 :Hello, World - 82bb413746aee42f89dea2b59614f9ef
SHA-256 :Hello, World - 03675ac53ff9cd1535ccc7dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5
AES-256 : enc - Yi97wxwk+Fj6g0VVQc3MUMq56ZZxX3+dsFk5nmj+OTsJT8mwcBA0Cwgy+Y9c71yBPd72sw==
AES-256 : dec - Hello, World

 

 

 

src/main/java패키지에

LoginController.java

package com.korea.myapp;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/login.do") //요청 경로
public class LoginController {
	
	public LoginController() {
		System.out.println("LoginController 빈 생성 Lee");
	}
	
	@Autowired
	BCryptPasswordEncoder pwEncoder;
	
	//salting과 Key Stretching을 구현한 해시 함수 중 가장 널리 사용 되는 것이  bcrypt
	//bcrpt는 처음부터 비밀번호를 단방향 암호화하기 위해 만들어진 해시 함수
	
	@RequestMapping(method = RequestMethod.GET)
	public String form() {
		return "/login/loginForm"; //  login/loginForm.jsp(뷰 페이지 이름)
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView loginproc(LoginDTO dto, HttpSession session){
		//ModelAndView : 컨트롤러 처리 결과 후 응답할 view와 view에 전달할 값을 저장 및 전달하는 클래스

		String id = dto.getId();
		String passwd = dto.getPasswd();
		String tel = dto.getTel();
		
		System.out.println("id : "+id);
		System.out.println("passwd : " + passwd);
		System.out.println("tel : " + tel);
		System.out.println("---------------------------------");
		System.out.println("id : "+id);
		System.out.println("passwd : " + pwEncoder.encode(passwd));
		System.out.println("tel : " + pwEncoder.encode(tel));
		
		//BcrptPasswordEncoder는 복호화가 되지 않으므로
		//로그인할때도 암화한 것을 비교해 로그인 하면 됨
		
		ModelAndView mav = new ModelAndView();
		
		if(id.equals("abc") && (passwd.equals("1234")) && (tel.equals("000")) ) {

			//request영역
			mav.addObject("r_id",id);
			mav.addObject("r_passwd",passwd);
			mav.addObject("r_tel",tel);
			
			//passwd를 encode로 암호화
			String encode_1 = pwEncoder.encode(passwd);
			String encode_2 = pwEncoder.encode(tel);
			
			mav.addObject("r_passwd2",encode_1);
			mav.addObject("r_tel2",encode_2);
			
			//session영역
			session.setAttribute("s_id", id);
			session.setAttribute("s_passwd", passwd);
			session.setAttribute("s_passwd2", encode_1);
			session.setAttribute("s_tel", tel);
			session.setAttribute("s_tel2", encode_2);
			
			mav.addObject("msg","로그인 성공");
			mav.setViewName("/login/loginProc");
			
		}else {
			mav.addObject("msg","<p>아이디와 패스워드가 일치하지 않습니다.</p>");
			mav.addObject("link","<a href='javascript:history.go(-1)'>다시시도</a>");
			
			mav.setViewName("/login/msgView");
			//msgView.jsp
		}
		
		return mav;
		
	}
}

 

BCryptPasswordEncoder

  • Spring Security 프레임워크에서 제공하는 클래스 → 비밀번호를 암호화(해시)하는데 사용
  • 단순히 1회 해시시키는것이 아니라 salt를 부여해 여러면 해싱하므로 안전하게 암호 관리 가능
  • BCrypt는 같은 비밀번호를 암호화하더라도 해시 값은 매번 다른 값이 도출됨
    → 사용자가 제출된 비밀번호와 암호화되어 저장된 비밀번호의 일치 여부를 확인하는 메서드 제공

 

 

LoginDTO.java생성

package com.korea.myapp;

public class LoginDTO {

	private String id;
	private String passwd;
	private String loginType;
	private String tel;

	public LoginDTO() {
		super();
	}

	public LoginDTO(String id, String passwd, String loginType) {
		super();
		this.id = id;
		this.passwd = passwd;
		this.loginType = loginType;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPasswd() {
		return passwd;
	}

	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}

	public String getLoginType() {
		return loginType;
	}

	public void setLoginType(String loginType) {
		this.loginType = loginType;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}

	@Override
	public String toString() {
		return "LoginDTO [id=" + id + ", passwd=" + passwd + ", loginType=" + loginType + ", tel=" + tel + "]";
	}

}

 

src/main/webapp/spring

spring_security.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:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-5.1.xsd">

<bean id="bcryptPasswordEncoder"
class ="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

</beans>

 

web.xml

<context-param>의 <param-value>에 /WEB-INF/spring/sping_security.xml 추가

한글을 사용하기 위해 filter추가

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml
					/WEB-INF/spring/spring_security.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

<!-- utf-8 encoding filter한글처리를 위한 필터 -->
<filter>
      <filter-name>encoding</filter-name>
      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
      <init-param>
         <param-name>encoding</param-name>
         <param-value>UTF-8</param-value>
      </init-param>
      <init-param>
         <param-name>forceEncoding</param-name>
         <param-value>true</param-value>
      </init-param>
   </filter>
   
   <filter-mapping>
      <filter-name>encoding</filter-name>
      <url-pattern>/*</url-pattern>
      </filter-mapping>
</web-app>

 

view폴더에서

loginForm.jsp생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원로그인</title>
</head>
<body>

</body>
<div>로그인</div>
<form action ="/login.do" method="post" name="login">
	<table>
		<tr>
			<th>아이디</th>
			<td><input type="text" name="id" value="" size="20"	></td>
		</tr>
		<tr>
			<th>비밀번호</th>
			<td><input type="password" name="passwd" value="" size="20"></td>
		</tr>
		<tr>
			<th>전화번호</th>
			<td><input type="text" name="tel" value="" size="20"	></td>
		</tr>
	</table>
	<div>
		<input type="submit" value="로그인">
	</div>
</form>
</html>

 

loginProc.jsp생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>longin/loginProc.jsp 로그인 성공</title>
</head>
<body>
1) jsp사용 결과<br>
<%=request.getAttribute("msg") %><br>

아이디 : <%=request.getAttribute("r_id") %><br>
비밀번호 : <%=request.getAttribute("r_passwd") %><br>
비밀번호2 : <%=request.getAttribute("r_passwd2") %><br>
전화번호 : <%=request.getAttribute("r_tel") %><br>
전화번호 : <%=request.getAttribute("r_tel2") %><br>
세션아이디 : <%=session.getAttribute("s_id") %><br>
세션 비밀번호 : <%=session.getAttribute("s_passwd") %><br>
세션 비밀번호2 : <%=session.getAttribute("s_passwd2") %><br>
세션 전화번호 : <%=session.getAttribute("s_tel") %><br>
세션 전화번호2 : <%=session.getAttribute("s_tel2") %><br>
<hr>
<hr size="5" color="#cccccc">
2) EL 사용 결과<br>
${msg }<br>
아이디 : ${r_id }<br>
비밀번호 : ${r_passwd }<br> 
비밀번호2 : ${r_passwd2 }<br>
전화번호 : ${r_tel }<br>
세션 아이디 : ${s_id }<br>
세션 비밀번호 : ${s_passwd }<br>
세션 비밀번호2 : ${s_passwd2 }<br>
세션 전화번호 : ${s_tel }<br>
세션 전화번호2 : ${s_tel2 }<br>


</body>
</html>

 

msgView.jsp생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login/msgView 로그인 실패</title>
</head>
<body>
<br><br><br>
<h1>
<%
//Script를 이용한 경우
//String msg = (String)request.getAttribute("msg");
//String link = (String)request.getAttribute("link");
//out.println(msg);
//out.println("<br><br>");
//out.pringln(link);
%>

${msg }<br><br>
${link }<br>
${link }<br>
</h1>
</body>
</html>

 

↓결과

url뒤에 login.do

 

loginProc.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>longin/loginProc.jsp 로그인 성공</title>
</head>
<body>
1) jsp사용 결과<br>
<%=request.getAttribute("msg") %><br>

아이디 : <%=request.getAttribute("r_id") %><br>
비밀번호 : <%=request.getAttribute("r_passwd") %><br>
비밀번호2 : <%=request.getAttribute("r_passwd2") %><br>
전화번호 : <%=request.getAttribute("r_tel") %><br>
전화번호 : <%=request.getAttribute("r_tel2") %><br>
세션아이디 : <%=session.getAttribute("s_id") %><br>
세션 비밀번호 : <%=session.getAttribute("s_passwd") %><br>
세션 비밀번호2 : <%=session.getAttribute("s_passwd2") %><br>
세션 전화번호 : <%=session.getAttribute("s_tel") %><br>
세션 전화번호2 : <%=session.getAttribute("s_tel2") %><br>
<hr>
<hr size="5" color="#cccccc">
2) EL 사용 결과<br>
${msg }<br>
아이디 : ${r_id }<br>
비밀번호 : ${r_passwd }<br> 
비밀번호2 : ${r_passwd2 }<br>
전화번호 : ${r_tel }<br>
세션 아이디 : ${s_id }<br>
세션 비밀번호 : ${s_passwd }<br>
세션 비밀번호2 : ${s_passwd2 }<br>
세션 전화번호 : ${s_tel }<br>
세션 전화번호2 : ${s_tel2 }<br>


</body>
</html>

 

msgView.jsp생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login/msgView 로그인 실패</title>
</head>
<body>
<br><br><br>
<h1>
<%
//Script를 이용한 경우
//String msg = (String)request.getAttribute("msg");
//String link = (String)request.getAttribute("link");
//out.println(msg);
//out.println("<br><br>");
//out.pringln(link);
%>

${msg }<br><br>
${link }<br>
${link }<br>
</h1>
</body>
</html>

 

↓결과

로그인 실패

 

로그인 성공

 


AOP(Aspect Oriented Programming)

  • 관점 지향 프로그래밍
  • 핵심적인 관점, 부가적인 관점으로 나누고 그 관점을 기준으로 모듈화
용어 의미
Aspect 흩어진 관심사를 모듈화 한것
Target Aspect를 적용하는 곳(클래스, 메서드 등)
Advice 실질적인 어떤일을 해야할 지에 대한것
실질적인 부가기능을 담은 구현체
Join Point Advice가 적용될 위치 혹은 끼어들 수 있는 시점
Point Cut JoinPoint의 상세한 스펙을 정의한 것
구체적으로 Advice가 실행될 시점을 정함

 

  • AOP를 적용하는 방법
    1. 컴파일 타임 적용
    2. 로드 타임 적용
    3. 런타임 적용방법(스프링 AOP가 주로 사용하는 방법)
        : Proxy Bean을 만들어 Proxy Bean이 Aspect코드를 추가해 동작하는 방법

 

src/main/java

aop_1패키지에

Boy.java생성

package aop_1;

public class Boy {
	public void runSomething() {
		System.out.println("Boy.java");
		
		try {
			System.out.println("컴퓨터");
		}catch(Exception e) {
			if(e.getMessage().equals("불")) {
				System.out.println("119");
			}
		}finally {
			System.out.println("잠");
		}
		System.out.println("집을 나섬");
	}
}

 

Girl.java생성

package aop_1;

public class Girl {

		public void runSomething() {
			System.out.println("Girl.java");
			
			try {
				System.out.println("요리");
			}catch(Exception e) {
				if(e.getMessage().equals("불")) {
					System.out.println("119");
				}
			}finally {
				System.out.println("잠");
			}
			System.out.println("집을 나섬");
		}

}

Start.java생성

package aop_1;

public class Start {
	
	public static void main(String[] args) {
		
	Boy romeo = new Boy();
	Girl juliet = new Girl();
	
	romeo.runSomething();
	System.out.println();
	juliet.runSomething();
	}
}

 

↓결과

Boy.java
컴퓨터
잠
집을 나섬

Girl.java
요리
잠
집을 나섬

 

 

aop_2패키지 생성

Person.java 인터페이스  생성

package aop_2;

public interface Person {
	void runSomething();
}

 

Boy.java생성

package aop_2;

public class Boy implements Person{
	
	@Override
	public void runSomething() {
		System.out.println("컴퓨터");
	}
}

 

Girl.java생성

package aop_2;

public class Girl implements Person {
	
	@Override
	public void runSomething() {
		System.out.println("요리");
	}
}

 

MyAspect.java생성

package aop_2;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {

	//runSomething()이 실행되기 전에
	@Before("execution(* runSomething())")
	public void before(JoinPoint joinpoint) {
		System.out.println("얼굴 인식 확인 : open");
	}
}

 

aop_2.xml(spring Bean configuration file)

<?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.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">


<!-- @AspectJ를 사용하기 위해 다음 코드를 Spring 설정에 추가
	@Aspect가 적용된 빈을 Aspect로 사용할 수 있게 한다 -->
<aop:aspectj-autoproxy/>

<bean id="myAspect" class="aop_2.MyAspect"></bean>
<bean id="boy" class="aop_2.Boy"></bean>
<bean id="girl" class="aop_2.Girl"></bean>

</beans>

적용되면 <bean>앞에 화살표가 표시됨

 

 

Start.java생성

package aop_2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Start {

	public static void main(String[] args) {
		
		ApplicationContext context = new ClassPathXmlApplicationContext("aop_2/aop_2.xml");
		
		Person romeo = context.getBean("boy", Person.class);
		Person juliet = context.getBean("girl", Person.class);
		
		romeo.runSomething();
		System.out.println();
		juliet.runSomething();
	}
}

 

 

pom.xml에 AspectJ뒤 추가

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>${org.aspectj-version}</version>
</dependency>

 

↓결과

얼굴 인식 확인 : open
컴퓨터

얼굴 인식 확인 : open
요리

 

 

'Spring' 카테고리의 다른 글

[Spring]Lambda 표현식  (0) 2023.06.05
221128_Spring_AOP2  (0) 2022.11.28
221124_Spring_국비_DI/DesignPattern/@Resource/@Autowired/@Inject  (0) 2022.11.24