Spring AOP 측면 지향 프로그래밍의 원리와 방법을 설명합니다.

1. AOP 란?

AOP (Aspect Oriented Programming)는 다음을 의미합니다. Aspect Oriented Programming은 사전 컴파일 및 런타임 동적 에이전트 구현을 통해 소스 코드를 수정하지 않고 프로그램에 동적으로 기능을 추가하는 기술을 동적 에이전트로 이해할 수 있습니다. Spring 프레임 워크의 중요한 부분입니다. AOP를 사용하면 비즈니스 로직의 각 부분을 분리하고, 비즈니스 로직의 다양한 부분 간의 결합을 줄이고, 프로그램의 재사용 성을 개선하고, 동시에 개발 효율성을 높일 수 있습니다.

2. 봄 AOP

① Spring에서 AOP의 역할
선언적 트랜잭션을 제공하고 사용자가 측면을 사용자 정의 할 수 있도록합니다.

② AOP
Cross-cutting 의 기본 개념 : 응용 프로그램의 여러 모듈에 걸쳐있는 방법 또는 기능. 즉, 비즈니스 로직과는 아무런 관련이 없지만주의가 필요한 부분은 교차 초점입니다. 로그, 보안, 캐시, 트랜잭션 등 ...

  • 측면 : 교차 절단 문제가 모듈화 된 특수 개체. 일반적으로 진입 점 및 알림을 정의 할 수있는 클래스
  • Weaving : 측면을 다른 애플리케이션 유형 또는 개체에 연결하고 권장 개체를 만듭니다. 이는 컴파일 시간, 클래스로드 시간 및 런타임에 수행 될 수 있습니다. 다른 순수 Java AOP 프레임 워크와 마찬가지로 Spring은 런타임에 위빙을 완료합니다.
  • Advice (notification) : AOP가 특정 pointcut에서 수행하는 향상된 처리는 aspect에서 수행해야하는 작업이며, 클래스의 메소드이기도합니다.
  • 대상 (대상) : 알림 대상
  • AOP (Proxy) : AOP 프레임 워크에 의해 생성 된 객체이며 프록시는 대상 객체의 향상입니다. * Spring의 AOP 프록시는 JDK 동적 프록시 또는 CGLIB 프록시 일 수 있으며 전자는 인터페이스를 기반으로하고 후자는 서브 클래스를 기반으로합니다.
  • JointPoint (연결 지점) : 프로그램 실행 중 명확한 지점, 일반적으로 메서드 호출
  • Pointcut (pointcut) : 알림이있는 연결 지점, pointcut과 일치하는 실행 지점
    ③. Spring을 사용하여 Aop
    전제 조건 달성
    AOP weaving 사용, 종속성 패키지 가져 오기 필요
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.5</version>
</dependency>

AOP를 달성하는 세 가지 방법

방법 1 : Spring API를 통한 구현 [주로 Spring API 인터페이스 구현]

먼저 비즈니스 인터페이스 및 구현 클래스 작성

public interface UserService {
  public void add();
  public void delete();
  public void update();
  public void search();
}
public class UserServiceImpl implements UserService{
  public void add() {
    System.out.println("增加了一个用户");
  }

  public void delete() {
    System.out.println("删除了一个用户");
  }

  public void update() {
    System.out.println("更新了一个用户");
  }

  public void select() {
    System.out.println("查询了一个用户");
  }
}

그런 다음 향상된 클래스를 작성합니다. 두 가지가 있습니다 : 사전 강화 된 로그 및 사후 강화 된 AfterLog

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
  //method: 要执行的目标对象的方法
  //args: 参数
  //target: 目标对象
  public void before(Method method, Object[] args, Object target) throws Throwable {
    System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
  }
}
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
  //returnValue;返回值
  public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
  }
}

마지막으로 Spring 파일 (applicationContext.xml)에 등록하고 AOP cut-in을 구현하고 import 제약에주의

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

  <!--注册bean-->
  <bean id="userService" class="com.lf.service.UserServiceImpl"/>
  <bean id="log" class="com.lf.log.Log"/>
  <bean id="afterLog" class="com.lf.log.AfterLog"/>
  
  <!--方式一:使用原生Spring API接口 -->
  <!--配置aop:需要导入aop的约束-->
  <aop:config>
  <!--切入点:expression:表达式,execution(要执行的位置! * * * * *) -->
  <aop:pointcut id="pointcut" expression="execution(* com.lf.service.UserServiceImpl.*(..))"/>
  <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
  <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
  <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
  </aop:config>

</beans>

테스트 수행 :

import com.lf.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
  @Test
  public void test(){
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService userService1 = (UserService) context.getBean("userService");
  UserService userService = (UserService) context.getBean("userService");
  userService.add();
  }
}

작업 결과 :

com.lf.service.UserServiceImpl的add被执行了
增加了一个用户
执行了add方法,返回结果为:null

방법 2 : 사용자 정의 클래스가 AOP (주로 측면 정의)를 구현합니다.
대상 비즈니스 클래스는 변경되지 않고 유지되거나 첫 번째 메소드의 UserServiceImpl이 유지됩니다.

컷인 클래스 작성

public class DiyPointCut {
  public void before(){
    System.out.println("========方法执行前=========");
  }

  public void after(){
    System.out.println("========方法执行后=========");
  }
}

Spring에서 구성 (applicationContext.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
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd">

  <!--注册bean-->
  <bean id="userService" class="com.lf.service.UserServiceImpl"/>
  <bean id="log" class="com.lf.log.Log"/>
  <bean id="afterLog" class="com.lf.log.AfterLog"/>
  
  <!--方式二:自定义类-->
  <bean id="diy" class="com.lf.diy.DiyPointCut"/>

  <aop:config>
  <!--自定义切面, ref 要引用的类-->
  <aop:aspect ref="diy">
  <!--切入点-->
  <aop:pointcut id="point" expression="execution(* com.lf.service.UserServiceImpl.*(..))"/>
  <!--通知-->
  <aop:before method="before" pointcut-ref="point"/>
  <aop:after method="after" pointcut-ref="point"/>
  </aop:aspect>
  </aop:config>
</beans>

위의 MyTest.java에서 테스트하고 결과를 얻으십시오.

메서드가 실행되기 전=
사용자 추가
메서드가 실행 된 후=

방법 3 : 주석을 사용하여 [다목적] 주석을위한
고급 클래스 작성

package com.lf.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect //标注这个类是一个切面
public class AnnotationPointCut {

  @Before("execution(* com.lf.service.UserServiceImpl.*(..))")
  public void before(){
    System.out.println("=====方法执行前======");
  }

  @After("execution(* com.lf.service.UserServiceImpl.*(..))")
  public void after(){
    System.out.println("=====方法执行后======");
  }

  //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点;
  @Around("execution(* com.lf.service.UserServiceImpl.*(..))")
  public void around(ProceedingJoinPoint jp) throws Throwable {
    System.out.println("环绕前");
    Signature signature = jp.getSignature();//获得签名
    System.out.println("signature:"+signature);

    Object proceed = jp.proceed();  //执行方法
    System.out.println("环绕后");

    System.out.println(proceed);
  }

}

Spring 구성 파일에서 Bean을 등록하고 Annotation을 지원하는 구성을 추가합니다.

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

  <!--注册bean-->
  <bean id="userService" class="com.lf.service.UserServiceImpl"/>
  <bean id="log" class="com.lf.log.Log"/>
  <bean id="afterLog" class="com.lf.log.AfterLog"/>

  <!--方式三-->
  <bean id="annotationPointCut" class="com.lf.diy.AnnotationPointCut"/>
  <!--开启注解支持!  JDK(默认 proxy-target-class="false")  cglib(proxy-target-class="true")-->
  <aop:aspectj-autoproxy/>
</beans>

MyTest.java에서 테스트

import com.lf.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
  @Test
  public void test(){
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService userService = (UserService) context.getBean("userService");
  userService.add();
  }
}

답을 얻었습니다.

环绕前
signature:void com.lf.service.UserService.add()
=====方法执行前======
增加了一个用户
=====方法执行后======
环绕后
null

최근 2020 년에 수집 된 몇 가지 빈번한 인터뷰 질문 (모두 문서로 구성됨), mysql, netty, spring, thread, spring cloud, jvm, 소스 코드, 알고리즘 및 기타 자세한 설명을 포함한 많은 건조 제품이 있습니다. 자세한 학습 계획, 인터뷰 질문 분류 등 이러한 내용을 얻으려면 Q를 추가하십시오. 11604713672

추천

출처blog.csdn.net/weixin_51495453/article/details/113645365