Spring(三)-AOP

2017-07-19  本文已影响0人  yzw12138

一、AOP作用

代码混乱:越来越多的非业务需求(日志、验证等)加入后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑时还必须其他多个兼顾点。
代码分散:一日只需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)中多次重复相同的日志代码,如果日支需求发生改变,必须修改所有模块代码。

二、AOP简介

Paste_Image.png Paste_Image.png

三、Spring AOP框架

(一)AspectJ

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.imooc.aop.impl">  </context:component-scan>
    <!-- 使AspjetJ注解起作用:为匹配的类声明代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

4、当SpringIOC容器侦测到bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动为与AspectJ切面配置的bean创建代理;创建一个切面类,目的是为了在被代理对象方法执行前执行此类中的方法,在方法前添加通知(注释),并说明在哪个方法目的执行前执行(通知注解详见Spring通知注解

//把这个类声明为一个切面:需要把该类放入IOC容器、在声明一个切面
@Aspect//声明一个切面
@Component//放入IOC容器
public class LoggingAspect {
    //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before("execution(public int com.imooc.aop.impl.ArithmeticCalculator.add(int, int))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName=joinPoint.getSignature().getName();
        List<Object> args=Arrays.asList(joinPoint.getArgs());
        System.out.println("The method "+methodName+" begins "+args);
    }
}
public static void main(String[] args) {
        
        //1、创建Spring的IOC容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、从IOC容器中获取bean的实例
        ArithmeticCalculator arithmeticCalculator=ctx.getBean(ArithmeticCalculator.class);
        //3、使用bean
        int result=arithmeticCalculator.add(3, 6);
        System.out.println("result:"+result);
    }
Paste_Image.png
public class LoggingAspect {
    //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before("execution(* com.imooc.aop.impl.*.*(int, int))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName=joinPoint.getSignature().getName();
        List<Object> args=Arrays.asList(joinPoint.getArgs());
        System.out.println("The method "+methodName+" begins "+args);
    }

AspectJ支持五种通知注解:

//把这个类声明为一个切面:需要把该类放入IOC容器、在声明一个切面
@Aspect//声明一个切面
@Component//放入IOC容器
public class LoggingAspect {
    //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before("execution(public int com.imooc.aop.impl.ArithmeticCalculator.add(int, int))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName=joinPoint.getSignature().getName();
        List<Object> args=Arrays.asList(joinPoint.getArgs());
        System.out.println("The method "+methodName+" begins "+args);
    }
}
    //后置通知:在目标方法执行后(无论是否发生异常),执行通知
    //在后置通知中还不能访问目标方法执行的结果
    @After("execution(* com.imooc.aop.impl.*.*(int, int))")
    public void afterMethod(JoinPoint joinPoint){
        String methodName=joinPoint.getSignature().getName();
        
        System.out.println("The method "+methodName+" end ");
    }
/*
     * 在方法正确执行后执行的代码
     * 返回通知是可以访问到方法的返回值的
     */
    @AfterReturning(value="execution(* com.imooc.aop.impl.*.*(int, int))",
            returning="result")
    public void afterReturntingMethod(JoinPoint joinPoint,Object result){
        String methodName=joinPoint.getSignature().getName();
        
        System.out.println("The method "+methodName+" end "+result);
    }
//可以访问到方法出现的异常
//可以访问到异常对象;且可以指定再出现特定异常时在执行通知代码
@AfterThrowing(value="execution(* com.imooc.aop.impl.*.*(int, int))",
            throwing="ex")
    //public void afterThrowingMethod(JoinPoint joinPoint,NullPointerException ex){
    public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
        String methodName=joinPoint.getSignature().getName();
        
        System.out.println("The method "+methodName+" occurs excetion:"+ex);
    }
/*
     * 环绕通知:必须携带ProceedingJoinPoint类型参数
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
     * 且环绕通知必须有返回值,返回值即为目标方法的返回值
     */
    @Around("execution(* com.imooc.aop.impl.*.*(int, int))")
    public Object aroundMethod(ProceedingJoinPoint pdb){
        Object result=null;
        String methodName=pdb.getSignature().getName();
        
        try {
            //前置通知
            System.out.println("The method "+methodName+" begins "+Arrays.asList(pdb.getArgs()));
            //执行目标方法
            result=pdb.proceed();
            //后置通知
            System.out.println("The method "+methodName+" end "+result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("The method "+methodName+" occurs excetion:"+e);
            throw new RuntimeException(e);
        }
        return result;
    }

四、基于xml文件配置AOP

    <!-- 配置 bean -->
    <bean id="arithmeticCalculator" 
        class="com.atguigu.spring.aop.xml.ArithmeticCalculatorImpl"></bean>

    <!-- 配置切面的 bean. -->
    <bean id="loggingAspect"
        class="com.atguigu.spring.aop.xml.LoggingAspect"></bean>

    <bean id="vlidationAspect"
        class="com.atguigu.spring.aop.xml.VlidationAspect"></bean>

    <!-- 配置 AOP -->
    <aop:config>
        <!-- 配置切点表达式 -->
        <aop:pointcut expression="execution(* com.atguigu.spring.aop.xml.ArithmeticCalculator.*(int, int))" 
            id="pointcut"/>
        <!-- 配置切面及通知 -->
        <aop:aspect ref="loggingAspect" order="2">
            <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
            <aop:after method="afterMethod" pointcut-ref="pointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
            <!--  
            <aop:around method="aroundMethod" pointcut-ref="pointcut"/>
            -->
        </aop:aspect>   
        <aop:aspect ref="vlidationAspect" order="1">
            <aop:before method="validateArgs" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
上一篇下一篇

猜你喜欢

热点阅读