Spring AOP小記
阿新 • • 發佈:2018-06-16
在一起 factor XML ble wing ssi spec 匹配 oid
Spring AOP vs AspectJ
AOP keywords
- Aspect, 橫切面,對象
- Jointpoint, 連接點,在Spring裏是方法,還可以是其他(AspectJ中的表達式within等)
- Pointcut, 切入點,連接點攔截的定義
- Advice, 通知,攔截到攔截點之後要做的動作(Before, After, Around, AfterReturning, AfterThrowing)
- Weaving, 織入(編譯期,類加載期(AspectJ5 LTW),運行期(Spring AOP基於此,動態創建代理))
Spring中對AOP的支持
- 基於代理的Spring AOP及其變種(ProxyFactoryBean等)
- AspectJ切面
AspectJ切點表達式
arg() 限制連接點匹配參數為指定類型的執行方法
@args() 限制連接點匹配參數為指定註解標註的執行方法
execution() 用於匹配是連接點的執行方法
within() 限制連接點匹配指定的類型
@within() 限制連接點匹配指定註解所標註的類型(使用Spring AOP時,方法定義在由指定註解標註的類裏)
@annotation 限定匹配帶有指定註解的連接點(比如限定被xx註解標註的方法)
組合表達式:&& || !
ProxyFactoryBean
<bean id="helloProxy" class= "org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces">
<list>
<value>io.dirac.aop.HelloService</value>
</list>
</property>
<property name="target" ref="hello"/>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
<!-- proxy target -->
<bean id="hello" class="io.dirac.aop.HelloServiceImpl"/>
<!-- AdvisorLogger implements MethodInterceptor 在這裏面實現前後通知 -->
<bean id="advisor" class="io.dirac.aop.AdvisorLogger"/>
<aop:config>
<bean id="logger" class="io.dirac.aop.LoggerHandler"/>
<!-- 對於log這個切面,會攔截HelloService中say方法這個切點id=sayMethod,say之前調用log切面的preHandle和postHandle方法 -->
<aop:config>
<aop:aspect id="log" ref="logger">
<aop:pointcut id="sayMethod" expression="execution(* io.dirac.aop.HelloService.say(..))"/>
<aop:before method="preHandle" pointcut-ref="sayMethod"/>
<aop:after method="postHandle" pointcut-ref="sayMethod"/>
</aop:aspect>
</aop:config>
AspectJ
如果是XML配置,需要配置如下開啟<aop:aspectj-autoproxy/>
, 如果是JavaConfig,需要在配置類上@EnableAspectJAutoProxy
開啟。
@Aspect
@Component
public class ConcurrencyLimitAspect {
// 值就是連接點的具體形式Pointcut,只不過此處現在一起了
// 對於AspectJ而言,連接點可以不止是方法
// 這個切點的意思是:對於註解了Component類中註解了ConcurrencyLimit方法起作用,寫切面在方法上做並發控制
@Around("@annotation(limit) && @within(org.springframework.stereotype.Component)")
public Object limit(ProceedingJoinPoint point, ConcurrencyLimit limit) {
int lmt = limit.limit();
if (lmt < 0) {
throw new RuntimeException("limit!");
}
try {
Object ret = point.proceed();
return ret;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
// 在createService方法處連接點的切點
@Pointcut("execution(public * io.dirax.api.OrderService.createService(..))")
public void pointcut() {
}
// pointcut切點前置通知
@Before("pointcut()")
public void beforeAction(JoinPoint jp) {
// TODO
}
// 指定參數,可以在通知中把參數傳入(如果對參數request修改,會影響後續)
@Pointcut("execution(public * io.dirax.api.OrderService.createService(Object)) && args(request)")
public void pointcutWithArgs(Object request) {
}
@After(value = "pointcut(request)", argNames = "request")
public void after(Object request){
//TODO
}
}
對環繞(@Around
)通知,參數ProceedingJoinPoint
可以在實際方法前後做環繞處理;其他的可以使用JoinPoint
。
如上實例,對於註解了Component
的對象中註解了ConcurrencyLimit
的方法,會使用切面ConcurrencyLimitAspect
中的limit
做增強。
Spring AOP小記