spring aop的实现_ssh框架工作原理及流程Spring的AOP实现原理,酝酿了一些日子,写博客之前信心不是很足,所以重新阅读了一边AOP的实现核心代码,而且又从网上找了一些SpringAop剖析的例子,但是发现挂羊头买狗肉的太多,标题高大上,内容却大部分都是比较浅显的一些介绍,可能也是由于比较少人阅读这部分的核心代码逻辑把,然后写这部分介绍的人估计也是少之又少,不过说实话,SpringAop的核心原理实现介绍确实不太好写,里面涉及的类
大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。 Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
Spring的AOP实现原理,酝酿了一些日子,写博客之前信心不是很足,所以重新阅读了一边AOP的实现核心代码,而且又从网上找了一些Spring Aop剖析的例子,但是发现挂羊头买狗肉的太多,标题高大上,内容却大部分都是比较浅显的一些介绍,可能也是由于比较少人阅读这部分的核心代码逻辑把,然后写这部分介绍的人估计也是少之又少,不过说实话,Spring Aop的核心原理实现介绍确实不太好写,里面涉及的类之间的调用还是蛮多的,关系图画的太细的画也很难画,而且最重要的一点就是,如果对AOP的概念以及spring的xml的解析,标签的解析,注解实现,还有java的代理,这些知识没有好好的理解的话也不可能对AOP的实现详细逻辑有一个好的理解。所以的话,建议是把这些前置知识都大概了解了,再来看这个AOP的实现,或者去阅读源代码,那样的话学习 起来会容易的多。
学习源代码的过程比较枯燥,尤其是spring比较严谨,调用层次比较多,没有画时序图的话可能真的被绕晕,所以建议学的时候还是画画时序图,然后跟着debug模式流程走一遍。
首先我们来热热身吧,先看看AOP的简介,待会再进入主题,
AOP简介
概念
切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。 连接点(Joinpoint) :程序执行过程中的某一行为。 通知(Advice) :“切面”对于某个“连接点”所产生的动作。 切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。 目标对象(Target Object) :被一个或者多个切面所通知的对象。 AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。
通知(Advice)类型 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在<aop:aspect>里面使用<after-returning>元素进行声明。 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。
切入点表达式 :如execution(* com.spring.service.*.*(..))
特点
1、降低模块之间的耦合度
2、使系统容易扩展
3、更好的代码复用。
动态AOP使用示例
由于在之前的博客,已经介绍过spring源码剖析(五)利用AOP实现自定义Spring注解 里面有介绍到AOP 的简单使用,相信大家要看这个AOP的原理的也对AOP的使用比较熟悉了,所以在这里也不再重复展示了。
动态AOP自定义标签
我之前的博客中有说到,如何自定义Spring标签的,以及自定义Spring标签的大概解析流程,其实这里的AOP的标签的定义也和之前的逻辑类似,先上时序图把:
时序图
流程说明
1)AOP标签的定义解析刘彻骨肯定是从NamespaceHandlerSupport的实现类开始解析的,这个实现类就是AopNamespaceHandler。至于为什么会是从NamespaceHandlerSupport的实现类开始解析的,这个的话我想读者可以去在回去看看Spring自定义标签的解析流程,里面说的比较详细。
2)要启用AOP,我们一般会在Spring里面配置<aop:aspectj-autoproxy/> ,所以在配置文件中在遇到aspectj-autoproxy标签的时候我们会采用AspectJAutoProxyBeanDefinitionParser解析器
3)进入AspectJAutoProxyBeanDefinitionParser解析器后,调用AspectJAutoProxyBeanDefinitionParser已覆盖BeanDefinitionParser的parser方法,然后parser方法把请求转交给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理
4)进入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法后,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,里面在转发调用给registerOrEscalateApcAsRequired,注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。
5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法处理完成之后,接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性。如果将proxy-target-class设置为true的话,那么会强制使用CGLIB代理,否则使用jdk动态代理,expose-proxy属性是为了解决有时候目标对象内部的自我调用无法实现切面增强。
6)最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。
创建AOP代理
上面说到AOP的核心逻辑是在AnnotationAwareAspectJAutoProxyCreator类里面实现,那么我们先来看看这个类的层次关系
我们可以看到这个类实现了BeanPostProcessor接口,那就意味着这个类在spring加载实例化前会调用postProcessAfterInitialization方法,对于AOP的逻辑也是由此开始的。
时序图
流程说明
1)spring 容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization()这个方法,然后接下来是调用wrapIfNecessary方法。
public Object <strong>postProcessAfterInitialization</strong>(Object bean, String beanName) throws BeansException {
if (bean != null ) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (! this .earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
2)进入wrapIfNecessary方法后,我们直接看重点实现逻辑的方法getAdvicesAndAdvisorsForBean,这个方法会提取当前bean 的所有增强方法,然后获取到适合的当前bean 的增强方法,然后对增强方法进行排序,最后返回。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this .targetSourcedBeans.containsKey(beanName)) {
return 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;
}
Object[] specificInterceptors = <strong>getAdvicesAndAdvisorsForBean</strong>(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;
}
3)获取到当前bean的增强方法后,便调用createProxy方法,创建代理。先创建代理工厂proxyFactory,然后获取当前bean 的增强器advisors,把当前获取到的增强器添加到代理工厂proxyFactory,然后设置当前的代理工的代理目标对象为当前bean,最后根据配置创建JDK的动态代理工厂,或者CGLIB的动态代理工厂,然后返回proxyFactory
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this );
if (!shouldProxyTargetClass(beanClass, beanName)) {
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.<strong>setTargetSource</strong>(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this .freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true );
}
return proxyFactory.getProxy( this .proxyClassLoader);
}
AOP动态代理执行
接下来,我们先来看看AOP动态代理的实现选择方式,先上核心实现代码:
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 JDK动态代理实现
在上面的第三步骤说道或根据用户的配置(例如是否配置了
proxyTargetClass 属性为true),选择创建的代理类型,这个的代理类型分两种实现,都是比较高效的,下面根据JDK的动态代理来说明AOP的执行,也是先上JdkDynamicAopProxy的核心代码invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
MethodInvocation invocation = null ;
Object oldProxy = null ;
boolean setProxyContext = false ;
TargetSource targetSource = this .advised.targetSource;
Class targetClass = null ;
Object target = null ;
try {
if (! this .equalsDefined && AopUtils.isEqualsMethod(method)){
return (equals(args[ 0 ])? Boolean.TRUE : Boolean.FALSE);
}
if (! this .hashCodeDefined && AopUtils.isHashCodeMethod(method)){
return newInteger(hashCode());
}
if (! this .advised.opaque &&method.getDeclaringClass().isInterface()
&&method.getDeclaringClass().isAssignableFrom(Advised.class )) {
return AopUtils.invokeJoinpointUsingReflection( this .advised,method, args);
}
Object retVal = null ;
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 {
invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
if (retVal != null && retVal == target &&method.getReturnType().isInstance(proxy)
&&!RawTargetAccess.class .isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
其实上面的注释也说的比较清楚,各个步骤执行的说明:
1)获取拦截器
2)判断拦截器链是否为空,如果是空的话直接调用切点方法
3)如果拦截器不为空的话那么便创建ReflectiveMethodInvocation类,把拦截器方法都封装在里面,也就是执行
getInterceptorsAndDynamicInterceptionAdvice方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
MethodCacheKeycacheKey = new MethodCacheKey(method);
List<Object>cached = this .methodCache.get(cacheKey);
if (cached == null ) {
cached= this .advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this ,method, targetClass);
this .methodCache.put(cacheKey,cached);
}
returncached;
}
4)其实 实际的获取工作其实是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()这个方法来完成的,获取到的结果会被缓存,下面来分析下这个方法的实现:
publicList getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) {
List interceptorList = new ArrayList(config.getAdvisors().length);
boolean hasIntroductions = hasMatchingIntroductions(config,targetClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
for ( int i = 0 ; i <advisors.length; i++) {
Advisor advisor = advisors[i];
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor;
if (config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
MethodInterceptor[]interceptors = registry.getInterceptors(advisor);
MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) {
if (mm.isRuntime()) {
for (intj = 0 ; j < interceptors.length; j++) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],mm));
}
} else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
} else if (advisor instanceof IntroductionAdvisor){
IntroductionAdvisor ia =(IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
Interceptor[] interceptors= registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
} else {
Interceptor[] interceptors =registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
5)这个方法执行完成后,Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor. 6)接下来货到invoke方法中的proceed方法 ,我们再看下得到的拦截器链是怎么起作用的,也就是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)) {
returndm.interceptor.invoke(this );
}
else {
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke( this );
}
}
7)好了拦截器到这边就可以执行了,复杂的代理终于可以起到他的作用了
Spring CGLIB动态代理实现
由于CGLIB的动态代理代码量比较长,在这就不贴出来代码了,其实这两个代理的实现方式都差不多,都是创建方法调用链,不同的是jdk的动态代理创建的是
ReflectiveMethodInvocation 调用链,而cglib创建的是Cglib
MethodInvocation 。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/194072.html 原文链接:https://javaforall.cn
【正版授权,激活自己账号】:
Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】:
官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...