spring的aop:advisor和aop:aspect

名词解释:

  • 连接点 : 应用程序中插入切面的地点 , 可以是方法调用 , 异常抛出 , 或者要修改的字段 . 一个类或者一段代码具有一些边界性质的特定点, 这些代码中特定点就是连接点, spring只支持方法的连接点 .

  • 切入点 : 定义了通知应该应用在哪些连接点 , 被应用的连接点就是切入点 . 通知可以应用到系统的任何连接点上 .

  • 切面(aspect) : 要实现的交叉功能 , 由切点和增强(引入)组成, 包括对横切关注功能的定义, 也包括对连接点定义 .

  • 通知(增强) : 切面的具体实现 ,是织入到目标连接点的一段程序代码, Spring提供的增强接口都是带方位名的 , 如 : BeforeAdvice, AfterReturningAdvice, ThrowsAdvice等,

  • 引入 : 一种特殊增强, 它为类添加一些属性和方法, 这样即使一个业务类原本没有实现某个接口, 通过引入功能, 可以动态给业务类添加接口实现逻辑, 让业务类称为这个接口的实现类 .

  • 织入 : 创建代理对象的过程 ,
    三种织入方式 :
    1>编译器织入 , 在java–>class文件时候 , 织入 . 需要特殊编译器 .
    2>类装在其织入 , 将java字节码载入到jvm , 将通知织入 , 需要特殊的classloader
    3>运行期 , spring就是用这种 .


advisor和aspect区别:

上网找关于这两个概念区别:

  • 第一种说法 :
    1、Adivisor是一种特殊的Aspect,Advisor代表spring中的Aspect
    2、区别:advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice
  • 第二种说法:
    aop:aspect实际上是定义横切逻辑,就是在连接点上做什么,aop:advisor则定义了在哪些连接点应用什么aop:aspect。Spring这样做的好处就是可以让多个横切逻辑(即aop:aspect定义的)多次使用,提供可重用性。

估计很多人看了之后也是懵懵哒 . 可以从这些说法中得出, Advisor是一个特殊的Aspect, 那么为什么要有Advisor呢?
Advisor充当Advice(通知)和Pointcut的适配器 , 一般会有advice和pointcut属性 . 大多数切面是由定义切面行为的通知 和 定义切面在什么地方执行的切入点组合而成 . spring认识到这一点 , 提供了Advisor类 . 这个类将通知和切入点组合到一个对象中 .


通过代码来看:

准备:

业务类接口:

public interface UserService {
    public void add();
}

业务类:

@Service("userService")
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("add.......");
    }
}

客户端:

public class App {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring/applicationContext-service.xml");
        UserService userService = (UserService) ac.getBean("userService");
        userService.add();
    }
}

1.advisor:

applicationContext-service.xml

<!-- 配置包扫描器,扫描所有带@Service注解的类 -->
    <context:component-scan base-package="com.zhangyan.service"/>
    <!-- 通知类 -->
    <bean id="myAdvice" class="com.zhangyan.busi.MyAroundAdvice"></bean>

    <aop:config>
        <aop:pointcut expression="execution(* com.zhangyan.service.*.*(..))" id="myPointCut"/>
        <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut"/>
    </aop:config>

MyAroundAdvice :

public class MyAroundAdvice implements MethodInterceptor  {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("start...");
        Object val = methodInvocation.proceed();
        System.out.println("end...");
        return val;
    }
}

当调用App客户端类打印结果:

start...
add.......
end...

2.Aspect

applicationContext-service.xml

<!-- 配置包扫描器,扫描所有带@Service注解的类 -->
    <context:component-scan base-package="com.zhangyan.service"/>

    <!-- 定义通知类 -->
    <bean id="consumeAspect" class="com.zhangyan.busi.ConsumeAdvice"></bean>
    <aop:config>
        <!-- 配置切面 -->
        <aop:aspect id="myAspect" ref="consumeAspect">
            <!--定义切入点  -->
            <aop:pointcut expression="execution(* com.zhangyan.service.*.*(..))" id="myPointCut"/>
            <!-- 定义各类通知 -->
            <aop:around method="doAround" pointcut-ref="myPointCut" />  
        </aop:aspect>
    </aop:config>

ConsumeAdvice通知类:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class ConsumeAdvice {

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("start.......");
        Object retVal = pjp.proceed();  
        System.out.println("end.........");
        return retVal;  
    }   
}

当执行完App客户端后, 执行结果:

start...
add.......
end...

总结:

可以很明显看到两种实现方式,
如果使用advisor, 那么定义通知类时候, 如果是环绕通知, 通知类必须实现MethodInterceptor, 当然还有其他接口 : BeforeAdvice , ThrowsAdvice, AfterReturningAdvice 等接口.
如果使用aspect, 那么配置<’aop:around method=”doAround” pointcut-ref=”myPointCut” />, 相当于声明使用环绕通知, 那么通知类不用实现任何接口, 通知类中方法名称和配置中method相同. 通知类中方法参数应该是ProceedingJoinPoint, 就ok .
所以advisor是Spring为了简化操作, 定义这种方式, 当然也有局限, 只能有一个Pointcut和一个advice .
在advice中可以定义多个Point和advice .
配置:

<!-- 定义通知类 -->
<bean id="consumeAspect" class="com.zhangyan.busi.ConsumeAdvice"></bean>
<aop:config>
        <!-- 配置切面 -->
        <aop:aspect id="myAspect" ref="consumeAspect">
            <!--定义切入点  -->
            <aop:pointcut expression="execution(* com.zhangyan.service.*.*(..))" id="myPointCut"/>
            <!-- 定义各类通知 -->
            <aop:around method="doAround" pointcut-ref="myPointCut" />
            <aop:before method="doBefore" pointcut-ref="myPointCut"/>
            <aop:after method="doAfter" pointcut-ref="myPointCut" />
            <aop:after-throwing method="doThrowing" pointcut-ref="myPointCut" throwing="ex"/>           
        </aop:aspect>
    </aop:config>

通知类 :

public class ConsumeAdvice {

    public void doBefore(JoinPoint jp) {
        System.out.println("log Begining method: " + jp.getTarget().
                getClass().getName() + "." + jp.getSignature().getName()); 
    }

    public void doAfter(JoinPoint jp) {
        System.out.println("log Ending method: " + jp.getTarget().getClass()
                .getName() + "." + jp.getSignature().getName());  
    }

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("start.......");
        Object retVal = pjp.proceed();  
        System.out.println("end.........");
        return retVal;  
    }

    public void doThrowing(JoinPoint jp, Throwable ex) {
         System.out.println("method " + jp.getTarget().getClass().getName()
                 + "." + jp.getSignature().getName() + " throw exception");  
         System.out.println(ex.getMessage());  
    }

}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值