SpringAOP
- 前言
- AOP基础
- ProxyFactory
- Pointcut
- Advisor
- ProxyFactory策略选择
- JDK策略的执行流程
- Cglib策略的执行流程
- @EnableAspectJAutoProxy
- AnnotationAwareAspectJAutoProxyCreator
前言
SpringAOP的原理是动态代理,动态代理又分为JDK动态代理
和Cglib动态代理
,这些想必大家已经知道了,所以不再赘述动态代理相关内容,此处为大家提供两种代理的示例代码
JDK动态代理
public static void jdkDynamicProxy() {UserServiceInterface userService = new UserService();UserServiceInterface proxyInstance = (UserServiceInterface) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{UserServiceInterface.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法执行前");Object result = method.invoke(userService, args);System.out.println("方法执行后");return result;}});proxyInstance.test1();}
Cglib动态代理
public static void cglibDynamicProxy() {UserService userService = new UserService();Enhancer enhancer =new Enhancer();enhancer.setSuperclass(UserService.class);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("方法执行前");Object result = method.invoke(userService, objects);System.out.println("方法执行后");return result;}});UserService proxyBean = (UserService) enhancer.create();proxyBean.test1();}
AOP基础
ProxyFactory
在Spring中,不会直接使用JDK动态代理或者Cglib动态代理,而是基于这两种动态代理封装了一个更高级的功能:ProxyFactory
public static void proxyFactoryDemo() {ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(new UserService());proxyFactory.addAdvice((org.aopalliance.intercept.MethodInterceptor) invocation -> {System.out.println("方法执行前");Object result = invocation.proceed();System.out.println("方法执行后");return result;});UserService userService = (UserService) proxyFactory.getProxy();userService.test1();}
那么ProxyFactory
有哪些好处呢?
- 不用关注底层具体实现,不需要操心是JDK动态代理还是Cglib动态代理
TargetSource
功能,对被代理对象封装,提供更丰富的操作- 除了
MethodInterceptor
这一种Advice还有许多,例如AfterAdvice、AfterReturningAdvice - 提供
Pointcut
功能,灵活配置切入点
Pointcut
Pointcut
(切入点)配置了代理生效的范围:
- ClassFilter,哪些类生效
- MethodMatcher,哪些方法生效
我们使用AspectJ时配置的Pointcut
表达式最终就会被解析成Pointcut
Advisor
由Advice
和Pointcut
组成,Advice
就是代理的逻辑内容。
可以往ProxyFactory
中添加Advisor
proxyFactory.addAdvisor(new Advisor() {@Overridepublic Advice getAdvice() {return null;}@Overridepublic boolean isPerInstance() {return false;}});
在项目启用AOP的前提下,我们往容器中注入Advisor
,符合条件的方法就会被代理
@Component
public class CustomsAdvisor implements PointcutAdvisor {@Overridepublic Pointcut getPointcut() {return new Pointcut() {@Overridepublic ClassFilter getClassFilter() {return clazz -> {for (Class<?> aClass : clazz.getClasses()) {if(aClass.equals(OrderService.class)){return true;}}return false;};}@Overridepublic MethodMatcher getMethodMatcher() {return MethodMatcher.TRUE;}};}@Overridepublic Advice getAdvice() {return (MethodInterceptor) invocation -> {System.out.println("before");return invocation.proceed();};}@Overridepublic boolean isPerInstance() {return false;}
}
ProxyFactory策略选择
当调用ProxyFactory.getProxy时会走到org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
方法
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);}}
- 如果ProxyFactory设置
isOptimize
为true或者设置proxyTargetClass
为true,则强制使用cglib代理 - 如果代理的目标类没有实现接口,使用cglib代理
- 如果代理的目标类就是一个接口,使用jdk代理
- 如果代理的目标类是Jdk生成的代理类,则使用jdk代理
简单来说,具体选择哪种策略主要看目标类有没有实现接口
JDK策略的执行流程
public Object getProxy(@Nullable ClassLoader classLoader) {return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);}
传入的InvocationHandler
是JdkDynamicAopProxy
本身,所以我们看invoke
方法
- 如果当前方法是equals、hscode等,不执行代理逻辑
- 如果设置了exposeProxy,将代理对象设置到ThreadLocal中
if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}
- 获取针对当前方法符合条件的MethodIntercepter集合
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
a. 获取proxy中设置的所有Advisor
b. 根据ClassFilter和MethodMatcher过滤
c. AdvisorAdapterRegistry
将Advisor进行适配,适配成MethodInterceptor
这个地方巧妙使用了适配器模式
和策略模式
AdvisorAdapterRegistry
中注册了以下几种适配器
public DefaultAdvisorAdapterRegistry() {registerAdvisorAdapter(new MethodBeforeAdviceAdapter());registerAdvisorAdapter(new AfterReturningAdviceAdapter());registerAdvisorAdapter(new ThrowsAdviceAdapter());}
可以将MethodBeforeAdvice
、AfterReturningAdvice
、ThrowsAdvice
都转换成MethodInterceptor
- 将执行链封装成
ReflectiveMethodInvocation
,非常巧妙的使用递归完成整个调用链的传递 - 在执行MethodInterceptor的invoke方法时,将本身传了进去
Cglib策略的执行流程
- 创建
Enhancer
对象 - 设置suplierClass为代理的类
- 设置Callback为
DynamicAdvisedInterceptor
- 当执行代理方法时会进入到
DynamicAdvisedInterceptor
的intercept
方法
@EnableAspectJAutoProxy
@EnableAspectJAutoProxy
注解会Import一个配置类AspectJAutoProxyRegistrar
,这个配置类实现了ImportBeanDefinitionRegistrar
接口,向容器中注册了AnnotationAwareAspectJAutoProxyCreator
的Bean
AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
是一个BeanPostProcessor,在初始化后方法postProcessAfterInitialization
中,如果必要会对当前Bean生成代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 表示已经生成过代理,跳过处理if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// advisedBeans表示已经判断过了的bean,false表示此bean不需要进行Aopif (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}// 如果是AOP基础设施Bean,不用代理if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.// 判断当前bean是否存在匹配的advice,如果存在则要生成一个代理对象// 此处根据类以及类中的方法去匹配到Interceptor(也就是Advice),然后生成代理对象,代理对象在执行的时候,还会根据当前执行的方法去匹配Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {// advisedBeans记录了某个Bean已经进行过AOP了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;}
AbstractAutoProxyCreator
这个类为Spring提供了AOP功能,使其能够处理容器中的Advisor;
而AnnotationAwareAspectJAutoProxyCreator
这个类则提供了解析AspectJ注解的能力,使其能够将容器中的切面解析成Advisor