spring aop(二):<aop>标签的解析和代理对象的创建

1.前言

当我们通过在spring的xml配置文件来通过标签来进行aop的相关配置时,需要以下步骤:

  1. 添加aop的xml nameSpace和dtd约束文件;
  2. 添加相关配置。

那么现在有一个问题,为什么我们在配置文件中加了aop:config,spring就为相关对象实现的代理,织入了切面。这一过程是怎么样实现的,我就是我们本章要解决的问题。

<?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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
     http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <!--代理的目标对象-->
    <bean id="userService" class="com.lihui.study.spring.service.impl.UserServiceImpl" scope="prototype">
        <property name="name" value="张学友"/>
    </bean>
    <!--切面类-->
    <bean id="myAspect" class="com.lihui.study.aspect.MyAspect"/>
    <!--aop配置-->
    <aop:config>
        <aop:aspect ref="myAspect">
            <aop:pointcut id="pointcut"
                          expression="execution(* com.lihui.study.spring.service.impl.UserServiceImpl.*(..))"/>
            <aop:before pointcut-ref="pointcut" method="doBefore"/>
            <aop:after pointcut-ref="pointcut" method="doAfter"/>
        </aop:aspect>
    </aop:config>
    <aop:config>
    </aop:config>
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

2.aop:config和 aop:aspectj-autoproxy标签的解析和自动代理构建器的创建。

2.1 将xml解析为Document对象

此过程不是关键,不详解。

2.2 将Document对象解析为BeanDefinitions,并根据<aop>标签注册相应的自动代理构建器,并注册配置文件中bean定义。

2.2.1 自定义标签的解析分支
  1. DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()
    根据是否是默认的命名空间,选择不同解析方式。<aop:config>明显会进入delegate.parseCustomElement(ele)分支
   protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
					  // 默认命名空间的元素解析
						parseDefaultElement(ele, delegate);
					}
					else {
					//自定义命名空间的元素解析
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
		//自定义命名空间的元素解析
			delegate.parseCustomElement(root);
		}
	}
  1. delegate.parseCustomElement()`

自定义命名空间标签的解析针对aop的命名空间,我们找到的解析处理类为:org.springframework.aop.config.AopNamespaceHandler

 public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    //获取命名空间,也就是我们xml中配置的xmlns:aop="http://www.springframework.org/schema/aop"
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	//会根据命名空间找到相应的标签处理器。会在项目中所有的META-INO文件夹下寻找spring.handlers文件。然后
	//找到通过命名空间找到对应的解析类。针对aop的命名空间,我们会在spring-aop-5.1.2.RELEASE.jar下面找到
	//spring.handlers文件,文件内容为:http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
	
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
//根据找到的解析处理类解析相应的元素
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
2.2.2 AopNamespaceHandler的初始化和解析过程

AopNamespaceHandler类的init()方法和父类NamespaceHandlerSupportparse()方法。

  1. 在上文的NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri),handler对象实例化完成后,会调用init()方法进行初始化。
  2. NamespaceHandler实例化和初始化完成后,会调用handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)),进行相应的解析处理。主要逻辑是通过标签名称找到上面init()方法注册的对应的解析器,然后通过对应的解析器的parse方法进行解析。
public class AopNamespaceHandler extends NamespaceHandlerSupport {
    
    //这里是注册beanDefinition的解析器和装饰器,具体的作用,后面再介绍。
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.5+ XSDs
		//用于2.0和2.5的SSD
		//ConfigBeanDefinitionParser解析类,负责解析<ao:config>及里面的<aop:pointcut>、<aop:advisor>、<aop:aspect>标签。
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		//负责解析<aspectj-autoproxy>标签
		//其注册的自动代理构建器AnnotationAwareAspectJAutoProxyCreator优先级更高
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace in 2.5+
		//仅用于2.0版本,2.5的移到了context 命名空间
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

}
2.2.3 <aop:config>标签的最终解析类 ConfigBeanDefinitionParser

如果是<aop:config>及其内部标签的解析,则会找到注册的解析器ConfigBeanDefinitionParser对象,通过器parse()方法进行解析。

  1. 开始解析 ConfigBeanDefinitionParser.parse()
public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);
        //这个方法很重要,内部会调用AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary()方法,注册一个自动代理构建器。
		configureAutoProxyCreator(parserContext, element);
        //解析相关标签
		List<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			if (POINTCUT.equals(localName)) {
				parsePointcut(elt, parserContext);
			}
			else if (ADVISOR.equals(localName)) {
				parseAdvisor(elt, parserContext);
			}
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}

2.创建并注册自动代理构建器的bean定义
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary()
注册一个AspectJAwareAdvisorAutoProxyCreator的自动代理构建器

public static void registerAspectJAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
        //registerOrEscalateApcAsRequired
		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		//设置proxyTargetClass的属性值,默认是false,为JDK代理;
		//设置exposeProxy的属性值,默认是false。如果设置为true,在调用这个对象的方法时,会将这个代理放入//ThreadLocal中,然后可以通过((UserService)AopContext.currentProxy()).addUser();方式来获取代理
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		registerComponentIfNecessary(beanDefinition, parserContext);
	}
  1. AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary()
 public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
	}
private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        //先判断注册器中是否包含名字为org.springframework.aop.config.internalAutoProxyCreator的bean定义
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			//比较两个构建器是否相同
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				//如果不同的话,需要比较两个构建器的优先级,保留优先级高的构建器如下
				/**
				* 在AopConfigUtils类中可以看到优先级别(低-高):
				* InfrastructureAdvisorAutoProxyCreator.class
				* AspectJAwareAdvisorAutoProxyCreator.class
				* AnnotationAwareAspectJAutoProxyCreator.class
				**/
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
        //如果注册器中没有,则注册一个传入的AspectJAwareAdvisorAutoProxyCreator 的bean定义
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

3. AspectJAwareAdvisorAutoProxyCreator 自动代理构建器

从上一节中,我们已经知道,如果容器中使用了<aop:config>标签,则注册AspectJAwareAdvisorAutoProxyCreator的bean定义;如果使用了<aop:aspectj-autoproxy/>标签,则注册优先级更高的AnnotationAwareAspectJAutoProxyCreator bean定义。

3.1 类图

AnnotationAwareAspectJAutoProxyCreator继承了AspectJAwareAdvisorAutoProxyCreator,下面没有画出。
从图我们可以看出,AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProfessor等三个后置处理器接口。
加上前面已经说过,已经注册了相应bean定义。所以,在我们之前介绍过得refresh()方法中的registerBeanPostProcessors()中,会注册AnnotationAwareAspectJAutoProxyCreator对于的bean。
类图

3.2 代理过程

3.2.1 aop代理的入口:BeanPostProcessor后置处理器

参见我之前的一篇博客,《bea的创建过程》,我们知道,在bean初始化之后,会调用BeanPostProcessor后置处理器的postProcessAfterInitialization()方法。代理相关的后置处理器就是AbstractAutoProxyCreator.postProcessAfterInitialization()

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//通过TargetSourceCreator进行自定义TargetSource不需要包装
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		//切面bean不需要被代理
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		//基础设施类和应该跳过的类不需要代理
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		//如果有切面则进行代理
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//创建代理
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
        //设置相应的切面bean,目标对象
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(getProxyClassLoader());
	}
3.2.2 AopProxy代理的创建:DefaultAopProxyFactory.createAopProxy()
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//如果指定了 optimize为true 或者是proxyTargetClass 为true 或者是 没有实现接口 
		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.");
			}
			//目标类是接口 或者是 class是由代理类动态通过getProxyClass方法 或者 newProxyInstance方法生成
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
3.2.3 获取jdk代理对象:JdkDynamicAopProxy.getProxy()
public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		//获取所有需要代理的方法
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		//创建并返回代理对象,这里需要注意传入的this对象包含了切面(切入点和通知)、回调方法等信息。
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
3.2.4 获取cglib代理对象:CglibAopProxy.getProxy()
public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating CGLIB proxy: " + 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 (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure 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 ClassLoaderAwareGeneratorStrategy(classLoader));

			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// fixedInterceptorMap only populated at this point, after getCallbacks call above
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

3.3 代理对象的方法执行

3.3.1 jdk代理对象的执行

根据上文,我们应该不难知道,当调用jdk代理对象的方法方法时候,最后会调用JdkDynamicAopProxy.invoke()方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
        //获取代理的目标对象
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				//目标对象没有实现equals方法,则调用JdkDynamicAopProxy的equals方法
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				//目标对象没有实现hashCode方法,则调用JdkDynamicAopProxy的hashCode方法
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				/**
				* method.getDeclaringClass()会返回方法的声明类
				* 也就是判断方法的声明类是不是DecoratingProxy接口,DecoratingProxy接口
				* 只有一个getDecoratedClass方法。当调用这个方法时候,直接跳转到下面的方法,
				* 返回代理对象的真实类型。
				**/

				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else 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) {
				// Make invocation available if necessary.
				// 代理是否需要暴露,前面介绍过,需要的话就把代理放到ThreadLocal中
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			//代理的目标对象
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			//回去此方法的拦截链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				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);
			}
		}
	}
3.3.1 cglib代理对象的执行

拦截的方法调用,最后会进下面的这个方法,与jdk代理的调用过程大同小异。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				// Check whether we only have one InvokerInterceptor: that is,
				// no real advice, but just reflective invocation of the target.
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					// We can skip creating a MethodInvocation: just invoke the target directly.
					// Note that the final invoker must be an InvokerInterceptor, so we know
					// it does nothing but a reflective operation on the target, and no hot
					// swapping or fancy proxying.
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					retVal = methodProxy.invoke(target, argsToUse);
				}
				else {
					// We need to create a method invocation...
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

4 使用@Aspect切面配置aop

xml配置文件中需要以下标签:

  1. <context:component-scan base-package="com.xx" 开启注解扫描
  2. <aop:aspectj-autoproxy/> 开启aspectj自动代理
    编写切面类,使用相关注解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值