내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
프록시란 객체 A가 다른 객체 B를 보유함으로써 B와 동일한 동작을 가질 수 있는 모드를 나타냅니다. 프로토콜을 외부 세계에 개방하기 위해 B는 종종 인터페이스를 구현하고 A도 인터페이스를 구현합니다. 그러나 B는 "실제" 구현 클래스인 반면 A는 B의 메서드를 빌려 인터페이스 메서드를 구현합니다. A는 "의사 군대"이지만 B의 메서드를 호출하기 전후에 B를 강화하고 다른 작업을 수행할 수 있습니다. Spring AOP는 동적 프록시를 사용하여 코드의 동적 "엮기"를 완료합니다.
프록시를 사용하면 이점이 더 커집니다. 프로젝트가 다른 프로젝트에서 제공하는 인터페이스에 의존하지만 다른 프로젝트의 인터페이스가 불안정하고 프로토콜이 자주 변경되는 경우 인터페이스가 변경되면 프록시를 사용할 수 있습니다. 비즈니스 코드를 하나씩 수정하는 것이 아니라 프록시만 수정하면 됩니다. 이런 의미에서 외부 코드가 우리 코드에 침입하는 것을 방지하기 위해 외부 세계에 적응하는 모든 인터페이스에 대해 이 작업을 수행할 수 있습니다. 프록시를 위한 다른 응용 프로그램이 많이 있을 수 있습니다.
위의 예에서 클래스 A는 B의 정적 프록시인 B를 보유하도록 하드 코딩되어 있습니다. A 프록시의 객체가 불확실한 경우 이는 동적 프록시입니다. 현재 동적 프록시에는 jdk 동적 프록시와 cglib 동적 프록시의 두 가지 일반적인 구현이 있습니다.
정적 프록시는 디자인 패턴이자 프록시 패턴의 일종입니다. 정적 프록시에서는 프로그램이 실행되기 전에 프록시 클래스가 정의되며 프록시 클래스와 프록시 클래스 간의 관계는 컴파일 타임에 결정됩니다. 이는 프록시 클래스와 프록시 클래스가 모두 동일한 인터페이스를 구현하거나 동일한 상위 클래스를 상속함을 의미합니다. 프록시 클래스는 내부적으로 프록시 클래스의 인스턴스를 보유하고 동시에 자체 메소드에서 프록시 클래스의 메소드를 호출합니다. , 호출 전후에 로깅, 권한 확인, 트랜잭션 처리 등과 같은 일부 작업을 추가할 수 있습니다.
정적 프록시에는 추상 인터페이스, 프록시 클래스 및 프록시 클래스의 세 가지 구성 요소가 있습니다. 구현 예는 다음과 같습니다.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
결과 출력:
메소드를 실행하기 전에...
대상 method1 실행 중 ...
메서드를 실행한 후...
-----------------------------
메소드를 실행하기 전에...
대상 메서드2 실행 중 ...
메서드를 실행한 후...
-----------------------------
메소드를 실행하기 전에...
대상 method3 실행 중 ...
메서드를 실행한 후...
3
정적 에이전트의 장점은 구현이 간단하고 이해하기 쉽다는 점을 정적 에이전트 구현을 통해 쉽게 알 수 있습니다. 그러나 단점도 분명합니다. 즉, 새 클래스에 프록시 기능을 추가해야 할 때마다 새 프록시 클래스를 수동으로 생성해야 하며, 이로 인해 클래스 수가 급격히 증가하고 유지 관리 비용이 증가한다는 것입니다. . 동시에 프록시 클래스와 프록시 클래스 간의 결합도가 너무 높습니다. 프록시 클래스에서 메소드를 추가, 삭제 또는 수정하면 해당 메소드도 프록시 클래스에서 추가, 삭제 또는 수정되어야 합니다. , 코드 유지 관리 비용이 향상됩니다. 또 다른 문제는 프록시 객체가 여러 대상 인터페이스의 구현 클래스를 프록시할 때 여러 구현 클래스에 서로 다른 메서드가 있어야 한다는 것입니다. 프록시 객체는 대상 객체와 동일한 인터페이스(실제로는 포함 관계)를 구현해야 하기 때문입니다. 수많은 방법으로 인해 코드가 비대해지고 유지 관리가 어려워질 수 있습니다.
동적 프록시의 핵심 아이디어는 원본 개체 코드를 수정하지 않고 프록시 개체를 통해 원본 개체에 간접적으로 액세스하고 액세스 전후에 추가 작업을 수행하는 것입니다.
동적 프록시의 구현 원리는 주로 Java의 반사 메커니즘을 기반으로 합니다. 동적 프록시를 사용하는 경우 프록시된 클래스(프록시된 개체)의 동작을 정의하는 인터페이스 또는 인터페이스 집합을 정의해야 합니다.그런 다음 구현을 작성해야 합니다.InvocationHandler
인터페이스 클래스, 이 클래스에는 프록시 개체에 대한 메서드 호출 전후에 실행되는 논리가 포함되어 있습니다.전화할 때Proxy.newProxyInstance()
메서드, 인터페이스의 클래스 로더, 인터페이스 배열 및InvocationHandler
객체, Java는 런타임에 지정된 인터페이스를 구현하는 프록시 클래스를 동적으로 생성하고 메소드 호출을 위임합니다.InvocationHandler
처리할 객체.프록시 객체의 메서드가 호출되면 실제로 호출됩니다.InvocationHandler
상호 작용invoke()
메서드 이름, 매개 변수 및 기타 정보를 기반으로 일부 전처리 논리를 수행한 다음 리플렉션을 통해 프록시 개체의 해당 메서드를 호출할 수 있는 메서드입니다.
다음으로 JDK 프록시와 CGLib라는 두 가지 동적 프록시를 소개합니다.
JDK 프록시는 Java의 반사 메커니즘을 사용하여 프록시 클래스를 동적으로 생성합니다. 구체적으로,Proxy
수업은 사용할 것입니다ProxyGenerator
클래스(이 클래스는 공개 API는 아니지만 JDK 내부에서 동적 프록시를 구현하는 핵심임)를 사용하여 프록시 클래스의 바이트코드를 생성하고 이를 JVM에 로드합니다.생성된 프록시 클래스는 다음에서 상속됩니다.java.lang.reflect.Proxy
클래스를 만들고 지정된 인터페이스를 구현합니다.프록시 클래스의 메소드에서 호출됩니다.InvocationHandler
~의invoke
메서드, 처리를 위해 메서드 호출을 프로세서로 전달합니다.
또한 성능 향상을 위해 JDK 프록시는 생성된 프록시 클래스의 클래스 개체를 캐싱하기 위한 캐싱 메커니즘도 제공합니다. 이런 방식으로 동일한 유형의 프록시 객체를 생성해야 할 때 프록시 클래스의 Class 객체를 다시 생성하지 않고 캐시에서 직접 얻을 수 있습니다.캐싱은 다음을 통해 수행됩니다.WeakCache
클래스에 의해 구현된 이 클래스는 캐시 객체에 대한 약한 참조를 사용하므로 더 이상 사용되지 않는 캐시 항목은 JVM이 가비지 수집을 수행할 때 자동으로 정리될 수 있습니다.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
인터페이스 및 재작성invoke
방법.존재하다invoke
메서드에 로깅, 권한 확인 등의 사용자 지정 논리를 추가하고 리플렉션을 통해 원래 클래스 메서드를 호출할 수 있습니다.Proxy.newProxyInstance
메소드, 클래스 로더, 인터페이스 배열 및InvocationHandler
프록시 객체를 동적으로 생성하는 인스턴스입니다. 이 메서드는 지정된 인터페이스를 구현하는 프록시 클래스 인스턴스를 반환합니다.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
~의invoke
메소드, 이 메소드에서 사용자 정의 로직을 실행한 후 원래 클래스의 메소드를 호출합니다.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
결과 출력:
메소드를 실행하기 전에...
method1 실행 중 ...
메서드를 실행한 후...
-----------------------------
메소드를 실행하기 전에...
방법2 실행 중 ...
메서드를 실행한 후...
-----------------------------
메소드를 실행하기 전에...
방법 3 실행 중 ...
메서드를 실행한 후...
3
MethodInterceptor
전처리, 후처리, 예외 처리 등과 같은 프록시 개체의 메서드 호출 전후에 사용자 지정 논리를 실행하는 메서드 인터셉터를 정의하는 인터페이스입니다.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
인터페이스 클래스 및 재정의intercept
방법. 이 메서드에 프록시 논리를 작성합니다.Enhancer
프록시 객체를 생성하는 클래스입니다.프록시 클래스를 설정해야 합니다(다음을 통해).setSuperclass
메소드) 및 콜백(경유)setCallback
메소드는 MethodInterceptor 구현 클래스를 설정합니다.- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
메소드의 프록시 논리.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
결과 출력:
com.heaboy.aopdemo.cglibproxy.대상이자형N시간ㅏN씨이자형아르 자형비와이씨G엘나비f9f41fb8
메소드를 실행하기 전에. . .
method1 실행 중 ...
메소드를 실행한 후. . .
이점:
결점:
프록시 개체 유형:JDK 프록시는 인터페이스를 구현하는 클래스만 프록시할 수 있는 반면 CGLib는 일반 클래스를 직접 프록시할 수 있습니다.
성능: CGLib는 런타임 시 프록시 클래스의 하위 클래스를 생성하며 일반적으로 JDK 프록시보다 성능이 약간 더 나은 것으로 간주됩니다. 그러나 대부분의 시나리오에서는 이러한 성능 차이가 크지 않습니다.
사용되는 장면: 대상 개체가 이미 인터페이스를 구현한 경우 JDK 프록시를 사용하는 것은 간단하고 직접적인 선택입니다. 인터페이스를 구현하지 않는 클래스를 프록시해야 하는 경우 CGLib를 사용해야 합니다.
의존하다:JDK 프록시는 Java 핵심 라이브러리의 일부이므로 추가 종속성이 필요하지 않지만 CGLib에서는 CGLib 라이브러리를 프로젝트 종속성으로 추가해야 합니다.
JDK 프록시는 Java 언어와 함께 제공되는 기능이므로 타사 클래스를 로드하여 구현할 필요가 없습니다.
Java는 JDK 프록시에 대한 안정적인 지원을 제공하며 JDK 프록시를 계속 업그레이드하고 업데이트할 예정입니다. 예를 들어 Java 8 버전의 JDK 프록시 성능은 이전 버전에 비해 크게 향상되었습니다.
JDK 프록시는 인터셉터와 리플렉션을 통해 구현됩니다.
JDK 프록시는 인터페이스를 상속하는 클래스만 프록시할 수 있습니다.
JDK 프록시는 구현 및 호출이 비교적 간단합니다.
CGLib는 타사에서 제공하는 도구로 ASM을 기반으로 구현되어 비교적 높은 성능을 가지고 있습니다.
CGLib는 인터페이스를 통해 구현될 필요가 없으며 하위 클래스를 구현하여 호출됩니다.
정적 프록시: 정적 프록시는 컴파일 중에 결정됩니다. 프록시 클래스는 프록시 클래스와 프록시 클래스가 동일한 인터페이스를 구현하거나 동일한 상위 클래스를 상속해야 합니다.
정적 프록시의 프록시 클래스는 컴파일 타임에 존재하므로 프로그램이 실행 중일 때 특정 클래스만 프록시할 수 있으며 프록시할 클래스를 동적으로 결정할 수는 없습니다.
정적 프록시는 원본 개체의 메서드 호출을 래핑하고 호출 전후에 추가 논리를 추가할 수 있지만 프록시 클래스를 미리 작성해야 하므로 코드 양이 늘어납니다.
정적 프록시는 코드에서 프록시 개체를 명시적으로 지정하고 비교적 사용이 직관적이지만 새 프록시 클래스를 추가하려면 다시 컴파일해야 합니다.
동적 프록시: 동적 프록시는 프록시 클래스를 미리 작성하지 않고 런타임에 프록시 개체를 생성합니다. Java의 리플렉션 메커니즘을 사용하여 프록시 클래스와 프록시 객체를 동적으로 생성합니다.
동적 프록시는 인터페이스를 기반으로 하며 java.lang.reflect.Proxy 클래스 및 java.lang.reflect.InvocationHandler 인터페이스를 통해 구현됩니다.
동적 프록시는 여러 인터페이스의 클래스를 프록시하고 어떤 클래스를 프록시할지 동적으로 결정할 수 있습니다. 런타임 시 필요에 따라 다양한 객체에 대해 프록시를 생성하여 유연성을 높일 수 있습니다.
동적 프록시는 각 프록시 클래스에 대해 특정 프록시 클래스를 작성할 필요가 없으므로 더 유연하고 코드가 절약됩니다.
동적 에이전트는 로깅, 트랜잭션 관리 등과 같은 프록시 개체에 대한 메서드 호출 전후에 사용자 지정 논리를 추가할 수 있습니다. 동적 프록시의 단점은 정적 프록시와 비교할 때 런타임에 프록시 객체를 생성하려면 특정 성능 오버헤드가 필요하다는 것입니다.
정적 프록시는 다음 시나리오에 적합합니다.
대상 객체(프록시 객체)의 개수가 제한되어 결정된 경우 수동으로 프록시 클래스를 작성하여 정적 프록시를 구현할 수 있습니다. 정적 프록시는 컴파일 타임에 프록시 클래스를 생성하므로 런타임에 더 나은 성능을 제공합니다.
정적 프록시는 대상 개체를 캡슐화하고 원본 코드를 수정하지 않고 추가 기능을 추가합니다. 이로 인해 로깅 및 트랜잭션 관리와 같은 교차 문제에 정적 프록시가 자주 사용됩니다.
동적 프록시는 다음 시나리오에 적합합니다.
대상 개체의 개수가 불확실하거나 미리 확인할 수 없는 경우 동적 프록시를 사용하면 보다 편리하게 프록시 개체를 생성할 수 있습니다. 여러 프록시 클래스를 수동으로 작성하는 지루한 작업을 피하면서 런타임에 프록시 클래스와 프록시 개체를 생성합니다.
동적 프록시는 런타임 시 대상 개체에 대한 프록시 동작을 추가, 제거 또는 변경할 수 있는 유연성을 제공합니다. 이로 인해 AOP(관점 지향 프로그래밍) 및 RPC(원격 프로시저 호출)와 같은 애플리케이션 시나리오에서 동적 프록시가 자주 사용됩니다.
동적 프록시는 런타임 시 리플렉션 메커니즘을 통해 프록시 클래스와 프록시 개체를 생성하기 때문에 성능이 정적 프록시보다 약간 낮을 수 있다는 점에 유의해야 합니다. 또한 동적 프록시는 인터페이스를 구현하는 대상 개체만 프록시할 수 있지만 정적 프록시에는 이러한 제한이 없습니다.
정리하자면, 정적 프록시는 대상 개체의 수가 제한되어 있고, 캡슐화 및 추가 기능이 필요한 시나리오에 적합하고, 동적 프록시는 대상 개체의 수가 불확실하거나 미리 결정할 수 없는 시나리오에 적합합니다. 프록시 동작은 유연하게 추가, 삭제 또는 변경되어야 합니다. 특정 요구와 상황에 따라 적절한 대행사 방법을 선택하십시오.
Spring AOP는 관점 지향 프로그래밍을 구현하는 데 사용되는 Spring 프레임워크의 중요한 모듈입니다.
대면 프로그래밍 , 이는 프로그래머가 사용자 정의 크로스커팅 포인트를 통해 모듈화하고 여러 클래스에 영향을 미치는 동작을 재사용 가능한 모듈로 캡슐화할 수 있는 프로그래밍 모델입니다. 예: 로그 출력의 경우 AOP를 사용하지 않는 경우 모든 클래스와 메소드에 로그 출력 문을 넣어야 합니다. 그러나 AOP를 사용하면 로그 출력 문을 재사용 가능한 모듈로 캡슐화하여 선언적 방식으로 클래스를 사용할 때마다 로그 출력이 자동으로 완료됩니다.
관점 지향 프로그래밍의 개념에서는 기능을 두 가지 유형으로 나눕니다.
핵심 사업: 로그인, 회원가입, 추가, 삭제, 수정, 조회 등을 모두 핵심사업이라고 합니다.
주변 기능: 로그 및 트랜잭션 관리는 보조 주변 서비스입니다.
관점 지향 프로그래밍에서는 핵심 비즈니스 기능과 주변 기능이 독립적으로 개발되고 두 기능이 결합되지 않습니다. 그러면 관점 기능과 핵심 비즈니스 기능이 함께 "엮여" 있는데, 이를 AOP라고 합니다.
AOP는 업무와 관련이 없는 것들을 변환할 수 있으며,그러나 이는 비즈니스 모듈에서 일반적으로 호출하는 논리 또는 책임(트랜잭션 처리, 로그 관리, 권한 제어 등)에 대해 캡슐화되어 있습니다.,쉬운시스템 내 중복 코드 감소,모듈 간 결합 감소,그리고향후 확장성과 유지 관리에 도움이 됩니다.。
AOP에는 다음과 같은 개념이 있습니다.
애스펙트J: Aspect는 개념일 뿐, 이에 해당하는 특정 인터페이스나 클래스는 없습니다.
조인 포인트 : 연결점은 메소드 호출, 예외 처리 등 프로그램 실행 중 지점을 의미합니다. Spring AOP에서는 메소드 수준 조인포인트만 지원됩니다.
조언 : 알림, 즉 우리가 정의한 관점의 교차 논리에는 "around", "before" 및 "after"의 세 가지 유형이 있습니다. 많은 AOP 구현 프레임워크에서 Advice는 일반적으로 인터셉터 역할을 하며 조인 포인트 주변에서 처리될 링크로 많은 인터셉터를 포함할 수도 있습니다.
포인트컷: 조인 포인트를 일치시키는 데 사용되는 Pointcut. AspectJ에 포함된 조인 포인트는 Pointcut으로 필터링되어야 합니다.
소개 : 소개, 어드바이스된 객체가 실제로 구현하지 않는 추가 인터페이스를 구현한다는 점을 선언하는 측면을 허용합니다. 예를 들어 프록시 개체를 사용하여 두 개의 대상 클래스를 프록시할 수 있습니다.
직조 : 위빙, 이제 연결점, 절단점, 알림 및 측면이 생겼는데 이를 프로그램에 어떻게 적용합니까? 맞습니다. 포인트컷의 안내에 따라 알림 로직이 대상 메소드에 삽입되어 메소드가 호출될 때 알림 로직이 실행될 수 있습니다.
AOP 프록시 : AOP 프록시는 AOP 구현 프레임워크에서 관점 프로토콜을 구현하는 객체를 의미합니다. Spring AOP에는 두 종류의 프록시, 즉 JDK 동적 프록시와 CGLIB 동적 프록시가 있습니다.
대상 객체: 대상 개체는 프록시 중인 개체입니다.
Spring AOP는 JDK 동적 프록시와 Cglib 승격을 기반으로 구현됩니다. 두 프록시 메소드 모두 런타임 메소드이므로 컴파일 타임 처리가 없으므로 Spring은 Java 코드를 통해 구현됩니다.
여러 클래스나 객체(예: 로깅, 트랜잭션 관리, 권한 제어, 인터페이스 현재 제한, 인터페이스 전원 등)에 분산된 몇 가지 일반적인 동작을 일반적으로 이라고 합니다. 교차적 우려 . 모든 클래스나 객체에서 이러한 동작을 반복적으로 구현하면 코드가 중복되고 복잡해지며 유지 관리가 어려워집니다.
AOP는 교차 편집 문제(예: 로깅, 트랜잭션 관리, 권한 제어, 인터페이스 전류 제한, 인터페이스 전원 등)를 다음과 같이 변환할 수 있습니다. 핵심 비즈니스 로직(핵심 관심사, 핵심 관심사) 관심사의 분리를 달성하려면 초점에서 분리하세요.
로깅: 로깅 주석을 사용자 정의하고 AOP를 사용하여 한 줄의 코드로 로깅을 달성합니다.
성능 통계: AOP를 사용하여 타겟 메소드 실행 전후의 메소드 실행 시간을 계산하여 최적화 및 분석을 용이하게 합니다.
거래 관리:@Transactional
주석을 사용하면 Spring이 예외 작업 롤백, 반복되는 트랜잭션 관리 논리 제거 등 트랜잭션 관리를 수행할 수 있습니다.@Transactional
Annotation은 AOP를 기반으로 구현됩니다.
권한 제어: AOP를 사용하여 대상 메소드를 실행하기 전에 사용자에게 필요한 권한이 있는지 확인하십시오. 그렇다면 대상 메소드를 실행하십시오. 그렇지 않으면 실행되지 않습니다.예를 들어 SpringSecurity는 다음을 활용합니다.@PreAuthorize
코드 줄에 주석을 달아 권한 확인을 사용자 정의할 수 있습니다.
인터페이스 전류 제한: AOP를 사용하여 대상 메서드가 실행되기 전에 특정 전류 제한 알고리즘 및 구현을 통해 요청을 제한합니다.
캐시 관리: AOP를 사용하여 타겟 메소드 실행 전후에 캐시를 읽고 업데이트합니다.
AOP의 일반적인 구현 방법에는 동적 프록시, 바이트코드 작업 등이 포함됩니다.
Spring AOP는 동적 프록시를 기반으로 합니다. 프록시할 객체가 특정 인터페이스를 구현하는 경우 Spring AOP는 다음을 사용합니다. JDK 프록시, 프록시 객체를 생성하려면 인터페이스를 구현하지 않는 객체의 경우 JDK 프록시를 사용하여 프록시를 사용할 수 없습니다. 씨글리브 프록시 역할을 할 프록시 객체의 서브클래스 생성
존재하다spring-aop.xml
구성 파일에서 관련 Bean 및 측면을 구성하십시오.
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- 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">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
출력 결과:
서라운드 프론트 알림
사전 알림
method1 실행 중 ...
반품 후 알림
서라운드 백 알림
존재하다spring-confaop.xml
구성 파일에서 관련 Bean 및 측면을 구성하십시오.
- <?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:context="http://www.springframework.org/schema/context"
- 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/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">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
출력 결과:
conf 사전 알림
conf 서라운드 접두사
방법 3 실행 중 ...
conf 반환 후 알림
conf 서라운드 포스트
conf 게시물 알림
0
- <?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:context="http://www.springframework.org/schema/context"
- 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/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">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }