Spring — 6.AOP面向切面编程

1、概述

  • AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程
  • AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2、原理以及优势

对原有【纵向】的代码,【横向】植入【内容】的对原有的代码进行【影响】

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强

优势:减少重复代码,提高开发效率,并且便于维护

3、实现(配置文件方式和注解方式)

几个专业的名字,如图所示进行解释:

Spring中自定义的5个增强类型 

增强/通知类型实现接口描述
前置增强org.springframework.aop.BeforeAdvice目标方法执行前实施增强
后置增强org.springframework.aop.AfterReturningAdvice在目标方法执行后实施增强
环绕增强org.aopalliance.intercept.MethodInterceptor在目标方法执行前后实施增强
异常抛出增强org.springframework.aop.ThrowsAdvice在目标方法抛出异常后实施增强
引介增强org.springframework.aop.IntroductionInterceptor在目标类中添加一些新的方法和属性

        3.1 xml实现一

step1:定义目标对象

UserService.java

package com.tc.service;

public interface UserService {
    public void addUser();

    public void deleteUser();
}

UserServerImp.java 

public class UserServiceImp implements UserService {
    public void addUser() {
        System.out.println("添加了一个user");
    }

    public void deleteUser() {
        System.out.println("删除了一个user");
    }
}

 step2定义切面以及增强/通知

切面A:前置增强/通知——MethodBeforeAdvice

public class Log implements MethodBeforeAdvice {
    /**
     *  method:目标对象的方法
     *  objects:参数
     *  o:目标对象
     *
      */
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了,参数为"+objects.toString());
    }
}

切面B:后置增强/通知——AfterReturningAdvice

public class AfterLog implements AfterReturningAdvice {
    /**
     * o:返回值
     *  method:目标对象的方法
     *  objects:参数
     *  o1:目标对象
     *
     */
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("后置增强:执行了"+o1.getClass().getName()+"的"+method.getName()+"方法,返回值为:"+o);
    }
}

step3:Bean注入

 <!--加载类到spring-->
    <bean id="userService" class="com.tc.service.UserServiceImp"></bean>
    <bean id="beforeLog" class="com.tc.aspect.BeforeLog"></bean>
    <bean id="afterLog" class="com.tc.aspect.AfterLog"></bean>

step4:定义连接点,以及切入点

1、execution(): 表达式主体 (必须加上execution)。

 2、第一个*号:表示返回值类型,*号表示所有的类型。

 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,cn.smd.service.impl包、子孙包下所有类的方法。

 4、第二个*号:表示类名,*号表示所有的类。

 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

书写的注意事项:execution(* cn.smd.service.impl.*.*(..))

<!--配置aop-->
    <aop:config>
        <!--定义切入点-->
        <aop:pointcut id="logAspect" expression="execution(* com.tc.service.UserService.*(..))"/>

        <!--定义连接点-->
        <!--前置通知/增强-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="logAspect" ></aop:advisor>
        <!--后置通知/增强-->
        <aop:advisor advice-ref="afterLog" pointcut-ref="logAspect" ></aop:advisor>
    </aop:config>

step5:调用测试

ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)applicationContext.getBean("userService");
userService.addUser();

输出:

        3.2 xml实现二

step1:定义目标对象,同上

step2:定义切面以及通知/增强定义

不需要实现任何接口,只是一个普通的类,类里面包括多个方法

public class commonAspect {
    public void beforeFunc(){
        System.out.println("前置增强");
    }
    public void afterFunc(){
        System.out.println("后置增强");
    }
}

 step3:切入点以及连接点定义

 <!--定义切面-->
<aop:aspect ref="commonAspect">
     <!--定义切入点-->
     <aop:pointcut  id="point" expression="execution(* com.tc.service.UserServiceImp.*(..))" ></aop:pointcut>
     <!--定义增强-->
       <aop:before method="beforeFunc" pointcut-ref="point"></aop:before>
       <aop:after method="afterFunc" pointcut-ref="point"></aop:after>
</aop:aspect>

        3.3 注解实现

切面,通知/增强,切入点,连接点都在类中定义

@Aspect
public class annoAspect {
    @Before("execution(* com.tc.service.UserServiceImp.*(..))")
    public void beforeFunc(){
        System.out.println("前置增强----");
    }

    @After("execution(* com.tc.service.UserServiceImp.*(..))")
    public void afterFunc(){
        System.out.println("后置增强");
    }

    @Around("execution(* com.tc.service.UserServiceImp.*(..))")
    public void aroundFunc(ProceedingJoinPoint process) throws Throwable {
        System.out.println("环绕增强前");
        Object obj = process.proceed();// 执行模板方法
        System.out.println("环绕增强后");
    }
}

@Aspet定义切面,相当于:

<bean id="commonAspect" class="com.tc.aspect.commonAspect"></bean>  
<aop:aspect ref="commonAspect">
           xxxx
</aop:aspect>

@Before("execution(* com.tc.service.UserServiceImp.*(..))")注解中的内容,为定义连接点,相当于:

<!--定义切入点-->
<aop:pointcut  id="point" expression="execution(* com.tc.service.UserServiceImp.*(..))" ></aop:pointcut>

@Before,@After,@around...定义切入点,相对于:

<!--定义连接点-->
<aop:before method="beforeFunc" pointcut-ref="point"></aop:before>
<aop:after method="afterFunc" pointcut-ref="point"></aop:after>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值