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