Proxy AOP 절단면 프로 그래 밍 사례 구현
15431 단어 ProxyAOP절단면 프로 그래 밍
인터페이스: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 절단면 프로 그래 밍 사례 는 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.여러분 에 게 참고 가 되 고 많은 응원 부 탁 드 리 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[TIL] 기술면접 대비 정리 2 | 내가보려고 간단하게 정리한 글Proxy(프록시 서버) 클라이언트가 다른 네트워크 서비스에 간접적으로 접속할 수 있도록 중계해주는 서버 HTTP 프록시 서버 SOCKET 프록시 서버 가장 간단하면서 기본적인 프록시 서버 유형, 웹 트래픽 (HTT...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.