spring AOP 基础(认真看完,保证你对aop的实际运用了如指掌)

------------------------------------------------基于动态代理实现springAOP--------------------------------------------

在没有aop之前,在一个项目中,要是对某几个方法进行日志处理的话就会出现很多重复的代码,导致核心代码块变的很冗长和难以维护,在此现实问题中。像类似于aop思想就可以解决,

动态代理实例:

package com.example.springtest.factoryandproxy.inter;

/**
 * ***GOOD LUCK****
 *
 * @Author : Wukn
 * @Date : 2018/6/
 */
public interface MateInter {

    public void add(Integer i);

    public void delete(String str);
}
package com.example.springtest.factoryandproxy.proxy;

import com.example.springtest.factoryandproxy.inter.MateInter;

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

/**
 * ***GOOD LUCK****
 *
 * @Author : Wukn
 * @Date : 2018/9/
 *
 * 代理对象
 */
public class OperationLoggerProxy {
    /**
     * 需要被代理的对象
     */
    public MateInter target;

    public OperationLoggerProxy(MateInter operation) {
        this.target = operation;
    }

    public MateInter getOperationFactory() {
        MateInter operation = null;

        //代理对象由哪一个类加载器负责
        ClassLoader classLoader = target.getClass().getClassLoader();
        //代理对象的类型。即其中有哪些方法
        Class[] op = new Class[]{MateInter.class};
        //当调用代理对象其中的方法时,改执行得1代码
        InvocationHandler handler = new InvocationHandler( ) {

            /**
             *
             * @param proxy   z正在返回那个代理对象,一般情况下都不使用
             * @param method  正在被调用的方法
             * @param args     调用方式时,传入的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    String methodName = method.getName();
                //前置  日志
                System.out.println("Logger"+methodName+ Arrays.asList( args));
                
                //执行方法
                Object result = null;
                try {
                    //返回  通知
                    result = method.invoke(target,args  );
                } catch (Exception e) {
                    //异常
                    e.printStackTrace( );
                }
                
                //后置   日志
                System.out.println(methodName+result+"");

                return result;
            }
        };
        //MateInter    这里返回的方法只能是接口
        operation = (MateInter) Proxy.newProxyInstance( classLoader,op,handler );


        return operation;
    }










}

 

 

在实际的运用用其实可以使用动态代理完成日志的打印,但是这样操作比较麻烦,于是就可以使用aop实现、

 

 

 

 

 

 

 

 

 

 

------------------------------------------------基于AspectJ实现springAOP-------------------------------------------

基于注解方式的AOP实现方式

1:首先导入相关AcpectJ的包

<dependency>
			<groupId>org.assertj</groupId>
			<artifactId>assertj-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjtools</artifactId>
			<version>1.8.9</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.9</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjtools</artifactId>
			<version>1.8.9</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

2:对于普通的spring项目,需要在xml配置文件中开启全局扫描和添加支持AspectJ的扫描

springboot项目中,只需要注解就可以

package com.example.springtest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
//扫描支持AcpectJ
@EnableAspectJAutoProxy
//全局扫描
@ComponentScan(value = "com.example.springtest")
public class SpringtestApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringtestApplication.class, args);
	}
}

3:定义切面,切面就是一个包含所有需要设置的切点的类,该类里面有需要执行的方法

package com.example.springtest.AspectJDemo.Acpect;

/**
 * ***GOOD LUCK****
 *
 * @Author : Wukn
 * @Date : 2018/6/
 */

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

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

/**把这个类申明为一个切面
 * 需要把该类放到IOC容器中,在申明一个切面
 */
@Aspect
@Component
public class LoggerAcpectJ {


    /**
     * 申明该方法是一个前置通知,在目标方法执行之前
     */
    @Before(  "execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))" )
    public void beforeMethod(JoinPoint joinPoint) {
        //方式名称
        String methodName = joinPoint.getSignature().getName();
        //参数
       List<Object> args =  Arrays.asList( joinPoint.getArgs() ) ;
       System.out.println(methodName+args);
        System.out.println("前置日志。。。。。。。。。");
    }


    /**
     * 后置通知,在目标方法执行后(无论改方法是否出现异常)的操作
     * 在后置通知中,还不能访问目标方法执行的结果
     */
    @After( "execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))" )
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList( joinPoint.getArgs() );
        System.out.println(methodName+args);
        System.out.println("后置通知日志。。。。。。。。。。。。。。");
    }


    /**
     * 在方法正常执行后执行的代码,无论该方法是否有异常
     * returning ="result"    该方法的返回值
     */
    @AfterReturning(value = "execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))",
            returning ="result")
    public void returnMethod(JoinPoint joinPoint,Object result) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList( joinPoint.getArgs() );
        System.out.println(methodName+args+result);
        System.out.println("返回通知。。。。。。");
    }



    /**
     * 目标方法出现异常时异常通知,可以访问异常对象
     * throwing ="ex"    返回的异常
     * Exception ex  这个异常可以指定特定的异常
     *
     */
   @AfterThrowing(value = "execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))",throwing = "ex")
    public void MethodThrow(JoinPoint joinPoint,Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList( joinPoint.getArgs() );
        System.out.println(methodName+args+ex);
        System.out.println("返回通知。。。。。。");
    }


    /**
     * 环绕通知需要携带ProceedingJoinPoint类型的参数,
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数,可以决定是否执行目标方法
     * 环绕通知必须有返回值,返回值为目标方法的返回值
     * @param point
     */
    @Around( value = "execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))" )
    public Object aroundMethod(ProceedingJoinPoint point) {
        Object result = null;
        String methodName = point.getSignature().getName();
        //执行目标方法
        try {
            //前置通知
            System.out.println("前置通知。。。"+methodName+Arrays.asList( point.getArgs() ));
            //目标对象的返回结果
            result = point.proceed();
            //后置通知
            System.out.println("后置通知。。。"+methodName+result);
        } catch (Throwable throwable) {
            //异常通知
            System.out.println("异常通知。。。"+throwable);
        }
        //后置通知
        System.out.println("环绕通知。。。。。。。。。");
        return 10086;
    }










}

 

 

 

 

 

 

 

 

 

 

--------------------------------------------------指定切面的优先级--------------------------------------------------------------

 

* 可以使用@Order(1)指定切面的优先级,值越小,优先级越高
package com.example.springtest.AspectJDemo.Acpect;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

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

/**
 * ***GOOD LUCK****
 *
 * @Author : Wukn
 * @Date : 2018/9/3
 *
 * 可以使用@Order(1)指定切面的优先级,值越小,优先级越高
 *
 */
@Order(1)
@Aspect
@Component
public class VlidationAspectJ {



    /**
     * 申明该方法是一个前置通知,在目标方法执行之前
     */
    @Before(  "execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))" )
    public void beforeVliationMethod(JoinPoint joinPoint) {
        //方式名称
        String methodName = joinPoint.getSignature().getName();
        //参数
        List<Object> args =  Arrays.asList( joinPoint.getArgs() ) ;
        System.out.println(methodName+args);
        System.out.println("前置参数。。。。。。。。。");
    }



}

 

 

 

 

  ---------------------------------------------重用切点表达式---------------------------------------------------

 

package com.example.springtest.AspectJDemo.Acpect;

/**
 * ***GOOD LUCK****
 *
 * @Author : Wukn
 * @Date : 2018/6/
 */

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

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

/**把这个类申明为一个切面
 * 需要把该类放到IOC容器中,在申明一个切面
 */
@Order(2)
@Aspect
@Component
public class LoggerAcpectJ {


    /**
     * 定义一个方法,用于申明切入点表达式,一般的该方法不需要再填入其他的代码
     *
     * 使用@Pointcut来申明切入点表达式
     * 后面的其他通知直接使用方法名
     */
    @Pointcut("execution(* com.example.springtest.AspectJDemo.service.MathInterImpl.add(..))")
    public void declareJointPointExpression() {
    }





    /**
     * 申明该方法是一个前置通知,在目标方法执行之前
     */
    @Before(  "declareJointPointExpression()" )
    public void beforeMethod(JoinPoint joinPoint) {
        //方式名称
        String methodName = joinPoint.getSignature().getName();
        //参数
       List<Object> args =  Arrays.asList( joinPoint.getArgs() ) ;
       System.out.println(methodName+args);
        System.out.println("前置日志。。。。。。。。。");
    }


    /**
     * 后置通知,在目标方法执行后(无论改方法是否出现异常)的操作
     * 在后置通知中,还不能访问目标方法执行的结果
     */
    @After( "declareJointPointExpression()" )
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList( joinPoint.getArgs() );
        System.out.println(methodName+args);
        System.out.println("后置通知日志。。。。。。。。。。。。。。");
    }


    /**
     * 在方法正常执行后执行的代码,无论该方法是否有异常
     * returning ="result"    该方法的返回值
     */
    @AfterReturning(value = "declareJointPointExpression()",
            returning ="result")
    public void returnMethod(JoinPoint joinPoint,Object result) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList( joinPoint.getArgs() );
        System.out.println(methodName+args+result);
        System.out.println("返回通知。。。。。。");
    }



    /**
     * 目标方法出现异常时异常通知,可以访问异常对象
     * throwing ="ex"    返回的异常
     * Exception ex  这个异常可以指定特定的异常
     *
     */
   @AfterThrowing(value = "declareJointPointExpression()",throwing = "ex")
    public void MethodThrow(JoinPoint joinPoint,Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList( joinPoint.getArgs() );
        System.out.println(methodName+args+ex);
        System.out.println("返回通知。。。。。。");
    }


    /**
     * 环绕通知需要携带ProceedingJoinPoint类型的参数,
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数,可以决定是否执行目标方法
     * 环绕通知必须有返回值,返回值为目标方法的返回值
     * @param point
     */
    @Around( value = "declareJointPointExpression()" )
    public Object aroundMethod(ProceedingJoinPoint point) {
        Object result = null;
        String methodName = point.getSignature().getName();
        //执行目标方法
        try {
            //前置通知
            System.out.println("前置通知。。。"+methodName+Arrays.asList( point.getArgs() ));
            //目标对象的返回结果
            result = point.proceed();
            //后置通知
            System.out.println("后置通知。。。"+methodName+result);
        } catch (Throwable throwable) {
            //异常通知
            System.out.println("异常通知。。。"+throwable);
        }
        //后置通知
        System.out.println("环绕通知。。。。。。。。。");
        return 10086;
    }










}

 

 

 

 

 

-----------------------------------基于配置文件的方法实现spring aop--------------------------------------------

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <!--<context:component-scan base-package="com.example.springtest"></context:component-scan>-->



    <!--配置目标方法的bean-->
    <bean id="m1" class="com.example.springtest.AspectJDemo.service.MathInterImpl"></bean>



    <!--配置切面bean1-->
    <bean id = "logger1" class="com.example.springtest.AspectJDemo.Acpect.LoggerAcpectJ"></bean>

    <!--配置切面bean2-->
    <bean id="vali1" class="com.example.springtest.AspectJDemo.Acpect.VlidationAspectJ"></bean>


    <!--配置aop-->
    <aop:config>
        <!--配置切点表达式-->
        <aop:pointcut  expression="execution(* com.example.springtest.AspectJDemo.service.MateInter.*(..))" id="pointcut"></aop:pointcut>
        <!--配置切面及通知1-->
        <aop:aspect ref="logger1" order="1">
            <!--前置通知-->
            <aop:after method="beforeMethod" pointcut-ref="pointcut"></aop:after>
            <!--后置通知-->
            <aop:before method="beforeMethod"  pointcut-ref="pointcut"></aop:before>
            <!--返回通知-->
            <aop:after-returning method="returnMethod" pointcut-ref="pointcut" returning="result"></aop:after-returning>
        </aop:aspect>

        <!--配置切面及通知2-->
        <aop:aspect ref="vali1" order="2">
            <aop:after method="beforeVliationMethod" pointcut-ref="pointcut"></aop:after>
        </aop:aspect>
    </aop:config>










</beans>

 

 

 

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

托尼吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值