读《Spring 实战(第四版)》第四章 Spring面向切面

Spring AOP是基于动态代理的,所以只支持方法连接点
Spring仅支持Aspectj切点指示器的一个子集
1

public interface Performance {
	public void perform();
}
编写切点

execution(* concert.Performance.perform(..)) && within(concert.*)

  • * 任意返回类型
  • concert.Performance 方法所属类
  • perform 方法
  • (..) 任意参数
  • && =and 前后指示器都要满足(后一个表示concert包下任意类的方法被调用时)
  • ||=or
  • !=not
    XML中可以使用单词代替避免特殊含义字符

execution(* concert.Performance.perform(..)) && bean('woodstock')

  • bean() 限定bean的ID为woodstock
定义切面
使用注解
  • @Before
  • @After
  • @Around
  • @AfterReturning
  • @AfterThrowing

定义一个切点表达式多次使用

@PoingCut("execution(* concert.Performance.perform(..)) ")
public void performance() {}

@Before("performance()")
public void before() {...}

在Java配置类中上使用EnableAspectjAutoProxy启用自动代理
或者xml中

<aop:aspectj-autoproxy />

@Aspectj 注解的bean创建一个代理,这个代理会围绕所有该切面的切点所匹配的bean

环绕通知方法需要接收ProceedingJoinPoint 参数,用来在通知方法中调用被通知的方法

@Around
public void around(ProceedingJoinPoint jp) {
	before();
	jp.proceed();
	after();
}
处理通知中的参数
@Pointcut("execution(* com.wang.count(int)) && args(number)")
public void count(int number) {};

@Before("count(number)") 
public void before(int number) {...}
  • count(int) 接受int类型参数
  • args(number) 指定参数,参数会传递到通知方法中,参数名称一样,可以在通知方法中使用
引入增强

已经定义好的A类,需要使用B接口的功能,在不修改A类实现的情况下使用B的方法功能

@DeclareParents(value="concert.Performance+", defaultImpl=DefaultImpl.class)
public AnotherIntf anotherintf;
  • value 指定需要引入新接口的bean(+表示所有Performance的子类型,不包括本身)
  • defaultImpl 指定为引入功能提供实现的类
  • 注解标注了要引入的接口
xml中声明切面
  • <aop:advisor> 定义aop通知器
  • <aop:after> 定义后置通知
  • <aop:after-returning> 定义返回通知
  • <aop:after-throwing> 定义异常通知
  • <aop:arounf> 定义环绕通知
  • <aop:aspectj> 定义一个切面
  • <aop:aspectj-autoproxy> 启用@Aspectj注解的切面
  • <aop:before> 定义前置通知
  • <aop:config> 大多数<aop:*> 元素都要包含在其中
  • <aop:declare-parents> 引入增强
  • <aop:pointcut> 定义一个切点
<aop:config>
	<aop:aspectj ref="audience"> <!--通知beanID-->
		<aop:pointcut id="performance" expression="execution(* concert.Performance.perform(..))" />
		
		<aop:before method=“before” pointcut-ref="performance"/>	
	</aop:aspectj>
</aop:config>

如果不定义<aop:pointcut/><aop:before/>中添加属性expression="execution(* concert.Performance.perform(..))"
传递参数:
加了and args(number)

<aop:config>
	<aop:aspectj ref="audience"> <!--通知beanID-->
		<aop:pointcut id="performance" expression="execution(* concert.Performance.perform(int)) and args(number)" />		
		<aop:before method=“before” pointcut-ref="performance"/>	
	</aop:aspectj>
</aop:config>

引入增强:

<aop:config>
	<aop:aspectj ref="audience"> <!--通知beanID-->
		<aop:declare-parents 
		types-matching="concert.Performance+"
		implement-interface="concert.Encorable"
		default-impl="concert.DefaultEncorable"  />
	</aop:aspectj>
</aop:config>

·····························································································································································································
Aspectj切面中注入bean
当SpringAOP不能满足需求时,就需要更为强大的Aspectj,如何使用Spring为Aspectj注入依赖:

public aspect CriticAspect {
	
}
<bean class="com.springinaction.springidol.CriticAspect" factory-method="aspectOf">
	<property name="criticismEngine" ref="criticismEnfine" />
</bean>

通常情况下,bean由Spring容器初始化,但是Aspectj切面是由Aspectj在运行期创建的,等到Spring有机会为CriticAspect注入criticismEnfine时,CriticAspect已经被实例化了。
因为Spring不负责创建CriticAspect,那就不能在Spring中简单的把CriticAspect声明为一个bean,我们需要一种方式获得由Aspectj创建的CriticAspect实例的句柄,来注入CriticismEnfine
所有的Aspectj切面都提供一个静态的aspectOf()方法,该方法返回切面的一个单例,所以要使用factory-method来调用aspectOf()方法,而不是调用构造器方法。
简而言之,Aspectj切面实例在运行时已经由Aspectj创建完成了,Spring需要通过aspectOf()工厂方法获得切面的引用,然后在该对象上执行注入。


  1. p107 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值