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("======================================");
}  

将输出:

 
 

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

===========before advice param:before

============say before

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

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

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的创建而创建,销毁而销毁。

Spring三种切面相关推荐

  1. JDK/Dubbo/Spring 三种 SPI 机制,谁更好?

    点击关注公众号,Java干货及时送达 来源:juejin.cn/post/6950266942875779108 SPI 全称为 Service Provider Interface,是一种服务发现机 ...

  2. JDK/Dubbo/Spring 三种 SPI 机制,谁更好呢?

    JDK/Dubbo/Spring 三种 SPI 机制,谁更好? SPI 全称为 Service Provider Interface,是一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文 ...

  3. Spring三种对象创建方式

    1.创建方式1:无参构造 我们先创建一个User类: public class User {private String name;private int age;public User() {Sys ...

  4. spring三种注入方式

    设置Spring的作用域 或者使用枚举值设置 单例和多里使用场景 自动注入 @Primary 一个接口有多个实现被spring管理吗,在依赖注入式,spring会不知道注入哪个实现类就会抛出NoUni ...

  5. Spring学习之Spring三种装配机制:(一)自动化装配bean

    装配:创建应用组件(对象)之间的协作的行为,这也是Spring依赖注入(DI)的本质. Spring提供了三种装配机制: 隐式的自动装配bean: 通过java代码装配bean(显示): 通XML中装 ...

  6. Spring三种注入方法(set注入、构造方法注入、p标签注入)

    一.构造注入 编写一个User类 public class User {private String name; //名字private Integer age; //性别private Date d ...

  7. 邮件发送 --- 纯Java、JavaWeb、Spring三种实现方式

    邮件发送学习笔记~ 一.邮件发送介绍 要在网络上实现邮件功能,必须要有专门的邮件服务器! 这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中! ...

  8. Spring 三种bean装配的方式

    1.使用xml配置文件装配 Spring成功启动的三大要件分别是:Bean定义信息.Bean实现类以及Spring本身. 在xml文件中配置bean,然后使用ClassPathXmlApplicati ...

  9. Spring三种方法的注解自动注入

    1 @Autowired注解 @Autowired是Spring提供的自动注入的方法,该注解可以放在变量和方法上,在bean+返回值类型的注解中,@Autowired还可以放在参数前:@Autowir ...

最新文章

  1. [训练日志] 7月22-31日
  2. 计算机网络双语名词,计算机网络中英文名词对照
  3. python字符串、元组常用操作
  4. 鸿蒙开发目录结构及文件使用规则介绍
  5. 【机器学习】传统目标检测算法之DPM
  6. laravel+vue开发环境搭建
  7. 赞!苏州大学95后硕士一作发《Nature》!
  8. Flume实战监听文件夹内文件变化
  9. 图片支持滚轮缩放(缩放中心为鼠标位置)_JS实现图片缩放、拖动、剪裁、预览及保存效果...
  10. Linux之间配置SSH互信(SSH免密码登录)
  11. 具有分页,排序,搜索和导出数据选项的ASP.NET Core CRUD操作
  12. Spring mvc @RequestHeader
  13. iOS Category 和 Extention 的本质区别【面试必备】
  14. 基于vue+js的商城、购物网站 毕业设计 毕设源代码的实现和设计(6)购物车
  15. Android源码刷机步骤
  16. pom文件配置阿里云仓库 转
  17. 正则表达式 - 常用正则表达式
  18. Nodeparty-SZ-1 深圳聚会活动回顾总结[2012.01.08] - CNode
  19. Python-实现语音识别并批处理标注(重命名)文件
  20. 分频器的Verilog设计

热门文章

  1. 最新版HBuilderx + 夜神模拟器 模拟器调试设置
  2. bilibili账号申诉中心_B站的申诉渠道究竟在哪啊
  3. 基于数据挖掘的智能停车场运营数据分析系统
  4. Ed2k协议背景介绍及eMule协议的整体架构
  5. 关于互联网“毕业“的一些思考
  6. 图片放大不模糊,如何实现?
  7. 交易猫跳转APP+后台管理
  8. 光猫修改配置同步到服务器,光猫—防火墙—3台服务器防火墙需要怎么配置,防火墙做二层?...
  9. Javascript 实现一个分钟秒钟倒计时器
  10. 软件团队的模式-窝蜂模式