spring-AOP的实现

AOP(面向切面编程)的理解与实现

1.什么是面向切面编程

要理解面向切面编程,必须要理解切面的含义,切面是指在程序的许多地方都会应用到的功能,例如对于日志系统来说,记录日志就可以被当做一个切面,在一个应用程序的许多地方,日志都是不可或缺的,但在这些地方,我们主要的关注点却不一定记录日志上,比如当我们在开启一个数据库连接时,我们主要关注的点在于开启连接,而不是记录日志,举个现实中的例子就是,我们日常生活中会使用到电脑,电视机,电灯等多种电器,产生的电力消耗都由电表来记录,但我们主要的关注点只在使用电器上,电表就可以理解为一个切面,面向切面编程可以将切面与应用程序解耦合

2.一些术语
  • Advice(通知):
    切面所需要的工作以及开始工作的时间,例如在使用电脑时,电表增加用电量,使用电脑之后,电表统计总的用电量,这些都是通知,通知分为以下几种
    1.前置通知(Before):目标方法被调用之前调用通知
    2.后置通知(After):目标方法被调用之后调用通知
    3.返回通知(After-Returning):目标方法成功返回之后调用通知
    4.异常通知(After-Throwing):目标方法抛出异常后调用通知
    5.环绕通知(Around):通知被包裹被通知的方法,在通知方法调用前和调用后执行自定义的行为
  • 连接点(join point):
    插入切面的一个点,例如在调用某方法之前将切面插入
  • 切点(poincut):
    在那个地方调用通知,例如在建立数据库连接的函数上
  • 切面(Aspect):
    完成工作所需要的一切,比如一个电表
  • 引入(Introduction):
    向现有类添加属性和新方法
  • 织入(Waving):
    把切面应用到目标对象创建新的代理的过程
3.例子

spring框架中实现AOP与实现DI一样不只有一种方式,这里以一场演出为例(观众为一个切面)
- 1.通过注解实现

//表演接口
    package aoptest;

    public interface Performance {
        public void perform(String name);
    }
    //表演类,注解为一个组件,用于注入单元测试类中
    package aoptest;

    import org.springframework.stereotype.Component;
    @Component("testPerformance")
    public class TestPerformance implements Performance{
        public void perform(String name){
            System.out.println("表演开始...");
            System.out.println("正在表演剧目"+name);
            System.out.println("表演结束...");
        }
    }
//spring配置类,开启自动扫描和开启AOP
    package aoptest;

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;

    @Configuration
    @ComponentScan(basePackages = "aoptest")
    @EnableAspectJAutoProxy
    public class ConcertConfig {

    }
//定义环绕通知
    package aoptest;

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;

    @Aspect
    @Component
    public class Audience {
        //定义一个切点
        @Pointcut("execution(* aoptest.Performance.perform(String)) && args(name)")
        public void performance(String name){};
        /*
        @Before("performance(name)")    //前置通知
        public void closePhone(String name){
            System.out.println("表演马上开始,关闭手机,表演的剧目           是"+name);
        }

        @AfterReturning("performance(name)")    //返回通知
            public void sayGood(String name){
                System.out.println(name+"演的好");
            }
        }
        */
        @Around("performance(name)")        //环绕通知
        public void watchPerformance(ProceedingJoinPoint joinPoint,String name){
            try{
                System.out.println("关闭手机,观众就坐,今天的剧目是"+name);
                joinPoint.proceed();//连接点
                System.out.println(name+"演的不错");
            }catch(Throwable e){
                System.out.println(name+"演的什么玩意!");
            }
        }
    }
    //测试类
    package aoptest;

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import javax.annotation.Resource;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = ConcertConfig.class)
    public class TestMain {
        Performance performance;
        @Resource(name="testPerformance")
        public void setPerformance(Performance performance){
            this.performance = performance;
        }
        @Test
        public void main(){
            performance.perform("花木兰");
            performance.perform("倩女幽魂");
        }
    }

结果如下

    关闭手机,观众就坐,今天的剧目是花木兰
    表演开始...
    正在表演剧目花木兰
    表演结束...
    花木兰演的不错
    关闭手机,观众就坐,今天的剧目是倩女幽魂
    表演开始...
    正在表演剧目倩女幽魂
    表演结束...
    倩女幽魂演的不错

    Process finished with exit code 0
  • 通过配置文件实现
    不使用注解声明切面的方式如下
<bean id="audience" class="aoptest.audience">
</bean>
<aop:config>
    <aop:aspect ref="auidence">
        <aop:before
            pointcut="execution(* aoptest.Performance.perform(..))"
            method="closePhone"/>
        <aop:after
            pointcut="execution(* aoptest.Performance.perform(..))"
            method="sayGood"/>
    </aop:aspect>
</aop:config>
声明切点并且使用切点的方式如下
<bean id="auidence" class="aoptest.auidence">
</bean>
<aop:config>
    <aop:aspect ref="auidence">
        <!--没有参数的切点
        <aop:poincut 
            id="performance"
            expression="execution(* aoptest.Performance.perform(..))"/>
        -->
        <aop:poincut 
            id="performance"
            expression="execution(* aoptest.Performance.perform(String)) and args(name)"/>
        <aop:before
            poincut-ref="performance"
            method="closePhone"/>
        <aop:after-returning
            poincut-ref="performance"
            method="sayGood"/>
        <aop:around
            pointcut-ref="performance"
            method="watchPerformance"/>
    </aop:aspect>
</aop:config>

以上就是spring两种实现AOP的方式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值