Spring AOP小记

Posted dirac

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring AOP小记相关的知识,希望对你有一定的参考价值。

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小记的主要内容,如果未能解决你的问题,请参考以下文章

阿里四面:你知道Spring AOP创建Proxy的过程吗?

spring aop中this和target区别

spring AOP使用中Error creating bean with name ‘…’defined in class path resource..问题及其解决方法

JAVA之AOP

CGlib小记

Spring AOP