Spring AOP
使用
代理模式就是为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的方法对程序进行扩展,现在常用的动态代理分为cglib和jdk的动态代理
ProxyFactory
当然我们的重点是spring,可以使用spring的代理工厂,内部是基于责任链模式设计的
使用了Advice接口,我们就不需要手动去执行代码了,spring的ProxyFactory自动会我们执行指定的AOP代码
在实际执行的时候,spring会将所有通知都封装为MethodInterceptor
MethodBeforeAdvice 前置通知,实现before方法
AfterReturningAdvice 返回通知,实现afterReturning方法
ThrowsAdvice 异常通知,比较特殊
MethodInterceptor 环绕通知,实现invoke方法
// 目标对象
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
// spring内部默认使用cglib进行动态代理,所以不需要接口
// proxyFactory.setInterfaces(UserService.class);
// 责任链模式
// proxyFactory.addAdvice(new MengnanThrowsAdvice());
// proxyFactory.addAdvice(new MengnanAroundAdvice());
// proxyFactory.addAdvice(new MengnanBeforeAdvice());
// proxyFactory.addAdvice(new MengnanAfterReturningAdvice());
// 除了执行addAdvice也可以执行addAdvisor
// addAdvisor = Pointcut + Advice
proxyFactory.addAdvisor(new PointcutAdvisor() {
@Override
// 切入点
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return targetClass.equals(UserService.class);// 匹配才会执行代理逻辑
}
};
}
@Override
// 执行前置通知
public Advice getAdvice() {
return new MengnanBeforeAdvice();
}
});
UserService proxy = (UserService) proxyFactory.getProxy();
proxy.testA();
异常通知比较特殊,ThrowsAdvice是一个空接口,继承它不需要实现任何方法,需要我们自己实现afterThrowing方法
先不考虑背后的原理,这么设计的好处显而易见,可以通过一个参数捕获指定异常,不过这样的话接口无法明确定义
接口注释上详细说明了可以实现的方法签名
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
public class MengnanThrowsAdvice implements ThrowsAdvice {
// 最后一个参数是NullPointerException,所以只能捕获NullPointerException
public void afterThrowing(Method method, Object[] args, Object target, NullPointerException ex) {
System.out.println("方法执行出现异常!");
}
}
ProxyFactoryBean
ProxyFactory只是一个工具,可以使用ProxyFactoryBean搭配spring的ioc一起使用
@Bean
// 注意不要和userService对象重名
public ProxyFactoryBean userService() {
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.addAdvice(new MengnanBeforeAdvice());
proxyFactoryBean.setTarget(userService);
return proxyFactoryBean;
}
BeanNameAutoProxyCreator
自动代理创建器,内部是基于beanPostProcessor
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
// 类名通配符
beanNameAutoProxyCreator.setBeanNames("user*");
// 匹配拦截器名称
beanNameAutoProxyCreator.setInterceptorNames("mengnanAroundAdvice");
return beanNameAutoProxyCreator;
}
DefaultPointcutAdvisor
只要当前类匹配就自动会对这个类进行动态代理,需要搭配DefaultAdvisorAutoProxyCreator使用
@Bean
// 可以看到这个类和spring中最常用的切面类aspect的使用方式几乎一致,所以DefaultAdvisorAutoProxyCreator源码非常重要
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
// 是否有test方法
pointcut.addMethodName("test");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
// 会执行MengnanBeforeAdvice的代理
defaultPointcutAdvisor.setAdvice(new MengnanBeforeAdvice());
return defaultPointcutAdvisor;
}
@Bean
// 也可以将@Import(DefaultAdvisorAutoProxyCreator.class)写在类上效果一致
// 内部会将所有Advisor的Bean找出来
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
注解
注解也是项目中最常用的使用方式
在spring项目中使用aspectj相关注解需要单独引入
dependencies {
implementation(project(":spring-context"))
implementation(project(":spring-aop"))
// 如果你想使用aspectj相关的注解,你需要单独引入aspectj相关的jar包
implementation group: 'org.aspectj', name: 'aspectjrt', version: '1.9.5'
implementation group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.5'
}
配置类中添加该注解@EnableAspectJAutoProxy
切面类
有如下几种注解
@Before
@After
@Around
@AfterReturning
@AfterThrowing
aspectj是在编译器通过(ajc命令)直接对代码进行增强,然而spring的aop不是,我们还是只需要通过javac进行编译
@Aspect
@Component
// spring解析到该Bean上添加了@Aspect,就知道这是一个切面类
// 开始解析@Before为Pointcut对象,并通过方法得到Advice对象,最后生成Advisor对象
// spring只是内部使用了Aspect的注解,但是底层并没有依靠aspectj而是自己实现
public class MengnanAspect {
@Before("execution(public void info.mengnan.service.UserService.test())")
public void mengnanBefore() {
System.out.println("mengnanBefore");
}
}
通过以上几种方式中的一种,就可以从ioc容器中直接获取代理对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从spring中获取代理了UserService的ProxyFactoryBean,执行代理逻辑
// 或者使用BeanNameAutoProxyCreator自动从spring获取被代理的对象和Advice实现代理
UserService userService = context.getBean("userService", UserService.class);
userService.test();
源码
ProxyFactory
ProxyFactory内部会将userService封装为一个TargetSource,TargetSource就是被代理对象
当我们执行完切面逻辑后会通过getTarget拿到被代理对象并执行方法
UserService userService = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
// 设置代理对象
proxyFactory.setTarget(userService);
// 添加切面逻辑
proxyFactory.addAdvice(new MengnanAfterReturningAdvice());
// 获取代理对象
UserService proxy = (UserService) proxyFactory.getProxy();
执行getProxy最终会执行createAopProxy方法,spring为我们自动选择是使用jdk的动态代理还是cglib的动态代理
其中就有对应的2个实现类
JdkDynamicAopProxy
ObjenesisCglibAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果你在ProxyFactory设置optimize为true,需要更好的性能
// ProxyFactory的proxyTargetClass设置为true并且@EnableAspectJAutoProxy的属性proxyTargetClass为false(默认为false)
// ProxyFactory没有addInterface
if (config.isOptimize() || config.isProxyTargetClass() || !config.hasUserSuppliedInterfaces()) {
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.");
}
// 被代理的对象是一个接口
// 判断是不是当前jdk生成的代理类
// 是否是lambda
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
基于Cglib的动态代理
private Object buildProxy(@Nullable ClassLoader classLoader, boolean classOnly) {
try {
// 拿到被代理的类targetClass
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
// 如果被代理的类本身就是cglib所生成的代理类
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
validateClassIfNecessary(proxySuperClass, classLoader);
// 创建cglib Enhancer
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader smartClassLoader &&
smartClassLoader.isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 被代理的类继承了代理类
enhancer.setSuperclass(proxySuperClass);
// 设置接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setAttemptLoad(true);
enhancer.setStrategy(KotlinDetector.isKotlinType(proxySuperClass) ?
new ClassLoaderAwareGeneratorStrategy(classLoader) :
new ClassLoaderAwareGeneratorStrategy(classLoader, undeclaredThrowableStrategy)
);
// 获取和被代理类所匹配的Advisor
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
ProxyCallbackFilter filter = new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset);
enhancer.setCallbackFilter(filter);
enhancer.setCallbackTypes(types);
try {
// classOnly为false返回创建代理对象
// classOnly一般情况下都为false
return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks));
}
finally {
filter.advised.reduceToAdvisorKey();
}
}
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) {
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
基于jdk的动态代理
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 {
// 如果接口中没有定义equals方法、hashCode方法则执行调用不走代理
if (!this.cache.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.cache.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果ProxyFactory的exposeProxy属性设置为true
if (this.advised.exposeProxy) {
// 则会将代对象存储在ThreadLocal中
// 如果是同一个线程可以通过AopContext.currentProxy()拿到代理对象
// 可以通过这个方法测试是否是事物失效
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 拿到被代理对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 代理对象在执行某个方法时,根据方法筛选出匹配的Advisor
// 详见[获取调用链路]
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 为空,直接执行被代理对应方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 封装为MethodInvocation对象
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行代理逻辑
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != void.class && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
if (coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(method)) {
return COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName()) ?
CoroutinesUtils.asFlow(retVal) : CoroutinesUtils.awaitSingleOrNull(retVal, args[args.length - 1]);
}
// 返回
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
不论是jdk的动态代理还是cglib的动态代理都会经历2个步骤
获取调用链路
执行代理逻辑
获取调用链路
执行ProxyFactory创建代理之前,拿到所有的Advisor并进行封装,并和当前正在执行的方法进行匹配
2种代理模式都会执行该方法来获取往内部添加的advice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 找出所有的Advisor
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
// 遍历Advisor通过Pointcut找到符合的Advice
// Advisor包含Pointcut + Advice
// 如果只调用了addAdvice内部也会赋值一个默认的Pointcut(Pointcut.TRUE所有都匹配)
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor pointcutAdvisor) {
// Pointcut内部需要实现getClassFilter(类匹配)和getMethodMatcher(方法匹配)方法
// 先匹配类
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 再匹配方法
if (mm instanceof IntroductionAwareMethodMatcher iamm) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = iamm.matches(method, actualClass, hasIntroductions);
}
// 实现getMethodMatcher方法需要传递MethodMatcher对象
// MethodMatcher需要传递MethodMatcher对象,MethodMatcher需要实现2个参数的matches方法
// 如果为true说明匹配方法
else {
match = mm.matches(method, actualClass);
}
// 如果匹配方法
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
// MethodMatcher对象还需要实现,isRuntime和3个参数的matches方法
// 这个matches方法可以在运行时传递的入参args是否匹配
// 是否设置为运行时
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
// 如果是运行时再封装一层 拦截器和动态方法匹配器
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 不匹配则忽略
}
}
else if (advisor instanceof IntroductionAdvisor ia) {
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
动态匹配
运行时匹配,使用DynamicMethodMatcherPointcut,这个时候isRuntime方法默认返回true
如果使用StaticMethodMatcherPointcut,isRuntime返回false,并且被final修饰
proxyFactory.addAdvisor(new PointcutAdvisor() {
@Override
public Pointcut getPointcut() {
return new DynamicMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return method.getName().equals("test");;
}
};
}
@Override
public Advice getAdvice() {
return new MengnanBeforeAdvice();
}
});
执行代理逻辑
把和当前方法匹配的advised,调用ReflectiveMethodInvocation的构造方法,把和方法所匹配的Advisor封装成MethodInterceptor
最后执行ReflectiveMethodInvocation的proceed方法,执行各个MethodInterceptor以及被代理对象的对应方法
按顺序调用每个invoke方法,并通过this将当前MethodInterceptor继续传递到下一个代理逻辑中
执行完最后一个MethodInterceptor执行invokeJoinpoint,执行被代理对象的当前方法
public Object proceed() throws Throwable {
// currentInterceptorIndex的初始值为-1
// interceptorsAndDynamicMethodMatchers就是调用链路拦截器advised
// 执行到最后一个执行被代理对象的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 取出第一个,并且执行自增操作,直到拿到最后一个
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 是否继承了InterceptorAndDynamicMethodMatcher
// 在获取调用链路发现methodMatcher的isRuntime代码中,如果为true就会封装为InterceptorAndDynamicMethodMatcher
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
// 根据方法动态进行匹配,如果匹配才会继续执行
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.matcher().matches(this.method, targetClass, this.arguments)) {
return dm.interceptor().invoke(this);
}
else {
// 否则跳过本链路
return proceed();
}
}
else {
// 没有继承,执行MethodInterceptor的invoke方法(每个invoke方法内部都会执行proceed)
// 如果是MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor
// 执行并进入调用链路(传递的是this)
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}