Spring5AOP——BeanPostProcessor

Spring5AOP——BeanPostProcessor,第1张

Bean的后置处理器,首先来说,他是Spring中抽象出来的一个顶级的接口,他里面有如下两个方法

简单点来理解,就是spring会自动从它的所有的bean定义中检测BeanPostProcessor类型的bean定义,然后实例化它们,再将它们应用于随后创建的每一个bean实例,在bean实例的初始化方法回调之前调用BeanPostProcessor的postProcessBeforeInitialization的方法(进行bean实例属性的填充),在bean实例的初始化方法回调之后调用BeanPostProcessor的postProcessAfterInitialization的方法(可以进行bean实例的代理封装)。

大家说它是Spring对外提供的拓展点,也许是因为,通过实现这个接口,程序员可以对Spring管理的bean的生命周期进行插手。

这也体现了AOP的设计思想,就比如在init()方法执行前后做出不同的动作,其实就是对bean的一种增强。

此外BeanPostProcessor可以存在多个。他们会被存储在一个列表中。然后依次被执行。

所谓的注册,只不过是对当前上下文中所有的BeanPostProcessor进行一种集中式管理罢了,为什么非得这么做呢 因为上下文中BeanPostProcessor的数量不是一成不变的,Spring为了启动的正常,需要添加原生的BeanPostProcessor,程序员因为自己的需求也会添加不同数量的bean的后置处理器,因此需要这种策略将上下文中所有的后置处理器进行统一的管理,方便回调。

Spring作为一个优秀的框架,拥有良好的可扩展性。Spring对对象的可扩展性主要就是依靠InstantiationAwareBeanPostProcessor和BeanPostProcessor来实现的。

AnnotationConfigApplicationContext构造方法中调用refresh()方法

refresh() 方法中这里主要关心两个方法:

通过beanFactorygetBeanNamesForType来获取所有BeanPostProcessor。

BeanPostProcessor按优先级分为PriorityOrdered,Ordered和其他的,对他们分别进行 *** 作。

InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法,该方法主要是在bean实例化之后,并且在其被设置上属性值之前去进行调用,用来判断是否继续去执行对属性赋值的流程,方法返回true,即默认情况下都会去执行populateBean方法,对Bean的属性进行赋值。

postProcessAfterInstantiation方法调用是在populateBean方法中,这里从doCreateBean方法进入。

在populateBean方法中,在对bean的属性进行真正赋值之前,会依次调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法。

什么是IoC

Ioc—Inversion of

Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

控制是什么:传统Java

SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC

容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

IoC能做什么

IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。

IoC和DI

DI—Dependency

Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

注:如果想要更加深入的了解IoC和DI,请参考大师级人物Martin Fowler的一篇经典文章《Inversion of Control

Containers and the Dependency Injection

pattern》,原文地址:>

AOP:面向切面编程

什么是AOP:

概念:在软件业,AOP为Aspect Oriented

Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(百度百科)

简单的说:就是将程序中重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

AOP的作用和优势:

作用:从定义中来看,就是为了在程序运行期间,不修改源码对已有方法进行增强。

优势:减少重复代码 提交了开发效率 维护方便

实现方式: 就是动态代理的技术

具体的作用:实现事务的控制 日志 和 安全模块

想系统的学习编程可以来我这看看,希望对您有所帮助!~

访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点。JoinPoint里包含了如下几个常用的方法:Object[]getArgs:返回目标方法的参数SignaturegetSignature:返回目标方法的签名ObjectgetTarget:返回被织入增强处理的目标对象ObjectgetThis:返回AOP框架为目标对象生成的代理对象注意:当使用@Around处理时,我们需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。

下图是AOP自动代理的流程图

spring中已经定义了创建代理的工厂类 ProxyFactory,通过 ProxyFactory 创建代理,必须要一个被代理对象和一个增强Advisor列表

spring的动态代理实质就是对象创建完毕之后,查找筛选能够应用于该对象上的Advisor列表,然后调用ProxyFactory创建代理对象返回。

Spring中定义了 AbstractAutoProxyCreator 类用于实现自动代理。

从继承图可以看出该类实现了 BeanPostProcessor 接口,覆写了postProcessAfterInitialization 方法。spring的bean初始化完成后会遍历注册的所有BeanPostProcessor实现类对象,调用其postProcessAfterInitialization方法,该方法可以返回一个新的对象覆盖原有对象,在此spring提供一个创建代理并覆盖被代理对象的机会

遍历容器中注册的所有BeanPostProcessor,调用postProcessAfterInitialization方法,如果返回一个新的对象会覆盖掉原始对象注册到spring容器中

上面分析了AbstractAutoProxyCreator是实现自动代理的关键,那么在spring中如何配置一个AbstractAutoProxyCreator的实现类对象呢,spring又是如何根据配置注册该对象的

在spring中可以通过两种配置,启动自动代理

这两中方法最终都是向spring容器中注册了一个AnnotationAwareAspectJAutoProxyCreator实例,这样在spring初始化完对象后就可以调用AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法了

上面分析了spring是在何时何处开始创建代理的,解下来分析AbstractAutoProxyCreator进行自动代理的总体实现

在postProcessAfterInitialization方法中判断 被代理对象不为空,调用wrapIfNecessary判断是否对目标类进行代理

createProxy方法中通过ProxyFactory设置AOP配置,如被代理对象和Advisor列表,调用getProxy创建代理对象。

至此AbstractAutoProxyCreator完成了自动创建代理的总体实现,在该抽象类中没有实现获取Adviso列表r的功能,交由各个子类去实现。

分析完spring自动代理的整体实现,接下来看下AbstractAutoProxyCreator的子类AbstractAdvisorAutoProxyCreator是如何进行查找 Advisor、筛选Advisor、排序Advisor的。

AbstractAdvisorAutoProxyCreator实现了getAdvicesAndAdvisorsForBean方法,用于获取应用于目标类的Advisor列表

在findEligibleAdvisors方法定义了查找 Advisor、筛选Advisor、排序Advisor三步 *** 作

在spring中可以通过注册Advisor的bean来实现对目标类的增强代理。spring会筛选出容器中所有Advisor类型的bean,用于对容器中的对象进行增强代理,查找的功能由AbstractAdvisorAutoProxyCreator类实现

将查找功能委托给advisorRetrievalHelper(BeanFactoryAdvisorRetrievalHelperAdapter)实现,该方法的功能就是获取Advisor类型的bean对象返回

spring除了支持配置或者手动注册 Advisor类型的bean之外,还支持通过 @Aspect、@Before、@After等AOP注解来声明Advisor。Advisor的查找解析由子类AnnotationAwareAspectJAutoProxyCreator实现

在AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法中,第一步首先调父类的方法获取到容器中注册的所有Advisor,然后再委托aspectJAdvisorsBuilder解析注解获取Advisor,然后合并两个结果返回

BeanFactoryAspectJAdvisorsBuilderbuildAspectJAdvisors方法解析AOP注解封装为Advisor对象。

spring定义了一个AspectJAdvisorFactory接口用于解析AOP的注解,接口主要定义了两个功能

AspectJAdvisorFactory的实现类ReflectiveAspectJAdvisorFactory提供了具体实现

调用getAdvisor方法,获取通知方法上的Pointcut表达式,如果在方法上未解析到Pointcut,则跳过,然后根据通知方法和对应Pointcut封装返回一个Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl对象

解析获取通知方法的Pointcut表达式,在该方法中会过滤掉不带Aop注解的非通知型方法,判断一个方法是不是通知就是判断该方法是否声明了切点

最终封装返回的Advisor是InstantiationModelAwarePointcutAdvisorImpl类型,在该实现类的getAdvice方法会回调ReflectiveAspectJAdvisorFactory中的getAdvice方法,ReflectiveAspectJAdvisorFactory会根据通知方法上不同的注解,创建对应的Advice

回调ReflectiveAspectJAdvisorFactory中的getAdvice,策略创建对应的Advice实现类对象

获取到spring容器中所有的Advisor之后,再回到AbstractAdvisorAutoProxyCreator类中,接下来筛选能够应用到目标对象的Advisor。通过Advisor中的Pointcut的ClassFilter和MethodMatcher来对目标对象进行匹配。 在这个阶段的筛选,只要Advisor能应用到目标类型的任意一个方法上都会返回成功

接下来看AbstractAdvisorAutoProxyCreatorfindAdvisorsThatCanApply方法,将筛选的工作委托给AopUtils来实现

AopUtilsfindAdvisorsThatCanApply方法中遍历所有的Advisor,然后调用canApply方法判断是否符合,在当中会区分引介增强和切点增强,引介增强是类级别的,只需要根据切点的ClassFilter对目标类进行判断就行。

canApply方法中,通过Pointcut来进行匹配,引介增强IntroductionAdvisor直接根据其ClassFilter判断目标类型,PointcutAdvisor根据其中的Pointcut来进行筛选

Pointcut会首先使用ClassFilter对目标类型进行过滤。如果通过,再使用 MethodMatcher 校验 类中所有的方法,只要有一个方法匹配上,代表该Advisor符合条件。

在这里宁可多通过,也不要校验太严格,因为在代理类中具体方法执行的时候,还会再一次使用Pointcut进行校验。所以该方法中会获取目标类型的所有接口,判断接口中的方法,有一个符合也会返回true

当获取到目标类型上的所有Advisor后,还需要对Advisor进行排序。Advisor的顺序决定了通知方法的应用顺序。

Advisor的排序主要分为两种

接下来看下spring是怎么实现排序的

AbstractAdvisorAutoProxyCreatorsortAdvisors提供了基于Ordered的排序,由spring的AnnotationAwareOrderComparator统一处理Ordered实现类或者添加@Ordered注解类的排序

AspectJAwareAdvisorAutoProxyCreator覆写了父类的sortAdvisors方法,在基于Ordered排序基础上提供了同一切面下不同通知之间的排序,具体排序实现委托给了PartialOrder

至此完成Advisor的查找、筛选、排序。

一、概述

java应用系统设计过程中,用户认证、用户授权、鉴权是绕不过去的话题。

如果这个权限管理的设计,没有做到与业务系统的隔离,拓展性不够强,很容易就会拖后腿。

这个问题应该做过开发的同学都会有所体会。

现在网络上的各种关于权限管理的框架比较主流的有 Apache Shiro,Spring Security,Sa-Token(新兴起的一个优秀框架)。

这里会有同学说,既然已经有这么多的成熟优秀的权限管理框架,为什么还有再给大家介绍这种实现思路。

在本人工作和学习的过程中,经常会使用这些优秀的权限管理框架。

但是,一旦是这些三方框架出现的异常和问题,想要排查,就比较麻烦。要么就是靠着百度大家的经验。要么就是猛扒代码,一点点去排查。

三方框架对于我们使用者来说,就像是一个黑盒。这一点一直让我觉得有点不顺畅。

同学们,谁不想要一个自己知根知底的的权限管理框架呢。

二、框架使用体验

21 项目初始化配置

Springboot老三样。

引入pom依赖:

修改配置文件:

22 用户登录

自定义一个凭证类

自定义一个凭证类认证器:

这个认证器很简单 就是默认admin 密码 123456 然后给与了固定的角色和全部的资源。实际应用中应该从数据库中获取到用户的权限 并组织返回的securityAuthority。

开放认证接口:

23 权限验证

路由级别鉴权:

不用做其他额外的配置 只需要打上@HasUrl 就会获取到Controller层的当前url地址,并校验用户是否有访问该url的权限。

并将解析后的用户信息放到方法的SecurityAuthority参数中

在第一步用户登录时,默认给了SecurityResallUrlRes() ,则配置了 / 的url访问权限。

方法级别鉴权

验证用户是否登录

三、时间地点人物

想要描述一个事情,都是将时间地点人物介绍完,才能吧事情描述清楚。

介绍这个设计思路也需要介绍前提:

31 什么时候用这个框架

显然,如果系统需要提供用户认证、用户授权、用户鉴权的时候,就需要有一个权限管理的模块。

整个流程应该是:

用户认证 --> 颁发token(用户授权) --> 用户鉴权 --> token回收

32 框架要提供哪些能力

以上能力老生常谈就是最基础的权限管理。

33 框架应该有哪些抽象组件

这个问题是面向对象开发的java程序员必须要好好思考的问题,就是当你接到一个需求时,如何以面向对象的思维来分析和设计程序来完成需求。

331 用户认证

用户认证,最最常见的场景就是用户名密码登录。

在这个场景中可能存在:

用户名+密码、用户名+密码+验证码、手机号+验证码、邮箱+验证码 这么多的登录方式。

而通常来验证这些登录信息是否合法,一般都是要去数据库中读取用户的注册信息来完成认证。

这个场景下可以抽象出来的类有:

1 凭证类:用户名+密码、用户名+密码+验证码、手机号+验证码、邮箱+验证码

2 凭证类验证器:用来验证用户上传的凭证是否是合法的。

332 用户授权

当用户完成认证凭证验证后,服务器应该返回一个用户的口令(token),给用户使用。

并且用户的token应该可以关联并携带出用户绑定的所有资源权限,和角色、部门、岗位等等信息。

用户的资源又分为:

静态资源:

菜单、按钮等静态资源

文档、等静态资源

动态资源:

对某种资源的CURD权限:如 是否可以对 sys_user表数据进行CURD。

这个场景下可以抽象出来的类:

其中的岗位和部门,有些权限管理框架中没有,有的或许有一个,这里不纠结这个问题,无论是部门还是岗位,其实都是提供了一种权限判断的维度,类型给用户打上一种标签。

333 token管理

生成用户token后,所有的token需要管理起来。可以用来统计和维护。

所以需要将上一步获取到的用户权限描述类的信息与token建立一种映射关系。从而可以通过token获取到用户的各种信息。

这个场景可以抽象出来的类:

Token管理类:用来管理所有生成的token。并建立用户信息与token的关联关系。

334 用户鉴权

当用户通过用户认证和用户授权后,就获取到了他的token口令。

每次用户来访问服务资源时,都需要携带token,当服务器收到请求后,需要通过token获取到用户的所有的权限信息,来判断用户是否可以访问当前资源。

这个场景似乎没有可以抽离出来的类,而是我们要找到一种用户鉴权的方案。

这里,根据以往的经验,基于Spring的AOP切面编程应该是对使用者最友好的方式

所以这里总结下我们需要鉴权的类型:

四、小结

上面铺垫了那么些,其实只是想让大家能跟笔者有一个相同的认知。

先梳理下上面总结出来的类。

凭证类、凭证类验证器、token生成器、token管理器。

以及,基于AOP实现的用户鉴权方案。

大致思路:

未完待续。。。

以上就是关于Spring5AOP——BeanPostProcessor全部的内容,包括:Spring5AOP——BeanPostProcessor、spring的ioc和aop都是什么、spring aop后置通知怎么获取目标方法返回值,及通知的信息等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9345547.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存