SpringBoot中Spring AOP体系讲解

目录

 

1、AOP思想介绍

2、AOP用途

3、具有相似功能的其他实现方式

4、AOP的实现方式--代理模式

5、SpringBoot中动态代理详细体系


1、AOP思想介绍

AOP是Aspect Oriented Programming的缩写,意为面向切面编程,是一种编程思想,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。

2、AOP用途

Spring中基于AOP思想的功能有很多

  • 数据库事务控制,也就是我们常用的@Transactional注解;AOP抽取出来的功能有:在开始一系列数据库操作前设置数据库连接的autoCommit属性为false来开启事务,然后等一系列数据库操作完毕后执行commit命令来提交事务,中间出现异常情况则执行rollback命令进行数据库操作回滚。当然Spring的事务机制并非如此简单,还有事务的传播性处理,与ORM框架整合时两边的事务统一处理等功能。
  • 缓存控制,也就是我们常用的@Cacheable等注解;AOP抽取出来的功能有:在方法调用前查询是否有缓存信息,是则直接返回缓存内容;在方法调用结束后进行缓存数据增加更新;
  • 参数校验 ,也就是我们常用的@Validated注解;AOP抽取出来的功能有:在controller方法调用前,对方法参数进行校验,不符合要求的进行异常抛出等处理;

3、具有相似功能的其他实现方式

  • Web项目中的Filter
  • Spring MVC的HandlerInterceptor

这两种方式的缺点

  1. 只支持对http请求进行切面化处理
  2. 灵活性比较低,无法进行精确的切面配置

4、AOP的实现方式--代理模式

AOP的实现方式为动态代理,常用的动态代理方式有JDK自带的基于接口的动态代理和CGLIB基于字节码修改技术的动态代理。

IOC是AOP的基石,虽然bean的获取也可以像dubbo中那样使用ExtensionLoader进行扩展对象的获取,但是这不符合Spring减少入侵性代码的思想。IOC天然的将bean的创建和获取分开,在BeanFactory进行bean的创建过程中正好可以进行切面的织入以及代理对象生成的工作,而IOC负责将代理对象注入到依赖bean中。

在介绍动态代理前,先介绍一下代理模式,代理模式是常用的设计模式之一,主要用于控制对象的访问,代理模式分静态代理跟动态代理两种,静态代理是通过完全手写代码的方式进行处理如:

/**
 * 定义接口
**/
public interface Subject {

    void sayHello(String name);

}


/**
* 定义实现类
**/

public class SubjectImpl implements Subject {


    @Override
    public void sayHello(String name) {
        System.out.println("hello " + name);
    }
}


/**
**定义代理类
**/

public class SubjectProxyImpl implements Subject {

    private Subject subject;

    public SubjectProxyImpl() {
        this.subject = new SubjectImpl();
    }

    @Override
    public void sayHello(String name) {
        System.out.println("before say Hello");
        subject.sayHello(name);
        System.out.println("after say hello");
    }

    public static void main(String[] args) {
        Subject subject = new SubjectProxyImpl();
        subject.sayHello("dddd");
    }
}

运行结果为:

静态代理的代码完全手写固定,每增加一个需要代理的类都需要写一套对应的代码,这很显然不是一种高效的方式。所以就有了另外的动态代理方式。

JDK动态代理的核心为Proxy类,他是java反射包下的一个类,创建代理实例的方法为:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

可以看到除了需要传入ClassLoader,接口的Class对象之外还需传入一个InvocationHandler对象,在调用被代理接口的某个方法时,这个InvocationHandler的invoke方法就是在调用代理方法时用于回调。

CGLIB字节码编辑技术的核心类为Enhancer,Enhancer对象需要设置Callback接口对象

/**
	 * Set the single {@link Callback} to use.
	 * Ignored if you use {@link #createClass}.
	 * @param callback the callback to use for all methods
	 * @see #setCallbacks
	 */
	public void setCallback(final Callback callback) {
		setCallbacks(new Callback[]{callback});
	}

	/**
	 * Set the array of callbacks to use.
	 * Ignored if you use {@link #createClass}.
	 * You must use a {@link CallbackFilter} to specify the index into this
	 * array for each method in the proxied class.
	 * @param callbacks the callback array
	 * @see #setCallbackFilter
	 * @see #setCallback
	 */
	public void setCallbacks(Callback[] callbacks) {
		if (callbacks != null && callbacks.length == 0) {
			throw new IllegalArgumentException("Array cannot be empty");
		}
		this.callbacks = callbacks;
	}

或者在使用Enhancer的静态方法创建代理对象

/**
	 * Helper method to create an intercepted object.
	 * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
	 * instead of this static method.
	 * @param type class to extend or interface to implement
	 * @param callback the callback to use for all methods
	 */
	public static Object create(Class type, Callback callback) {
		Enhancer e = new Enhancer();
		e.setSuperclass(type);
		e.setCallback(callback);
		return e.create();
	}

	/**
	 * Helper method to create an intercepted object.
	 * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
	 * instead of this static method.
	 * @param superclass class to extend or interface to implement
	 * @param interfaces array of interfaces to implement, or null
	 * @param callback the callback to use for all methods
	 */
	public static Object create(Class superclass, Class interfaces[], Callback callback) {
		Enhancer e = new Enhancer();
		e.setSuperclass(superclass);
		e.setInterfaces(interfaces);
		e.setCallback(callback);
		return e.create();
	}

	/**
	 * Helper method to create an intercepted object.
	 * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
	 * instead of this static method.
	 * @param superclass class to extend or interface to implement
	 * @param interfaces array of interfaces to implement, or null
	 * @param filter the callback filter to use when generating a new class
	 * @param callbacks callback implementations to use for the enhanced object
	 */
	public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
		Enhancer e = new Enhancer();
		e.setSuperclass(superclass);
		e.setInterfaces(interfaces);
		e.setCallbackFilter(filter);
		e.setCallbacks(callbacks);
		return e.create();
	}

最简单的静态方法需要传入被代理类信息和Callback接口实例。

不管是jdk的InvocationHandler还是Enhancer的Callback接口都给我们提供了一个钩子,通过这个钩子把被代理对象方法的调用交还给我们进行控制,修改一下静态代理的代码来模仿:

静态代理的半动态化版:


public interface Subject {

    String sayHello(String name);

}



import java.lang.reflect.Method;

public interface Callback {

    Object invoke(Method method, Object[] args, Object realObject);
}



public class SubjectImpl implements Subject {


    @Override
    public String sayHello(String name) {
        System.out.println("hello " + name);
        return "ok" +name;
    }
}



import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class SubjectProxyImpl implements Subject {

    private Subject subject;

    private Callback callback;

    public SubjectProxyImpl(Callback callback) {
        this.subject = new SubjectImpl();
        this.callback = callback;
    }

    @Override
    public String sayHello(String name) {
        StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
        String methodName = stackTraceElement.getMethodName();
        Method method = null;
        try {
            method = subject.getClass().getMethod(methodName, String.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return callback.invoke(method, Arrays.asList(name).toArray(), subject).toString();
    }

    public static void main(String[] args) {
        Subject subject = new SubjectProxyImpl(new Callback() {
            @Override
            public Object invoke(Method method, Object[] args, Object realObject) {
                try {
                    System.out.println("before say hello ");
                    Object object = method.invoke(realObject, args);
                    System.out.println("after say Hello ");
                    return object;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
        String result = subject.sayHello("dddd");
        System.out.println("result is " + result);
    }
}

执行结果为:

 

动态代理的原理方面讲的已经差不多了,其实还有另一种方法达到对应的效果,就是动态编译就像Dubbo中获取Adaptive对象时需要进行动态编译一样,生成静态代理类的完整代码,然后编译成class文件流再进行BeanDefinition注册和bean的创建。这个过程比较繁琐,以后有空的时候再进行尝试。

5、SpringBoot中动态代理详细体系

SpringBoot在autoconfigure包中提供了AopAutoConfiguration

package org.springframework.boot.autoconfigure.aop;

import org.aspectj.weaver.Advice;

import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
 * Auto-configuration} for Spring's AOP support. Equivalent to enabling
 * {@link EnableAspectJAutoProxy @EnableAspectJAutoProxy} in your configuration.
 * <p>
 * The configuration will not be activated if {@literal spring.aop.auto=false}. The
 * {@literal proxyTargetClass} attribute will be {@literal true}, by default, but can be
 * overridden by specifying {@literal spring.aop.proxy-target-class=false}.
 *
 * @author Dave Syer
 * @author Josh Long
 * @since 1.0.0
 * @see EnableAspectJAutoProxy
 */


@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		ClassProxyingConfiguration(BeanFactory beanFactory) {
			if (beanFactory instanceof BeanDefinitionRegistry) {
				BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
		}

	}

}

默认会被加载配置,除非将其添加到AutoConfiguration的exclude列表中,或者配置spring.aop.auto=false

默认条件化装配的是ClassProxyingConfiguration,未引入aspectjweaver.jar包的情况下。通过AopConfigUtils向BeanDefinitionRegistry注册了InfrastructureAdvisorAutoProxyCreator,并强制设置其proxyTargetClass属性为true,也就是强制使用CGLIB进行动态代理。

而InfrastructureAdvisorAutoProxyCreator通过继承AbstractAdvisorAutoProxyCreator,继承了实现SmartInstantiationAwareBeanPostProcessor的AbstractAutoProxyCreator。

在AbstractAutowireCapableBeanFactory的

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException 方法会在这里进行代理类的创建

刚好是在bean实例化并进行生命周期调用之前。

resolveBeforeInstantiation方法中使用的是InstantiationAwareBeanPostProcessor进行bean的创建处理,而SmartInstantiationAwareBeanPostProcessor是InstantiationAwareBeanPostProcessor的子接口

说明InfrastructureAdvisorAutoProxyCreator从AbstractAutoProxyCreator继承来的postProcessBeforeInstantiation方法被调用了。

在这里进行被代理对象的生成以及代理对象的生成。

getAdvicesAndAdvisorsForBean方法获取的是BeanFactory中适用于当前被代理对象的Advisor bean并排序。

@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}


/**
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}


protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}


public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}

完整的方法调用流程中,如果advisor对象同时也是IntroductionAdvisor或者PointcutAdvisor对象时getAdvicesAndAdvisorsForBean方法返回的数组才不为空。

而IntroductionAdvisor和PointcutAdvisor都为接口,都继承了Advisor接口。IntroductionAdvisor有getClassFilter方法,返回ClassFilter对象。PointcutAdvisor有getPointcut方法,返回Pointcut对象,而Pointcut对象中有ClassFilter和MethodMatcher两个属性,很明显都是用于判断某个类是否需要进行动态代理。

创建代理方法如下,这里

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);
			}
		}

		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());
	}

由代理工厂进行代理创建获取,代理工厂中加入了所有需要织入的切面Advisor。

proxyFactory.getProxy方法中

先创建AopProxy,然后通过AopProxy进行代理创建,而AopProxy又通过AopProxyFactory进行创建,最终调用DefaultAopProxyFactory的方法,确定使用哪种动态代理方式进行处理,对应接口类型和代理类型的代理使用JDK自带动态代理方式,否则使用CGLIB动态代理方式。

	@Override
	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() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

可以看到JdkDynamicAopProxy获取代理对象最终回归到Proxy类,ObjenesisCglibAopProxy继承CglibAopProxy获取代理对象最终回归到Enhancer类,只是传入的回调对象(InvocationHandler对象或者Callback对象)都不是我们直接定义任何东西。

InvocationHandler(也就是JdkDynamicAopProxy自己)的invoke方法中将所有Advisor对象转换成调用链,如果调用链为空,则直接通过反射执行方法,返回结果,如果调用链不为空则再次转换为MethodInvocation进行切面代码的执行。最终递归执行方法为ReflectiveMethodInvocation.proceed方法

invokeJoinpoint方法为最后反射执行被代理对象的对应方法,后面两个invoke方法都为MethodInterceptor的invoke方法,而MethodInterceptor接口继承了Interceptor接口,Interceptor接口又继承了Advice接口。

而spring的另一个MethodInterceptor接口实现了Callback接口只有一个intercept方法,CglibAopProxy中有几个这个MethodInterceptor的实现类,如HashCodeInterceptor用于处理对hashCode方法的切面,EqualsInterceptor 用于处理对equals方法的切面,DynamicAdvisedInterceptor则用于处理我们常规定义的切面。DynamicAdvisedInterceptor的intercept方法中可以看到:

逻辑跟JdkDynamicAopProxy.invoke方法中基本相同,CglibMethodInvocation为ReflectiveMethodInvocation的子类,CglibMethodInvocation的proceed方法只是调用了一下父类的proceed方法。

结合静态代理的半动态化版代码,Spring中动态代理实现AOP功能的原理已经差不多明了。

由下往上梳理几个关键接口

整个过程中,只有Advisor是从BeanFactory中批量获取到的,意味着在上面这套体系中我们的切入点就是Advisor,但体系中在确认是Advisor之后,又会以是否为PointcutAdvisor或者IntroductionAdvisor对象进行分类区分处理,所以我们可以通过实现PointcutAdvisor或者IntroductionAdvisor接口的方式来实现AOP功能,最简单的处理方式:

@Component
public class TestAdvisor implements PointcutAdvisor {
    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {
            @Override
            public ClassFilter getClassFilter() {
                return new ClassFilter() {
                    @Override
                    public boolean matches(Class<?> clazz) {
                        return clazz == TestController.class;
                    }
                };
            }

            @Override
            public MethodMatcher getMethodMatcher() {
                return new MethodMatcher() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return true;
                    }

                    @Override
                    public boolean isRuntime() {
                        return true;
                    }

                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        return true;
                    }
                };
            }
        };
    }

    @Override
    public Advice getAdvice() {
        return new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println(method.getName());
            }
        };
    }

    @Override
    public boolean isPerInstance() {
        return true;
    }
}

Pointcut负责判断是否需要动态代理,也就是切面判定,Advice负责处理通知,两者一起组成一个Advisor。其他更细致化的功能介绍如AspectJExpressionPointcut(表达式化定义切面),MethodBeforeAdvice(方法前置通知)等。

以上是Spring提供的基于接口开发的AOP相关功能的实现体系,具有一定的代码入侵性,需要开发者比较了解spring内部的API。

Spring还集成了aspectjweaver基于注解体系的AOP开发方式。

在引入aspectjweaver.jar包的同时需要引入spring-aspects包

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

这时候最简单的AOP实现如下:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class TestAop {

    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    public void pointcut() {

    }

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println(joinPoint.getSignature().getName());

    }
}

在引入aspectjweaver包后,AopAutoConfiguration引入的为CglibAutoProxyConfiguration,而CglibAutoProxyConfiguration上的EnableAspectJAutoProxy注解Import引入AspectJAutoProxyRegistrar,AspectJAutoProxyRegistrar通过AopConfigUtils向BeanDefinitionRegistry注册了AnnotationAwareAspectJAutoProxyCreator,并设置其proxyTargetClass属性和exposeProxy属性为EnableAspectJAutoProxy注解配置值,@EnableAspectJAutoProxy注解可以在主引导类上进行手动配置。

AnnotationAwareAspectJAutoProxyCreator除了会将正常的实现Advisor接口的bean同样进行处理,还会将beanFactory中所有有Aspect注解的class进行解析,查找class中带有@Pointcut注解的方法,获取@Pointcut中的切面el表达式信息,包装成AspectJExpressionPointcut,查找class中带有@Around,@Before,@After,@AfterReturning,@AfterThrowing注解的方法并包装成对应的Advice:AspectJAroundAdvice,AspectJMethodBeforeAdvice,AspectJAfterAdvice,AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice,最后组成Advisor:InstantiationModelAwarePointcutAdvisorImpl

 

有一个小细节:

如何使被代理类的对象能够获取到代理对象?

设置EnableAspectJAutoProxy注解exposeProxy属性为true 或者调用AopConfigUtils.forceAutoProxyCreatorToExposeProxy进行设置。代理对象会被存放到ThreadLocal中,通过AopContext.currentProxy()方法,被代理类的对象中可以获取到代理对象,进行方法调用时切面通知,数据库事务依然正常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
视频详细讲解,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 1、课程简介 Spring框架是一系列应用框架的核心,也可以说是整合其他应用框架的基座。同时还是SpringBoot的基础。在当下的市场开发环境Spring占据的地位是非常高的,基本已经成为了开发者绕不过去的框架了。它里面包含了SpringSpringMVC,SpringData(事务),SrpingTest等等。 其Spring本身里面包含了两大核心IOC和AOP。IOC负责降低我们代码间的依赖关系,使我们的项目灵活度更高,可复用性更强。AOP是让方法间的各个部分更加独立,达到统一调用执行,使后期维护更加的方便。 SpringMVC本身是对Servlet和JSP的API进行了封装,同时在此基础上进一步加强。它推出的一套注解,可以降低开发人员的学习成本,从而更轻松的做表现层开发。同时,在3.x版本之后,它开始之初Rest风格的请求URL,为开发者提供了开发基于Restful访问规则的项目提供了帮助。 SpringData是一组技术合集。里面包含了JDBC,Data JPA,Data Redis,Data Mongodb,Data Rabbit,Data ElasticSearch等等。合集的每一项都是针对不同数据存储做的简化封装,使我们在操作不同数据库时,以最简洁的代码完成需求功能。 SpringTest它是针对Junit单元测试的整合。让我们在开发以及开发后期进行测试时,直接使用Junit结合spring一起测试。 本套课程,我们将全面剖析SpringSpringMVC两个部分。从应用场景分析,到基本用法的入门案例,再到高级特性的分析及使用,最后是执行原理的源码分析。让学生通过学习本套课程不仅可以知其然,还可以知其所以然。最终通过一个综合案例,实现灵活运用Spring框架的各个部分。 2、适应人群 学习spring,要有一定的Java基础,同时应用过spring基于xml的配置。(或者学习过官网的Spring课程) 学习springmvc,要有一定java web开发基础。同时对spring框架要有一定了解。 3、课程亮点 系统的学习Spring框架各个部分,掌握Spring一些高级特性的使用。 l Spring IoC n 设计模式-工厂模式 n 基础应用-入门案例 n 基础应用-常用注解使用场景介绍及入门 n 高级特性-自定义BeanNameGenerator n 高级特性-自定义TypeFilter n 高级特性-ImportSelector和ImportBeanDefinitionRegistrar的分析 n 高级特性-自定义ImportSelector n 高级特性-FilterType的AspectJTypeFilter的使用 n 高级特性-自定义ImportBeanDefinitionRegistrar n 高级特性-自定义PropertySourceFactory实现解析yaml配置文件 n 源码分析-BeanFactory类视图和常用工厂说明 n 源码分析-AnnotationConfigApplicationContext的register方法 n 源码分析-AnnotationConfigApplicationContext的scan方法 n 源码分析-AbstractApplicationContext的refresh方法 n 源码分析-AbstractBeanFactory的doGetBean方法 l Spring Aop n 设计模式-代理模式 n 编程思想-AOP思想 n 基础应用-入门案例 n 基础应用-常用注解 n 高级应用-DeclareParents注解 n 高级应用-EnableLoadTimeWeaving n 源码分析-@EnableAspectJAutoproxy注解加载过程分析 n 源码分析-AnnotationAwareAspectJAutoProxyCreator n 技术详解-切入点表达式详解 l Spring JDBC n 基础应用-JdbcTemplate的使用 n 源码分析-自定义JdbcTemplate n 设计模式-RowMapper的策略模式 n 高级应用-NamedParameterJdbcTemplate的使用 n 源码分析-TransactionTemplate n 源码分析-DataSourceUtils n 源码分析-TransactionSynchronizationManager

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值