Spring-AOP

Posted zqlovesym

tags:

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

一.动态代理

1.创建一个接口

ArithmeticCalculator 
package com.atguigu.spring.aop.helloworld;

public interface ArithmeticCalculator {

    int add(int i ,int j);
    int sub(int i ,int j);
    int mul(int i ,int j);
    int div(int i ,int j);

}

2.创建接口的实现类

package com.atguigu.spring.aop.helloworld;

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

    @Override
    public int add(int i, int j) {
        int result = i +j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }

}

3.创建代理类

package com.atguigu.spring.aop.helloworld;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ArithmeticCalculatorLoggingProxy {
    //要代理的对象
    private ArithmeticCalculator target;
    
    
    public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
        this.target = target;
    }


    public ArithmeticCalculator getLoggingProxy(){
        ArithmeticCalculator proxy = null;
        //代理对象由哪一个类加载器负责加载
        ClassLoader loader = target.getClass().getClassLoader();
        //代理对象的类型,即其中有哪些方法
        Class[] interfaces = new Class[]{ArithmeticCalculator.class}; 
        
        //当调用代理对象其中的方法时,该执行的代码
        InvocationHandler h = new InvocationHandler() {
            /**
             * proxy:正在返回的那个代理对象,一般情况下,在invoke方法中都不使用该对象
             * method:正在被调用的方法
             * args:调用方法时,传入的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                //日志
                System.out.println("【before】The method" + method + "begins with "+Arrays.asList(args));
                //执行方法
                Object result = null;
                try {
                    //前置通知
                    result = method.invoke(target, args);
                    //返回通知
                } catch (Exception e) {
                    e.printStackTrace();    
                    //异常通知,可以访问到方法出现的异常
                }
                    
                //后置通知  因为方法可能会抛异常,所以访问不到方法的返回值
                //日志
                System.out.println("【ends】The method" + method + "ends with "+ result);
                return result;
            }
        };
        proxy = (ArithmeticCalculator)Proxy.newProxyInstance(loader, interfaces, h);
        return proxy;
    }
    
    
}

4.测试类

package com.atguigu.spring.aop.helloworld;

public class Main {

    public static void main(String[] args) {
        ArithmeticCalculator target = new ArithmeticCalculatorImpl();
        ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();
        int result = proxy.add(2, 3);
        //System.out.println("-->"+result);
    }
}

5.配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 自动扫描的包 -->
    <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>

    <!-- 使 AspectJ 的注解起作用 ,自动为匹配的类生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

 

二,Spring  AOP

1.定义接口

package com.atguigu.spring.aop.impl;

public interface ArithmeticCalculator {

    int add(int i ,int j);
    int sub(int i ,int j);
    int mul(int i ,int j);
    int div(int i ,int j);

}

2.创建接口的实现类

package com.atguigu.spring.aop.impl;

import org.springframework.stereotype.Component;

@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

    @Override
    public int add(int i, int j) {
        int result = i +j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }

}

3.创建切面

package com.atguigu.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//把这个类生命为一个切面:需要先把该类放到IOC容器中,在声明为一个切面
@Component
@Aspect
public class LoggingAspect {

    //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before(value = "execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(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. with.."+args);
    }
    
    
    
    //后置通知:在目标方法执行后(无论是否发生异常),执行的通知
    //在后置通知中还不能访问目标方法执行的结果
    @After(value = "execution(* com.atguigu.spring.aop.impl.*.*(int,int))")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("后置通知---The method  "+methodName+"  ends ");

    }
    
    /**
     * 在方法正常结束之后执行的代码
     * 返回通知 是可以返回目标方法执行的结果
     * @param joinPoint
     */
    @AfterReturning(value = "execution(* com.atguigu.spring.aop.impl.*.*(int,int))",returning = "result")
    public void afterReturning(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("返回通知---The method   " + methodName + "  ends with  " + result);
    }
    
    /**
     * 在目标方法出现异常时会执行的代码  
     * 可以访问到异常对象,且可以指定在出现特定异常时在执行的代码
     * 例如:测试的时候使用100/0   会报java.lang.ArithmeticException: / by zero  异常,
     * 但在接受的时候使用的是NullPointerException,(afterThrowing(JoinPoint joinPoint,NullPointerException ex))
     * 那么将不会执行方法
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value = "execution(* com.atguigu.spring.aop.impl.*.*(int,int))",
            throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){ 
        String methodName = joinPoint.getSignature().getName();
        System.out.println("异常通知---The method   " + methodName + " occurs exception  with  " + ex);
    }
    
    /**
     * 环绕通知需要携带ProceedingJoinPoint类型的参数
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
     * 且环绕通知必须有返回值,返回值即为目标方法的返回值。
     * @param pjd
     */
    @Around("execution(* com.atguigu.spring.aop.impl.*.*(int,int))")
    public Object aroundMethod(ProceedingJoinPoint pjd){
        Object result = null;
        String methodName = pjd.getSignature().getName();
        //执行目标方法
        try {
            //前置通知
            System.out.println("The method " + methodName + "begins with" + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("The method " + methodName + "ends with" +result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("异常通知---The method   " + methodName + " occurs exception  with  " + e);
            e.printStackTrace();
        }
        //后置通知
        System.out.println("The method " + methodName + "ends");
        return result;
    }
    
    
}

4.测试类

package com.atguigu.spring.aop.impl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        
        //1.创建Spring的IOC容器
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从IOC容器中获取Bean的实例
        ArithmeticCalculator arith = app.getBean(ArithmeticCalculator.class);
        //3.使用Bean
        int result = arith.add(3, 6);
        System.out.println("result:" + result);
        result = arith.div(100, 0);
        System.out.println("result:" + result);

    }
}

 

5.配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 自动扫描的包 -->
    <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>

    <!-- 使 AspectJ 的注解起作用 ,自动为匹配的类生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

 

6.使用的jar文件:

技术图片

 

以上是关于Spring-AOP的主要内容,如果未能解决你的问题,请参考以下文章

Spring-AOP

spring-AOP原理

spring-AOP(面向切面编程)

Spring-AOP

spring-AOP概念

Spring-AOP