Proxy AOP 절단면 프로 그래 밍 사례 구현

JDK 의 프 록 시 에이 전 트 를 통 해 비 즈 니스 클래스 에 대한 간단 한 AOP 구현
인터페이스:UserService 에 포 함 된 방법 은 삽입점 으로 에이전트 에 의 해 차 단 됩 니 다
클래스:UserServiceImpl 구현 UserService 인터페이스
클래스:UserServiceFactory 공장 모드 생 성 동적 에이전트
클래스:MyAspect 절단면 류,접점 에 대한 조작 실현UserService

public interface UserService {
  //  :         
  public void addUser();
  public void updateUser();
  public int deleteUser(int id);
}
UserServiceImpl

public class UserServiceImpl implements UserService {
  public void add() {
    System.out.println("UserServiceImpl.add()");
  }
 
  public void add(User user) {
    System.out.println("UserServiceImpl.add(" + user + ")");
  }
 
  //     UserService         
  @Override
  public void addUser() {
    System.out.println("UserServiceImpl.addUser()");
  }
 
  @Override
  public void updateUser() {
    System.out.println("UserServiceImpl.updateUser()");
  }
 
  @Override
  public int deleteUser(int id) {
    System.out.println("UserServiceImpl.deleteUser(" + id + ")");
    return 1;
  }
}
UserServiceFactory

public class UserServiceFactory {
  public static UserService createUserService() {
    //1、      target
    final UserService userService = new UserServiceImpl();
    //2、       
    final MyAspect myAspect = new MyAspect();
    //3、    before() after()        
    //3.1、  JDK  (      )
    /*
     newProxyInstance(
        ClassLoader loader,   //    ,    
        Class<?>[] interfaces, //  ,               
        InvocationHandler h)  //             :deforre()、after()
     */
    UserService serviceProxy = (UserService) Proxy.newProxyInstance(
        UserServiceFactory.class.getClassLoader(),
        userService.getClass().getInterfaces(),
        new InvocationHandler() {
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //    
            myAspect.before();
            
            //               
            Object obj = method.invoke(userService, args);
 
            //    
            myAspect.after();
            
            return obj;
          }
        });
    return serviceProxy;
  }
}
MyAspect:(로그 기록 등 구체 적 인 작업 입 니 다)

public class MyAspect {
  public void before() {
    System.out.println("MyAspect.before()    ...");
  }
 
  public void after() {
    System.out.println("MyAspect.after()    ...");
  }
}
유닛 테스트:

  @Test
  public void aop_test() {
    UserService userService = UserServiceFactory.createUserService();
    userService.addUser();
    userService.deleteUser(10);
    userService.updateUser();
  }
출력:
MyAspect.before()트 랜 잭 션 시작...
UserServiceImpl.addUser()
MyAspect.after()사무 제출...
MyAspect.before()트 랜 잭 션 시작...
UserServiceImpl.deleteUser(10)
MyAspect.after()사무 제출...
MyAspect.before()트 랜 잭 션 시작...
UserServiceImpl.updateUser()
MyAspect.after()사무 제출...
보충 지식:동적 대리 기술 학습 SpringAop 과 결합 하여 절단면 프로 그래 밍 실현
하나의 예 를 결합 하여 동적 대리 기술 과 SpringAop 을 이용 하여 수 요 를 실현 하 다.
필요:내 UserService 클래스 의 모든 방법 에 타 이 머 를 추가 합 니 다.
최초의 실현 은 모든 클래스 에 코드 를 추가 하 는 것 이 었 는데,이렇게 하면 코드 의 지루 함 이 매우 커 보 였 다.

정적 에이전트 구현
JDK 를 사용 하여 동적 대 리 를 제공 하기 전에 정적 대리 기술 을 이용 하여 이 수 요 를 실현 합 니 다.

정적 프 록 시 는 프 록 시 클래스 의 구체 적 인 코드 를 다음 과 같이 만들어 야 합 니 다.
UserService 인터페이스 및 그의 실현 클래스 및 목표 클래스 UserService Target 만 들 기

public interface UserService {
 
  public void insert();
  public void update();
  public void delete();
}
 
//    
public class UserServiceTarget implements UserService {
 
  @Time
  public void insert() {
    System.out.println("    ");
  }
 
  public void update() {
    System.out.println("    ");
  }
 
  public void delete() {
    System.out.println("    ");
  }
}
TimeHandler 클래스 를 만 들 고 중복 되 는 타이머 코드 논 리 를 TimeHandler 클래스 에 기록 합 니 다.

public class TimeHandler {
  private UserServiceTarget userService = new UserServiceTarget();
  //               -- method
  public void invoke(Method method) {
    long start = System.nanoTime();
    //     :   .invoke(  ,   );
    try {
      method.invoke(userService);
    } catch (Exception e) {
      e.printStackTrace();
    }
    long end = System.nanoTime();
    Time time = method.getAnnotation(Time.class);
    if(time != null) {
      System.out.println("   : " + (end - start));
    }
  }
}
마지막 단 계 는 자신 이 대리 류 UserServiceProxy 를 실현 하 는 것 이다.자신 이 대리 류 를 실현 하 는 것 을 정적 대리 라 고 부른다.

public class UserServiceProxy implements UserService {
 
  public void insert() {
    try {
      TimeHandler timeHandler = new TimeHandler();
      Method a = UserServiceTarget.class.getMethod("insert");
      timeHandler.invoke(a);
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
  }
 
  public void update() {
    try {
      TimeHandler timeHandler = new TimeHandler();
      Method b = UserServiceTarget.class.getMethod("update");
      timeHandler.invoke(b);
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
  }
 
  public void delete() {
    try {
      TimeHandler timeHandler = new TimeHandler();
      Method c = UserServiceTarget.class.getMethod("delete");
      timeHandler.invoke(c);
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
  }
}
이렇게 하면 UserService 클래스 와 실제 클래스 를 바 꿀 필요 가 없 는 상황 에서 코드 의 확장 성 을 증가 시 켜 코드 간 의 결합 도 를 낮 춘 다.
동적 에이전트 구현
동적 프 록 시 는 프 록 시 클래스 와 프 록 시 대상 을 만 들 필요 가 없습니다.JDK 는 프로그램 실행 중 에 프 록 시 대상 을 자동 으로 생 성 합 니 다.
동적 에이전트 의 세 단계
1.프 록 시 클래스 의 바이트 코드 생 성
2,실행 클래스 로 딩 바이트 코드 를 JVM 에 불 러 옵 니 다
3.프 록 시 클래스 의 인 스 턴 스 대상 만 들 기
방식 1
스스로 코드 를 써 서 프 록 시 클래스 가 필요 한 바이트 코드 를 생 성 합 니 다.
1.프 록 시 클래스 의 바이트 코드 가 져 오기
byte[] bytes = ProxyGenerator.generateProxyClass("UserServiceProxy", new Class[]{UserService.class});
//여기 서 첫 번 째 매개 변 수 는 자신 이 프 록 시 클래스 를 위 한 클래스 이름 이 고 두 번 째 매개 변 수 는 프 록 시 클래스 의 바이트 코드 배열 을 만들어 야 합 니 다.
2.실행 클래스 로 딩

 ClassLoader cl = new ClassLoader() {
      @Override
      protected Class<?> findClass(String name) throws ClassNotFoundException {
        return defineClass(name, bytes, 0, bytes.length);
      }
    };
    Class c = cl.loadClass("UserServiceProxy"); //      ,     UserServiceProxy    
3.프 록 시 클래스 인 스 턴 스 대상 만 들 기-반사

 //           
    Constructor constructor = c.getConstructor(InvocationHandler.class);
 
    UserServiceTarget target = new UserServiceTarget();
    //       ,            
    UserService proxy = (UserService)constructor.newInstance(new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.nanoTime();
        method.invoke(target, args);
        long end = System.nanoTime();
        System.out.println("   :" + (end - start));
        return null;
      }
    });
이 곳 의 Invocation Handler 인 터 페 이 스 는 익명 으로 우리 의 이전 TimeHandler 류 와 유사 하 게 구현 되 며,중복 코드 논 리 를 그 안에 기록 하여 방법 대상 을 통 해 이 방법 을 반사 적 으로 호출 하면 동적 대 리 를 실현 할 수 있 습 니 다.
//프 록 시 대상 사용
proxy.insert();
방식 2
Proxy 류 의 new Proxy Instance()방법 으로 동적 대 리 를 실현 합 니 다.구체 적 인 코드 는 다음 과 같 습 니 다.

public static void main(String[] args) {
    //           
    // 1.       
    ClassLoader cl = UserService.class.getClassLoader();
    // 2.            
    Class[] interfaces = new Class[] {UserService.class};
    // 3.     InvocationHandler   ,           
    UserServiceTarget target = new UserServiceTarget();
    InvocationHandler h = new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.nanoTime();
 
        //   .invoke(  ,   );
        method.invoke(target, args);
 
        long end = System.nanoTime();
        System.out.println("   :" + (end - start));
        return null;
      }
    };
    UserService proxy = (UserService) Proxy.newProxyInstance(cl, interfaces, h);
    //4.       
    proxy.update();
  }
}
Spring 프레임 워 크 AOP(절단면 을 위 한 프로 그래 밍)를 사용 하여 수 요 를 완성 합 니 다.
Spring 프레임 워 크 의 가장 주요 한 두 가지 특징 은 IOC(반전 제어)와 AOP(절단면 프로 그래 밍)이다.
IOC 총 결 제 블 로그 SpringIOC 총 결
AOP(aspect oriented programming)즉 절단면 프로 그래 밍
절단면 aspect=알림 adivce+접점 pointcut
알림:하나의 방법 입 니 다.그 중에서 중복 되 는 논리(예 를 들 어 오늘 우리 가 실현 해 야 할 타이머 수요 와 Spring 사무 관리의 바 텀 실현)를 포함 합 니 다.
접점:조건 과 일치 하 는 목표 방법 이 므 로 알림 방법 을 사용 할 수 있 습 니 다.접점 표현 식 에 맞 춰 야 합 니 다.
이전의 그림 을 다시 한 번 비교 해 보 자.

그림 속 의 User Service 는 SpringAOP 기술 의 대리 이 고 TimeHandler 는 절단면 이 며 User Service Target 은 SpringAOP 기술 에서 목표 로 불 린 다.
SpringAOP 실현
우선 Maven 의존 도 를 추가 해 야 합 니 다.

<!--spring    -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.22.RELEASE</version>
</dependency>
<!--      -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.8.13</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.13</version>
</dependency>
두 번 째 단 계 는 절단면 류 를 작성 합 니 다.

@Component
//     spring    
@Aspect
//@Aspect             
//   =    +   
public class UserAspect {
  //     @Around        
  @Around("within(service.impl.*)")
 
  //      
  //ProceedingJoinPoint          
  public Object time(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    long start = System.nanoTime();
    Object proceed = proceedingJoinPoint.proceed();//          
    long end = System.nanoTime();
    System.out.println("springaop     " + (end - start) + "  ");
    return proceed;
  }
}
UserService 와 UserServiceImpl 코드 는 다음 과 같 습 니 다.

public interface UserService {
  void insert(); 
  void update(); 
  void delete();
}
 
@Service
public class UserServiceImpl implements UserService {
  @Override
  public void insert() {
    System.out.println("UserServiceImpl       ");
}
 
  @Override
  public void update() {
    System.out.println("UserServiceImpl       ");
  }
 
  @Override
  public void delete() {
    System.out.println("UserServiceImpl       ");
  }
}
마지막 단계,Spring 프로필 설정

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
>
  <!-- spring          @Componet @Service @Controller @Repository   spring    -->
  <context:component-scan base-package="service,aspect"/>
 
  <!--            ,  : @Aspect, @Around,               -->
  <aop:aspectj-autoproxy/>
</beans>
테스트 클래스 작성

public class TestSpringAopProgramming {
  public static void main(String[] args) {
    ClassPathXmlApplicationContext context =
        new ClassPathXmlApplicationContext("spring.xml");
    UserService userService = context.getBean(UserService.class);
    userService.insert();
    userService.update();
    userService.delete();
  }
}
달걀
이때 위의 수요 에 또 변 법 이 발생 했 습 니 다.UserService 의 모든 방법 에 타 이 머 를 추가 하 는 것 이 아니 라 지 정 된 방법 에 타 이 머 를 추가 하 는 것 입 니 다.어떻게 실현 해 야 합 니까?
만약 우리 가 타 이 머 를 추가 하 는 방법 에 주 해 를 추가 하면 이 방법 을 반사 적 으로 호출 할 때 이 주해 가 동적 대 리 를 통 해 타 이 머 를 추가 하면 문 제 를 해결 할 수 있 지 않 을 까 판단 할 수 있다.
사용자 정의 주석

사용자 정의 주석 은 두 개의 주석 을 추가 해 야 합 니 다@Target@Retention
@Target 은 어떤 위치 에 추가 할 수 있 는 지 표시 합 니 다.
Element Type.TYPE 는 클래스 에 추가 할 수 있 음 을 표시 합 니 다.
Element Type.METHOD 는 방법 에 추가 할 수 있 음 을 표시 합 니 다.
Element Type.FIELD 는 속성 에 추가 할 수 있 음 을 표시 합 니 다.
@Retention 은 주해 의 역할 범 위 를 표시 합 니 다.
Source 는 주 해 는*.자바 소스 코드 에서 만 유효 합 니 다.
Class 는 주 해 는*.자바 소스 코드 와*.class 바이트 코드 에서 유효 합 니 다.
Runtime 은 주 해 는*.자바 소스 코드 와*.class 바이트 코드 와 실행 기간 에 유효 합 니 다.
사용자 정의 주석 클래스 시간

@Target({ ElementType.METHOD } ) //         
@Retention(RetentionPolicy.RUNTIME)//     ,   ,        
public @interface Time {
}
이 때 는 지정 한 방법 에@Time 주 해 를 추가 한 다음 에 대리 대상 에서 판단 하면 됩 니 다.예제 코드 는 다음 과 같 습 니 다.

public void insert() {
    try {
      TimeHandler timeHandler = new TimeHandler();
      Method a = UserServiceTarget.class.getMethod("insert");
      //  getAnnotation()        @Time  
      if(method.getAnnotation(Time.class) !=null) {
        timeHandler.invoke(a);
      }
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
  }
이상 의 이 프 록 시 실현 AOP 절단면 프로 그래 밍 사례 는 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.여러분 에 게 참고 가 되 고 많은 응원 부 탁 드 리 겠 습 니 다.

좋은 웹페이지 즐겨찾기