Spring三种切面

2023-11-11

Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明。

1 启用对@AspectJ的支持

Spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置:

java代码:

<aop:aspectj-autoproxy/>

这样Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。

2 声明切面

@AspectJ风格的声明切面非常简单,使用@Aspect注解进行声明:

java代码:

@Aspect()  
Public class Aspect{  
……  
}  

然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:

java代码:

<bean id="aspect" class="……Aspect"/>  

该切面就是一个POJO,可以在该切面中进行切入点及通知定义,接着往下看吧。

3 声明切入点

@AspectJ风格的命名切入点使用org.aspectj.lang.annotation包下的@Pointcut+方法(方法必须是返回void类型)实现。

java代码:

@Pointcut(value="切入点表达式", argNames = "参数名列表")  
public void pointcutName(……) {}  
   

value:指定切入点表达式;

argNames:指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。

pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式。

java代码:

@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")  
public void beforePointcut(String param) {}  

定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。

4 声明通知

@AspectJ风格的声明通知也支持5种通知类型:

一、前置通知:使用org.aspectj.lang.annotation 包下的@Before注解声明;

java代码:

@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")  

value:指定切入点表达式或命名切入点;

argNames:与Schema方式配置中的同义。

接下来示例一下吧:

1、定义接口和实现,在此我们就使用Schema风格时的定义;

2、定义切面:

java代码:

package cn.javass.spring.chapter6.aop;  
import org.aspectj.lang.annotation.Aspect;  
@Aspect  
public class HelloWorldAspect2 {  
   
}  

3、定义切入点:

java代码:

@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")  
public void beforePointcut(String param) {}  

4、定义通知:

java代码:

@Before(value = "beforePointcut(param)", argNames = "param")  
public void beforeAdvice(String param) {  
    System.out.println("===========before advice param:" + param);  
}  

5、在chapter6/advice2.xml配置文件中进行如下配置:

java代码:

<?xml version="1.0" encoding="UTF-8"?>  
<beans  xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:aop="http://www.springframework.org/schema/aop"  
        xsi:schemaLocation="  
           http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
           http://www.springframework.org/schema/aop  
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">  
            
  <aop:aspectj-autoproxy/>  
  <bean id="helloWorldService"  
            class="cn.javass.spring.chapter6.service.impl.HelloWorldService"/>  
   
  <bean id="aspect"  
             class="cn.javass.spring.chapter6.aop.HelloWorldAspect2"/>  
   
</beans>  
   

6、测试代码cn.javass.spring.chapter6.AopTest:

java代码:

@Test  
public void testAnnotationBeforeAdvice() {  
    System.out.println("======================================");  
    ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter6/advice2.xml");  
    IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);  
    helloworldService.sayBefore("before");  
    System.out.println("======================================");  
}  

将输出:

==========================================

					<p>===========before advice param:before</p>

					<p>============say before</p>

					<p>==========================================</p>
					</td>
				</tr></tbody></table></td>
	</tr></tbody></table><p> </p>

切面、切入点、通知全部使用注解完成:

1)使用@Aspect将POJO声明为切面;

2)使用@Pointcut进行命名切入点声明,同时指定目标方法第一个参数类型必须是java.lang.String,对于其他匹配的方法但参数类型不一致的将也是不匹配的,通过argNames = "param"指定了将把该匹配的目标方法参数传递给通知同名的参数上;

3)使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点;

4)配置文件需要使用<aop:aspectj-autoproxy/>来开启注解风格的@AspectJ支持;

5)需要将切面注册为Bean,如“aspect”Bean;

6)测试代码完全一样。

二、后置返回通知:使用org.aspectj.lang.annotation 包下的@AfterReturning注解声明;

java代码:

@AfterReturning(  
value="切入点表达式或命名切入点",  
pointcut="切入点表达式或命名切入点",  
argNames="参数列表参数名",  
returning="返回值对应参数名")  

value:指定切入点表达式或命名切入点;

pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

argNames:与Schema方式配置中的同义;

returning:与Schema方式配置中的同义。

java代码:

@AfterReturning(  
    value="execution(* cn.javass..*.sayBefore(..))",  
    pointcut="execution(* cn.javass..*.sayAfterReturning(..))",  
    argNames="retVal", returning="retVal")  
public void afterReturningAdvice(Object retVal) {  
    System.out.println("===========after returning advice retVal:" + retVal);  
}  

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationAfterReturningAdvice测试方法。

三、后置异常通知:使用org.aspectj.lang.annotation 包下的@AfterThrowing注解声明;

java代码:

@AfterThrowing (value="切入点表达式或命名切入点",  
pointcut="切入点表达式或命名切入点",  
argNames="参数列表参数名",  
throwing="异常对应参数名")  
   

value:指定切入点表达式或命名切入点;

pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

argNames:与Schema方式配置中的同义;

throwing:与Schema方式配置中的同义。

java代码:

@AfterThrowing(  
    value="execution(* cn.javass..*.sayAfterThrowing(..))",  
    argNames="exception", throwing="exception")  
public void afterThrowingAdvice(Exception exception) {  
    System.out.println("===========after throwing advice exception:" + exception);  
}  

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationAfterThrowingAdvice测试方法。

四、后置最终通知:使用org.aspectj.lang.annotation 包下的@After注解声明;

java代码:

@After (  
value="切入点表达式或命名切入点",  
argNames="参数列表参数名")  

value:指定切入点表达式或命名切入点;

argNames:与Schema方式配置中的同义;

java代码:

@After(value="execution(* cn.javass..*.sayAfterFinally(..))")  
public void afterFinallyAdvice() {  
    System.out.println("===========after finally advice");  
}  

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationAfterFinallyAdvice测试方法。

五、环绕通知:使用org.aspectj.lang.annotation 包下的@Around注解声明;

java代码:

@Around (  
value="切入点表达式或命名切入点",  
argNames="参数列表参数名")  

value:指定切入点表达式或命名切入点;

argNames:与Schema方式配置中的同义;

java代码:

@Around(value="execution(* cn.javass..*.sayAround(..))")  
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {  
    System.out.println("===========around before advice");  
    Object retVal = pjp.proceed(new Object[] {"replace"});  
    System.out.println("===========around after advice");  
    return retVal;  
}  

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的annotationAroundAdviceTest测试方法。

6.4.5 引入

@AspectJ风格的引入声明在切面中使用org.aspectj.lang.annotation包下的@DeclareParents声明:

java代码:

@DeclareParents(  
value=" AspectJ语法类型表达式",  
defaultImpl=引入接口的默认实现类)  
private Interface interface;  

value:匹配需要引入接口的目标对象的AspectJ语法类型表达式;与Schema方式中的types-matching属性同义;

private Interface interface:指定需要引入的接口;

defaultImpl:指定引入接口的默认实现类,没有与Schema方式中的delegate-ref属性同义的定义方式;

java代码:

@DeclareParents(  
    value="cn.javass..*.IHelloWorldService+", defaultImpl=cn.javass.spring.chapter6.service.impl.IntroductiondService.class)  
private IIntroductionService introductionService;  
   

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationIntroduction测试方法。

 <aop:config></aop:config>解析
<?xml version="1.0" encoding="UTF-8"?>  
  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xsi:schemaLocation="   
             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd   
             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
    <bean id="testAction" class="test.action.Stuts2ActionTest">  
        <property name="service" ref="templatesService"></property>  
    </bean>  
  
    <bean id="templatesService"  
        class="test.service.impl.TaoTemplatesServiceImpl">  
        <property name="dao" ref="templatesDAO" />  
    </bean>  
  
    <bean id="templatesDAO" class="test.dao.impl.TaoTemplatesDAOImpl">  
        <property name="sessionFactory" ref="sessionFactory"></property>  
    </bean>  
  
  
    <!--定义数据源-->  
    <bean id="dataSource"  
        class="org.apache.commons.dbcp.BasicDataSource">  
        <!--    定义数据库驱动-->  
        <property name="driverClassName">  
            <value>oracle.jdbc.driver.OracleDriver</value>  
        </property>  
        <!--    定义数据库url-->  
        <property name="url">  
            <value>jdbc:oracle:thin:@192.168.1.96:1521:yxdb</value>  
        </property>  
        <!--    定义数据库用户名-->  
        <property name="username">  
            <value>yxuser</value>  
        </property>  
        <!--    定义数据库密码-->  
        <property name="password">  
            <value>yxuser</value>  
        </property>  
    </bean>  
  
    <!--定义一个hibernate的SessionFactory-->  
    <bean id="sessionFactory"  
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <!--    定义SessionFactory必须注入DataSource-->  
        <property name="dataSource">  
            <ref local="dataSource" />  
        </property>  
        <property name="mappingResources">  
            <list>  
                <!--以下用来列出所有的PO映射文件-->  
                <value>test/mapping/Tao_Templates.hbm.xml</value>  
            </list>  
        </property>  
        <property name="hibernateProperties">  
            <props>  
                <prop key="hibernate.dialect">  
                     org.hibernate.dialect.Oracle10gDialect   
                </prop>  
                <prop key="hibernate.show_sql">true</prop>  
                 <!--此处用来定义hibernate的SessionFactory的属性:   
                     不同数据库连接,启动时选择create,update,create-drop -->  
                <prop key="hibernate.hbm2ddl.auto">update</prop>  
            </props>  
        </property>  
    </bean>  
  
    <bean id="transactionManager"  
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
        <property name="sessionFactory">  
            <ref bean="sessionFactory" />  
        </property>  
    </bean>   

<!--
 <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="jamon-proxy-DataSource"></property>
     </bean>
 -->
 <!-- 事务通知 -->   
     <tx:advice id="txAdvice" transaction-manager="transactionManager">   
         <tx:attributes>   
             <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception,SmoException,BmoException,DaoException" />   
             <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception,SmoException,BmoException,DaoException" />   
             <tx:method name="upd*" propagation="REQUIRED" rollback-for="Exception,SmoException,BmoException,DaoException" />
    <tx:method name="*" propagation="SUPPORTS" read-only="true" />
   </tx:attributes>
  </tx:advice>
  <!-- Spring AOP config 
  解释一下(* com.evan.crm.service.*.*(..))中几个通配符的含义:
  第一个 * —— 通配 任意返回值类型
  第二个 * —— 通配 包com.evan.crm.service下的任意class
  第三个 * —— 通配 包com.evan.crm.service下的任意class的任意方法
  第四个 .. —— 通配 方法可以有0个或多个参数
   -->
  <aop:config>
   <aop:pointcut id="servicesPointcut" expression="execution(* com.jstrd.mss..*SMOImpl.*(..))" />
   <aop:advisor advice-ref="bluePrint.txAdvice" pointcut-ref="servicesPointcut" />  
  </aop:config>   
  </beans>   
    <aop:scoped-proxy/>解析

首先看一下Spring文档上的两个例子对比:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>



<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
    <aop:scoped-proxy/>
</bean>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

       前一个例子没有使用<aop:scoped-proxy/>,并且userManager是singleton,所有userManager仅被初始化一次,并且其属性userPreferences也仅被注射一次。当session失效后,userManager仍将保留userPreferences实例。但后一个例子则不一样,userManager的属性userPreferences指向的是com.foo.UserPreferences实例的代理,当session过期后,userManager的属性userPreferences自然也不能再使用。网上有人解释说,这个代理只随着session的创建而创建,销毁而销毁。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring三种切面 的相关文章

随机推荐

  • 实训周笔记

    主机信息收集技术 基础知识 主要收集目标主机的相关信息 主要包括端口 服务 漏洞等信息 信息收集手段多样 可借助工具也多种多样 端口扫描 Nmap 主机信息收集技术 Nmap namp 192 168 1 1 namp A T4 v 192
  • proteus 问题--解决创建项目、打开项目:Error opening VSM Studio project STM32F401VE,无法查看Source Code,无法创建硬件项目

    问题描述 原因 安装软件的路径有中文 删掉所有东西后 重新下载即可 创建新项目 点击New Project 选择GCC for ARM这个配置项 也可以进入后在配置
  • qt如何触发点击事件_PyQt5事件处理机制(一)

    基于窗体的应用程序都是事件 event 驱动的 鼠标单击 按下某个按键 重绘某个组件 最小化窗口都会产生相应的事件 应用程序对这些事件作出相应的处理以实现程序的功能 常用的特定事件处理函数及方法示例代码 from PyQt5 Qt impo
  • 解读 Q_D, Q_Q 指针

    见 qglog h文件定义 define Q D Class Class Private const d d func define Q Q Class Class const q q func d指针是在主类中使用的 来获取私有子类成员指
  • STM32HAL库软件模拟SPI驱动0.96OLED屏幕,F1、F4系列通用,6pin和7pin模块通用

    本实验通过网上搜集的资料 整理出HAL库的SPI驱动 为了方便移植 选择采用软件模拟SPI通信来驱动OLED 本实验使用的OLED为7pin 默认通信模式为SPI 可以更改板上电阻更换为IIC模式 屏幕驱动芯片为SSD1306 模块简介 6
  • 代码流星雨

    什么是html html就是前端可以理解成为网页界面 不会但是想玩 可以在电脑桌面上建一个记事本然后把代码复制后粘贴在记事本里面 然后保存最后吧记事本 新建文本文档 tx 的后缀 就是重命名 改成html 新建文本文档 html 来自htm
  • 阀门与压力表同步代码

    using System Collections using System Collections Generic using UnityEngine public class Mmmmmm MonoBehaviour float sum
  • Elasticsearch 写入和查询优化底层原理

    一 Elasticsearch 写入原理 1 每个index 是由多个shard组成 默认是5个 每个shard有一个主节点和多个副本节点 分散在不同的物理节点上 2 写入数据的时候 先根据routing参数 以那个字段的值作为路由key
  • 入门级题解:704. 二分查找

    题目 给定一个 n 个元素有序的 升序 整型数组 nums 和一个目标值 target 写一个函数搜索 nums 中的 target 如果目标值存在返回下标 否则返回 1 暴力查找 直接找 遍历 直接尝试二分查找 递归应该要用 中间的值 a
  • 1_simulink简单入门_simulink仿真PID控制

    1 simulink简单入门 simulink仿真PID控制 2 simulink搭建RCL 电阻电感电容模块 毕业前想去做物联网还是或者linux 结果玩了一年多的电机控制 早就深知matlab simulink绕不过的 拖到现在 下班晚
  • attention机制(SE-Net、CBAM及Triplet)

    简介 注意力机制 Attention Mechanism 源于人类视觉的研究 在认知科学中 人类会选择性地关注所有信息的一部分 而忽略其他可见信息 为了合理利用有限的资源 就需要选择视觉区域的特定部分 并重点关注它 在神经网络中 atten
  • RabbitMQ 几种模式

    普通模式 一个生产者 一个交换机 一个队列 一个消费者 生产者 public class Send private final static String QUEUE NAME hello public static void main S
  • “csproj文件究竟是做什么用的”

    csproj文件大家应该不会陌生 那就是C 项目文件的扩展名 它是 C Sharp Project 的缩写 那么它究竟是给谁用的呢 那是给开发工具用的 例如我们在熟悉不过的Visual Studio 以及大家可以没有接触过 但是应该都听说过
  • adobe 软件(PS AI)占用内存过大问题

    adobe 软件 PS AI 占用内存过大问题 电脑是通过数据的交换来进行工作 CPU是处理数据交换的硬件 内存是暂时存储这些数据的硬件 电脑内存 RAM 容量越大你的数据交换能力就越强 就越能够完成复杂的任务 查看设备配置 操作系统 内存
  • 毕业设计-基于机器视觉的木材表面缺陷检测-OpenCV

    目录 前言 课题背景和意义 实现技术思路 一 表面缺陷分析及检测方案设计 二 表面缺陷图像识别 三 系统识别性能测试 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业
  • 【python】天平最少砝码设计

    题目 有一架天平 砝码的种类和个数要你来设计 给定一个整数n 则待称重的物品的重量可能是 1 n 之间的整数 砝码可以放在左盘也可以放在右盘 要能称出所有 1 n 重量的物品 请问如何设计砝码的种类和个数 使得这一套砝码的总个数最少 比如
  • 卷积神经网络 —— 图像卷积

    卷积神经网络是最具代表性的深度学习算法之一 目前已经被大范围的应用与计算机视觉等领域 并且取得了众多突破性的进展 在学习卷积神经网络之前 我们需要学习图像卷积运算 图像卷积运算的作用 图像卷积运算是一种图像处理算法 通过它可以实现很多不同的
  • gin http-request

    func main router gin Default router POST form post message func c gin Context 查询请求URL后面拼接的参数 id c Query id 从取得URL中参数 此处U
  • 移动开发技术(三)

    禅道工具的使用 添加产品 步骤 在 产品视图 中 单击 添加产品 按钮 在 新增产品 页面中 输入产品信息 单击 保存 按钮 说明 产品由产品经理进行添加 产品类型 正常 多分支 PC Android Ios 多平台 Windows Lin
  • Spring三种切面

    Spring除了支持Schema方式配置AOP 还支持注解方式 使用 AspectJ风格的切面声明 1 启用对 AspectJ的支持 Spring默认不支持 AspectJ风格的切面声明 为了支持需要使用如下配置 java代码