Spring AOP 학습 노트 04: AOP 핵심 실현 의 창설 에이전트

위의 글 에서 우 리 는 모든 인 텐 시파 이 어 를 얻 고 일치 하 는 인 텐 시파 이 어 를 얻 는 것 을 분 석 했 습 니 다. 본 고 에서 Spring AOP 의 또 다른 핵심 논리 인 프 록 시 생 성 을 분석 하 겠 습 니 다.이 부분의 논리 적 입 구 는 wrapIfNecessary () 방법 에서 인 텐 시파 이 어 를 가 져 온 createProxy () 입 니 다.
protected Object createProxy(
        Class> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

    ProxyFactory proxyFactory = new ProxyFactory();
    //           
    proxyFactory.copyFrom(this);
    //        bean      targetClass           
    if (!shouldProxyTargetClass(beanClass, beanName)) {
        // Must allow for introductions; can't just set interfaces to
        // the target's interfaces only.
        Class>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
        for (Class> targetInterface : targetInterfaces) {
            //       
            proxyFactory.addInterface(targetInterface);
        }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    for (Advisor advisor : advisors) {
        //      
        proxyFactory.addAdvisor(advisor);
    }
    //        
    proxyFactory.setTargetSource(targetSource);
    //     
    customizeProxyFactory(proxyFactory);
    ////     false(         ,          )
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(this.proxyClassLoader);
}

프 록 시 클래스 의 생 성 및 처리 에 대해 Spring 은 프 록 시 팩 토리 에 의뢰 하 였 으 며, 위의 함수 에 서 는 프 록 시 팩 토리 의 초기 화 작업 을 수행 하 였 으 며, 실제 프 록 시 생 성 을 위 한 준 비 를 하 였 으 며, 초기 화 는 다음 과 같은 내용 을 포함 합 니 다.
  • 현재 속성 가 져 오기;
  • 프 록 시 인터페이스 추가;
  • Advisor 를 밀봉 하고 Proxy Factory 에 가입 합 니 다.
  • 대리 할 클래스 설정 하기;
  • 대리 공장 에 대해 맞 춤 형 처 리 를 하여 자 류 를 실현 하도록 한다.
  • 프 록 시 가 져 오기;

  •     그 중에서 Advisor 를 봉인 하고 프 록 시 팩 토리 에 가입 하 며 에이 전 트 를 만 드 는 것 은 상대 적 으로 번 거 로 운 과정 입 니 다. 프 록 시 팩 토리 가 제공 하 는 addAdvisor 방법 을 통 해 인 텐 시파 이 어 를 프 록 시 공장 에 직접 설치 할 수 있 지만 인 텐 시파 이 어 를 인 텐 시파 이 어 로 밀봉 하 는 것 은 일정한 논리 가 필요 합 니 다.
    protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
        //        interceptorName
        Advisor[] commonInterceptors = resolveInterceptorNames();
    
        List allInterceptors = new ArrayList();
        if (specificInterceptors != null) {
            //      
            allInterceptors.addAll(Arrays.asList(specificInterceptors));
            if (commonInterceptors != null) {
                if (this.applyCommonInterceptorsFirst) {
                    allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                }
                else {
                    allInterceptors.addAll(Arrays.asList(commonInterceptors));
                }
            }
        }
        if (logger.isDebugEnabled()) {
            int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
            int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
            logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
                    " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
        }
    
        Advisor[] advisors = new Advisor[allInterceptors.size()];
        for (int i = 0; i < allInterceptors.size(); i++) {
            //            Advisor
            advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
        }
        return advisors;
    }
    
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        //             Advisor             
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        //     Advisor Advice    ,     
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            //    MethodInterceptor     DefaultPointcutAdvisor  
            return new DefaultPointcutAdvisor(advice);
        }
        //     Advisor               
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

    Spring 에 서 는 과도 한 차단기, 인 텐 시파 이 어, 인 텐 시파 이 어 등 방식 으로 논 리 를 강화 하기 때문에 인 텐 시파 이 어 를 Advisor 로 패키지 하여 프 록 시 생 성 을 진행 할 필요 가 있 습 니 다. 강 화 된 패 키 징 과정 을 마 쳤 습 니 다. 그 다음은 가장 중요 한 단계 인 프 록 시 생 성 과 획득 입 니 다.
    public Object getProxy(ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }

    1. 프 록 시 생 성
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        //     
        return getAopProxyFactory().createAopProxy(this);
    }
    
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface()) {
                return new JdkDynamicAopProxy(config);
            }
            return CglibProxyFactory.createCglibProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

    여기 서 프 록 시 생 성 이 완료 되 었 습 니 다. 우리 가 이전에 Spring 의 소스 코드 를 읽 었 든 안 읽 었 든 간 에 Spring 의 프 록 시 에서 JDK Proxy 의 실현 Cglib Proxy 의 실현 에 대해 어느 정도 들 어 본 적 이 있 을 것 입 니 다.Spring 은 만약 에 골 랐 다 면?이제 우 리 는 소스 코드 의 측면 에서 스프링 이 어떻게 대리 방식 을 선택 하 는 지 분석 해 보 자.
        상기 코드 에서 의 판단 조건 을 보면 세 가지 측면 이 Spring 의 판단 에 영향 을 미 친 다 는 것 을 알 수 있다.
  • optimize: CGLIB 를 통 해 만 든 에이전트 가 급진 적 인 최적화 전략 을 사용 하 는 지 제어 하 는 데 사 용 됩 니 다.AOP 에이전트 가 최 적 화 를 어떻게 처리 하 는 지 완전히 알 지 않 으 면 사용자 가 이 설정 을 사용 하 는 것 을 추천 하지 않 습 니 다.현재 이 속성 은 CGLIB 에이전트 에 만 사 용 됩 니 다. JDK 동적 에이전트 (기본 에이전트) 에 대해 서 는 유효 하지 않 습 니 다.
  • proxy TargetClass: 이 속성 이 true 일 때 대상 클래스 자체 가 대상 클래스 의 인터페이스 가 아 닌 프 록 시 되 고 CGLIB 방식 으로 프 록 시 를 만 듭 니 다. xml 파일 설정 방식 은 다음 과 같 습 니 다.
  • hasNoUser Supplied ProxyInterfaces: 프 록 시 인터페이스 가 존재 하 는 지 여부 입 니 다.

  •     다음은 JDK 와 Cglib 방식 에 대한 정리 입 니 다.
  • 대상 이 인 터 페 이 스 를 실현 하면 기본 적 인 상황 에서 JDK 의 동적 에이전트 로 AOP 를 실현 합 니 다.
  • 대상 이 인 터 페 이 스 를 실현 하면 CGLIB 를 강제로 사용 하여 AOP 를 실현 할 수 있다.
  • 대상 이 인 터 페 이 스 를 실현 하지 못 하면 CGLIB 방식 으로 AOP 를 실현 해 야 하 며 Spring 은 자동 으로 전환 된다.

  • 어떻게 CGLIB 를 강제로 사용 하여 AOP 를 실현 합 니까?
  • CGLIB 라 이브 러 리 추가, SpringHOME/cglib/*.jar
  • Spring 프로필 에 추가
  • JDK 동적 에이전트 와 CGLIB 바이트 코드 생 성의 차이 점 은?
  • JDK 동적 에이 전 트 는 인 터 페 이 스 를 실현 한 클래스 에 만 에이 전 트 를 생 성 할 수 있 을 뿐 클래스 에 대한 에이 전 트 는 할 수 없다.
  • CGLIB 는 클래스 에 대한 에이전트 로 지 정 된 클래스 에 하위 클래스 를 생 성하 고 덮어 쓰 는 방법 입 니 다. 계승 이기 때문에 이 클래스 나 방법 은 final 이 라 고 밝 히 지 않 는 것 이 좋 습 니 다.

  •  
    2. 에이전트 가 져 오기
        어떤 프 록 시 방식 을 사용 하면 프 록 시 생 성 을 할 수 있 는 지 확 정 했 습 니 다. Spring 에 서 는 주로 두 가지 방식 으로 프 록 시 생 성 을 실 현 했 습 니 다. JDK 동적 프 록 시, cglib. 우 리 는 분석 합 니 다.
    2.1 JDK 동적 에이전트 방식
        여 기 는 JdkDynamicAopProxy 의 getProxy () 로 직접 위치 합 니 다.
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    JDK 동적 에이전트 의 사용 관건 은 사용자 정의 InvocationHandler 를 만 드 는 것 입 니 다. InvocationHandler 에는 덮어 써 야 할 함수 getProxy 가 포함 되 어 있 습 니 다. 여기 서 JdkDynamicAopProxy 는 InvocationHandler 를 계승 한 것 입 니 다. 그래서 위의 방법 은 바로 이 조작 을 완성 한 것 입 니 다. 그리고 우 리 는 JdkDynamicAopProxy 에 반드시 invoke 함수 가 있 을 것 이 라 고 추측 할 수 있 습 니 다.그리고 JdkDynamicaopProxy 는 AOP 의 핵심 논 리 를 그 안에 쓰 고 찾 아 보면 반드시 이런 함수 가 있 을 것 입 니 다.
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
    
        TargetSource targetSource = this.advised.targetSource;
        Class> targetClass = null;
        Object target = null;
    
        try {
            //   equals  
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                return equals(args[0]);
            }
            //   hash  
            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                return hashCode();
            }
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
    
            Object retVal;
            //
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
    
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
    
            //            
            List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
            if (chain.isEmpty()) {
                //                    
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                //        ReflectiveMethodInvocation,      proceed         
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //       
                retVal = invocation.proceed();
            }
    
            //     
            Class> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

    위의 invoke () 함수 의 가장 중요 한 작업 은 바로 차단기 체인 을 만 들 고 ReflectiveMethodInvocation 류 를 사용 하여 체인 의 패 키 징 을 하 는 것 입 니 다. ReflectiveMethodInvocation 류 의 proced 방법 에서 차단기 의 하나씩 호출 을 실현 하면 우 리 는 이어서 탐구 합 니 다.proceed 방법 에서 선행 강화 가 목표 방법 전에 호출 되 고 나중에 목표 방법 후에 호출 되 는 논 리 를 어떻게 실현 합 니까?
    public Object proceed() throws Throwable {
        //                  
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        //             
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            //     
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                //
                return proceed();
            }
        }
        else {
            //      ,    。 this                    
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

    ReflectiveMethodInvocation 의 주요 직책 은 체인 호출 카운터 를 유지 하고 현재 호출 체인 의 위 치 를 기록 하여 체인 이 질서 있 게 진행 할 수 있 도록 하 는 것 이다.사실 이 방법 에서 우리 가 구상 한 각종 증강 순 서 는 없 지만 세심 한 독자 들 은 이 부분 이 사실은 각 증강 기 에 의뢰 하여 실현 되 었 다 는 것 을 알 수 있다. 앞에서 말 한 바 와 같다.
    2.2 Cglib 방식
        CGLIB 대 리 를 완성 한 종 류 는 CglibAopProxy 류 에 의뢰 하여 이 루어 진 것 입 니 다. 끝까지 알 아 보 겠 습 니 다.앞의 분석 에 따 르 면 우 리 는 CglibAopProxy 의 입구 도 getProxy () 에 있 을 것 이 라 고 쉽게 판단 할 수 있다.
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }
    
        try {
            Class> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
    
            Class> proxySuperClass = rootClass;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }
    
            //   Class
            validateClassIfNecessary(proxySuperClass);
    
            //      CGLIB Enhancer
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
            enhancer.setInterceptDuringConstruction(false);
            //      
            Callback[] callbacks = getCallbacks(rootClass);
            Class>[] types = new Class>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
            enhancer.setCallbacks(callbacks);
    
            //             
            Object proxy;
            if (this.constructorArgs != null) {
                proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
            }
            else {
                proxy = enhancer.create();
            }
    
            return proxy;
        }
        catch (CodeGenerationException ex) {
            catch    。。。
        }
    }

    위의 함수 에서 Enhancer 를 완전 하 게 만 드 는 과정 입 니 다. Enhancer 의 문 서 를 참고 할 수 있 습 니 다. 여기 서 가장 중요 한 것 은 getCallbacks () 방법 으로 차단기 체인 을 설정 하 는 것 입 니 다.
    private Callback[] getCallbacks(Class> rootClass) throws Exception {
        //   expose-proxy     
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();
    
        //        DynamicAdvisedInterceptor 
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    
        // Choose a "straight to target" interceptor. (used for calls that are
        // unadvised but can return this). May be required to expose the proxy.
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        }
        else {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }
    
        //        callback 
        Callback targetDispatcher = isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
    
        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };
    
        Callback[] callbacks;
    
        // If the target is a static one and the advice chain is frozen,
        // then we can make some optimisations by sending the AOP calls
        // direct to the target using the fixed chain for that method.
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap(methods.length);
    
            // TODO: small memory optimisation here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(methods[x].toString(), x);
            }
    
            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        }
        else {
            callbacks = mainCallbacks;
        }
        return callbacks;
    }

    getCallback () 에서 Spring 은 많은 상황 을 고려 했 고 디 테 일 한 부분 이 많 았 습 니 다. 그러나 우 리 는 소스 코드 를 읽 을 필요 도 없고 모든 디 테 일 을 이해 할 정력 도 없 었 습 니 다. 중요 한 것 은 중심 을 잡 으 면 됩 니 다.여기 서 가장 많이 사용 되 는 것 만 이해 해 야 합 니 다. 예 를 들 어 advised 속성 을 Dynamic Advised Interceptor 에 밀봉 하고 콜 백 스에 가입 하 는 목적 은 무엇 입 니까?CGLIB 에서 방법 에 대한 차단 은 사용자 정의 차단기 (MethodInterceptor 인 터 페 이 스 를 실현 하 는 클래스) 를 Callback 에 추가 하고 프 록 시 를 호출 할 때 차단기 의 intercept () 방법 을 직접 활성화 시 키 는 것 으로 이 루어 졌 으 며, getCallback () 방법 에 서 는 이러한 기능 이 구현 되 었 습 니 다. Dynamic Advised Interceptor 는 MethodInterceptor 에서 계승 하여 Callback 에 가입 한 후,프 록 시 를 다시 호출 할 때 intercept () 방법 을 직접 호출 합 니 다. 이 를 통 해 CGLIB 방식 으로 이 루어 진 프 록 시 에 대해 핵심 논 리 는 Dynamic Advised Interceptor 의 intercept () 방법 에 있 을 것 으로 추정 합 니 다.
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Class> targetClass = null;
        Object target = null;
        try {
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            // May be null. Get as late as possible to minimize the time we
            // "own" the target, in case it comes from a pool...
            target = getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
            //       
            List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                //                 
                retVal = methodProxy.invoke(target, args);
            }
            else {
                //     
                retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            retVal = processReturnType(proxy, target, method, retVal);
            return retVal;
        }
        finally {
            if (target != null) {
                releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

    여기 서 의 실현 은 JDK 동적 에이전트 방식 실현 에이전트 의 invoke 방법 과 크게 다 릅 니 다. 모두 먼저 차단기 체인 을 구성 한 다음 에 이 체인 을 밀봉 하여 직렬 호출 을 하 는 것 입 니 다. 다른 것 은 JDK 동적 에이전트 방식 에서 Reflective MethodInvocation 을 직접 구성 하 는 것 이 고 cglib 에 서 는 Cglib MethodInvocation 을 사용 합 니 다. 이것 은 Reflective MethodInvocation 을 계승 하 는 것 입 니 다.그러나 프로 세 스 () 방법 은 다시 쓰 지 않 았 다.
     
    3. 총화
    본 고 는 Spring AOP 실현 원리 에서 대리 대상 의 생 성 과정 을 분석 하 는 데 중심 을 두 었 다. bean 의 초기 화 과정 에서 Spring 의 백 엔 드 프로 세 서 를 실행 할 것 이다. 여기 서 이 bean 이 강화 되 어야 하 는 지 여 부 를 판단 하고 필요 하 다 면 Aspect 에서 정의 한 강화 정보 에 따라 지정 bean 을 강화 하 는 것 이다. 즉, 대리 대상 을 만 드 는 것 이다.프 록 시 대상 을 만 드 는 방법 은 두 가지 가 있 습 니 다. 하 나 는 JDK 동적 프 록 시 를 통 해, 다른 하 나 는 cglib 를 통 해 이 루어 집 니 다.

    좋은 웹페이지 즐겨찾기