Spring Aop两种实现

Spring Aop两种实现

标签(空格分隔): spring


  • Spring Aop(Aspct-Orinted Programming 面向切面编程):是对传统OOP(Object-Orinted Programming,面向对象编程)的补充。

  • AOP 的主要编程对象是切面(aspect),而切面模块化横切关注点

  • 在应用Aop编程是任需要定义公共功能,但可以明确定义功能在哪里,以什么方式应用,并且不必修改送影响类,这样一来横切关注点就被模块化到特殊的对象(切面)里

  • AOP 的好处:
    每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
    业务模块更简洁, 只包含核心业务代码.

image_1c61tlq161t14e2e1i5e95f1l37m.png-76.4kB

  • 切面(Aspect) :横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
  • 通知(Advide):切面必须完成的工作
  • 目标(Target):被通知的对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 连接对象(JoinPoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置
  • 切点(pointcut):每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

Aop基于注解使用

bean.xml

<?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.zx.aop"/>

    <!-- 使 AspectJ 的注解起作用 默认使用JDK动态代理 -->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<!-- 使用 CGLib动态代理 -->
<!--<aop:aspectj-autoproxy proxy-target-class="true"/>-->
</beans>

dao层

@Repository
public interface ArithmethicCalculatorDao {
    int add(int i,int j);
    int sub(int i,int j);
    int mul(int i,int j);
    int div(int i,int j);
}

service层:

//将AirthmeticDaoImp添加到Spring容器里面
@Service
public class ArithmethicCalculatorDaoImp implements ArithmethicCalculatorDao {


    @Override
    public int add(int i, int j) {
        System.out.println("执行中" );
        return i+j;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("执行中" );
        return i-j;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("执行中" );
        return i*j;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("执行中" );
        return i/j;
    }
}

定义切面:

@Order(2)//切面的优先级,值越低优先级越高
@Aspect
@Component
public class LoggingAspect {


    /**
     *  定义一个方法,同于声明切入点表达式,一般地,该方法中再不需要添入其他的代码
     *  使用@Pointcut 来声明切入点表达式
     *  后面的其他通知直接使用方法名来引用当前的切入点表达式
     *  1. 在相同的包,其他切面引用时,需要加入的类名
     *  2. 在不同的包,其他切面引用时,需要加入包名和类名
     *
     */
    @Pointcut("execution(public int com.zx.aop.ArithmethicCalculatorDaoImp.*(int, int))")
    public void declareJointPointExpression(){

    }
    @Before("declareJointPointExpression()")
    public void beforeMethod(JoinPoint joinPoint){
        //获取切入点方法名称
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName+Arrays.asList(joinPoint.getArgs()));

        System.out.println("正在使用前置通知:"+methodName);
    }
  /*  @Before("execution(public int com.zx.aop.AirthmeticDaoImp.*(int, int))")
    public void beforeMethod(JoinPoint joinPoint){
        //获取切入点方法名称
        String methodName = joinPoint.getSignature().getName();
        System.out.println("正在使用前置通知:"+methodName);
    }*/

    //在目标方法执行后(无论是否发生异常),执行通知
    //后置通知不能还不能访问目标执行结果
    @After("execution(public int com.zx.aop.ArithmethicCalculatorDaoImp.*(int, int))")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("正在使用后置通知:"+methodName);
    }

    /**
     *  返回通知:返回通知可以获得切入点方法的返回结果
     *  1.当程序正常执行结束才会执行返回通知
     * @param joinPoint
     * @param result 返回通知返回的值
     */
    @AfterReturning(value = "execution(public int com.zx.aop.ArithmethicCalculatorDaoImp.*(int, int)))",
        returning = "result")
    public void afterReturing(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("正在使用返回通知,返回值为:"+result);
    }

    /**
     *当切入点方法发次指定的异常时才执行,异常通知
     *   public void afterThrowing(JoinPoint joinPoint,NullPointerException ex) 只有发生NullPointerException时才会执行异常通知
     * @param joinPoint
     * @param ex 指定发生那种异常时,才执行异常通知
     */
    @AfterThrowing(value = "execution(public int com.zx.aop.ArithmethicCalculatorDaoImp.*(int, int))",
        throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){
        String methodName = joinPoint.getSignature().getName();

        System.out.println(methodName+"正以使用异常通知:"+ ex);
    }

    /**
     *  环绕通知需要携带ProceedingJoinPoint 类型的参数
     *  环绕通知类似于动态代理的全过程;ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
     *  企鹅环绕通知必须有返回值,返回值即为目标方法的返回值
     * @param proceedingJoinPoint 环绕通知的必须参数,决定环绕通知是否执行
     * @return
     */
   /* @Around("execution(public int com.zx.aop.ArithmethicCalculatorDaoImp.*(int, int))")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){

        Object result = null;
        String methodName = proceedingJoinPoint.getSignature().getName();
        try {
            //前置通知
            //Arrays.asList(proceedingJoinPoint.getArgs())获取通知的的参数
            System.out.println("The method"+methodName+" begins with"+ Arrays.asList(proceedingJoinPoint.getArgs()));
            result =   proceedingJoinPoint.proceed();//环绕通知开启
            System.out.println("返回通知:"+result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知"+throwable);
        }

        System.out.println("后置通知");
        return  result;

    }*/

}

测试:

public class testAop {
    public static void main(String[] args) {
   BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml");

        ArithmethicCalculatorDaoImp airthmeticDaoImp = beanFactory.getBean("arithmethicCalculatorDaoImp", ArithmethicCalculatorDaoImp.class);

        airthmeticDaoImp.add(1,1);
        airthmeticDaoImp.sub(4,2);
        airthmeticDaoImp.mul(2,2);
        airthmeticDaoImp.div(1000,100);
    }
}

image_1c6fpojg5iif4rt18h718kbj649.png-29.9kB

AOP XML配置文件实现

<bean id="airthmeticDaoImpXml" class="com.zx.aop.ArithmethicCalculatorDaoImpXml"></bean>

    <!--  配置切面的bean -->
    <bean id="loginAspectXml" class="com.zx.aop.LoggingAspectXml"></bean>

    <bean id="vlidationAspect" class="com.zx.aop.VlidationAspect"></bean>

    <!-- 配置Aop -->
    <aop:config>
        <!-- 配置切点表达式 -->
        <aop:pointcut id="point" expression="execution(* com.zx.aop.ArithmethicCalculatorDaoImpXml.*(int,int))"/>
        <!--配置切面及通知-->
        <aop:aspect ref="loginAspectXml" order="2">
            <aop:before method="benforeK" pointcut-ref="point"/>
            <aop:after method="afterK" pointcut-ref="point"/>
            <aop:after-returning method="afterReturingK" pointcut-ref="point" returning="result"/>
        </aop:aspect>

        <!-- 配置第二个切面 和通知-->
        <aop:aspect ref="vlidationAspect" order="1">
            <aop:before method="vlidationK" pointcut-ref="point"></aop:before>
        </aop:aspect>
    </aop:config>
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

LoggingAspectXml切面设置

public class LoggingAspectXml {

    public void vaildateArgs(JoinPoint joinPoint){
        System.out.println("-->vaildateArgs"+ Arrays.asList(joinPoint.getArgs()));
    }
    public void benforeK(JoinPoint joinPoint){
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName+"正在执行前置通知");
    }
    public void afterK(JoinPoint joinPoint){
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName+"正在执行后置通知");
    }
    public void afterReturingK(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("正在使用返回通知,返回值为:"+result);
    }
}

测试:

public class TestAopXml {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-xml.xml");

        ArithmethicCalculatorDaoImpXml airthmeticDaoImpXml =  applicationContext.getBean("airthmeticDaoImpXml", ArithmethicCalculatorDaoImpXml.class);

        airthmeticDaoImpXml.add(1,1);
        airthmeticDaoImpXml.sub(100,10);


    }
}

image_1c6fprf7r17bpbmn5dl1nl81q4lm.png-23.2kB

猜你喜欢

转载自blog.csdn.net/zx6571269/article/details/79331498
今日推荐