Spring之AOP

本文阅读 8 分钟
首页 代码,Java 正文

通知

就是你想要的功能,也就是我们常说的安全、事物、日志等。先定义好这些,然后再想用的地方用一下。包含Aspect的一段处理代码

注意:其实这些功能(通知)并不是我们业务逻辑所必须的,只是为了安全,输出信息,或者其他的原因,总之是为了方便我们对项目维护而增加的操作,一般我们会把这些功能封装成相关的方法,但是我们又不想这些功能直接入侵我们的正常业务代码,因为这样会增加关注度并且污染我们的业务逻辑,所以我们就用切面的思想来很好解决这个问题

连接点

就是spring允许你加 通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring一般只支持方法连接点,除非引入其他的aop框架才可以实现更细粒度的连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点

切入点

在上面说的连接点的基础上,来定义切入点。例如:你的一个类里,有15个方法,那就有至少十几个连接点了对吧,但是你并不想在所有方法附近都使用通知(使用叫织入,下面再说),你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法

注意:切入点定义的一般是你的业务中的某些方法(也有可能是某些特殊地方,在“特例”下有个例子切点切的就是方法,而是自定义的注解),就是供切面实际切入的地方,也就是需要执行通知的地方

切面

用来切插业务方法的类。

切面是通知和切入点的结合。现在发现了吧,没连接点什么事,链接点就是为了让你好理解切点搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的befor,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义

目标

引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面,而自己专注于业务本身的逻辑。

代理

怎么实现整套AOP机制的,都是通过代理,这个一会儿给细说

织入(weaving)

把切面应用到目标对象来创建新的代理对象的过程。有三种方式,spring采用的是运行时,为什么是运行时,在上一文《Spring AOP开发漫谈之初探AOP及AspectJ的用法》中第二个标提到

目标对象

项目原始的Java组件。

AOP代理

由AOP框架生成java对象。

AOP代理方法

代理方法= advice + 目标对象的方法。

AOP依赖

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.9</version>
</dependency>

AOP配置文件

在使用xml方式的Aop时,首先要保证xml头部引入了aop包和spring的基础包,如下:

< beans xmlns="http://www.springframework.org/schema/beans" 

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context" 
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd" >
</ beans>

在spring-context.xml(也就是spring的主配置文件)中加入

<aop:aspectj-autoproxy/>

aop具体代码:

<!-- 定义普通的Bean实例 -->
    <bean id="adviceTest" class="com.abc.advice.AdviceTest" />
    <!-Aop配置->
    <aop:config>
        <!-- 将容器中的adviceTest转换成切面Bean --> 
         <!-- 注意这里可以使用order属性为Aspect指定优先级 -->
        <aop:aspect id="firstAspect" ref="adviceTest" order="2">
          <!-切点第一种写法开始->
              <!-- @Before切点 -->
          <!-method属性对应的方法一定是切面中的方法->
              <aop:before pointcut="execution(* com.abc.service.*.*(..))" 
                      method="permissionCheck"  arg-names="name,age"/>
              <!-- @After切点 -->
              <aop:after pointcut="execution(* com.abc.service.*.*(..))" 
                      method="releaseResource"/>
              <!-- @AfterReturning切点 -->
              <aop:after-returning pointcut="execution(* com.abc.service.*.*(..))" 
                      method="log" returning="discussion" arg-names="discussion"/>
          注意:如果有returning属性,那么arg-names属性必须有,两者的属性值可以任意取名,但是必须一致,否者就会报错
              <!-- @AfterThrowing切点 -->
              <aop:after-throwing pointcut="execution(* com.abc.service.*.*(..))" 
                      method="handleException"/>
              <!-- @Around切点(多个切点提示符使用and、or或者not连接) -->
              <aop:around pointcut="execution(* com.abc.service.*.*(..)) and args(name,time,..)" 
                      method="process"/>
          <!-切点第一种写法结束->
    
          <!-切入点第二种写法开始->
          <!-单参数传参->
          <aop:pointcut      id="thinking"   expression="execution(* com.bird.springidol.Thinker.thinkOfSomething(String)) and args(thoughts)"/>             
          <aop:before method="interceptThoughts" pointcut-ref="thinking" arg-names="thoughts"/>
          注意:这个配置的意思就是,拦截这个Thinker接口的实现方法,其中的参数命名为thoughts,
          下面的before方法里面的interceptThoughts方法接受一个参数,这个参数映射到thoughts这个地方,然后暗中的拦截方法就能接受到参数了
 
          <!-对象传参->
          <aop:pointcut id="log4add" expression="execution(* com.tfedu.discuss.web.TeacherDiscussionController.delete(com.tfedu.discuss.abutment.TestAddLog)) and            args(testAddLog)" />
          <aop:after method="addLog" pointcut-ref="log4add" arg-names="testAddLog"/>

          <!-切入点第二种写法结束->

          <!-切点为注解时,也就是将切点切到注解上 开始->

             <!-切点为注解时,也就是将切点切到注解上 结束-> 
          </aop:aspect>
    </aop:config>

配置中常用属性介绍:

  • pointcut-ref:当pointcut单独写时,在通知标签里,要是用pointcut-ref属性来指向响应的切点Id
  • method:一般对应的是切面中的通知方法
  • arg-names:定义的是通知方法中的参数。一般通知方法中需要使用切点方法的参数时,这个属性最好加上(当然有时不写也可以传参),并且和expression表达式中的args()的小括号中的名称保持一直
  • order Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟spring的事务aop执行的先后顺序问题,比如说动态切换数据源的问题,如果事务在前,数据源切换在后,会导致数据源切换失效,所以就用到了Order(排序)这个关键字.我们可以通过在@AspectJ的方法中实现org.springframework.core.Ordered 这个接口来定义order的顺序,order 的值越小,说明越先被执行

Spring之AOP示例

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/qq_38571892/article/details/123337316
-- 展开阅读全文 --
Web安全—逻辑越权漏洞(BAC)
« 上一篇 03-13
Redis底层数据结构--简单动态字符串
下一篇 » 04-10

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复