栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Spring框架之AOP

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring框架之AOP

目录

一、AOP的简介

        1.1 对aop的理解?

        1.2 aop能解决的问题?

        1.3 aop的关键概念名词?

二、通知代码的分类

        2.1 前置通知

        2.2 后置通知

        2.3 环绕通知

        2.4 异常通知

        2.5 过滤通知(适配器)


一、AOP的简介

        1.1 对aop的理解?

    AOP是一种面向切面编程,可以完成一些非核心业务的功能。

        1.2 aop能解决的问题?

不需要在原有的业务逻辑中添加任何代码,就可以实现共性非业务功能。

例如:书籍的增删改,本身只需要完成增删改的功能即可,这是如果需要添加日志功能,那么需要在原有的代码基础上,去修改添加日志功能,受牵连的方法就三个(add/edit/del)了;

        1.3 aop的关键概念名词?

        AOP有一些关键性的概念名词,非常重要,我们来一一看看:

        ①:连接点(Joinpoint)

连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出。

        ②:目标对象(Target)

目标(Target):被通知(被代理)的对象

注1:完成具体的业务逻辑

        ③:通知(Advice)

通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)

注2:完成切面编程

        ④:代理(Proxy)

代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),

             例子:外科医生+护士

注3:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的

        ⑤:切入点(Pointcut)

切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点。

                 (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)

        ⑥:适配器(Advisor)

适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut) 


二、通知代码的分类

关于aop切面编程主要就是写通知,所以我们着重来看一下通知方面的一些案例!

        2.1 前置通知

        首先我们准备一些类:

        BookBiz接口类:

package com.leaf.aop.biz;

public interface BookBiz {
	
	// 购书
	public boolean buy(String userName, String bookName, Double price);

	// 发表书评
	public void comment(String userName, String comments);
	
}

        PriceException 异常类:

package com.leaf.aop.exception;


public class PriceException extends RuntimeException {

	public PriceException() {
		super();
	}

	public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public PriceException(String message, Throwable cause) {
		super(message, cause);
	}

	public PriceException(String message) {
		super(message);
	}

	public PriceException(Throwable cause) {
		super(cause);
	}
	
}

BookBizImpl实现类:就是前面说的目标对象

package com.leaf.aop.impl;

import com.leaf.aop.biz.BookBiz;
import com.leaf.aop.exception.PriceException;


public class BookBizImpl implements BookBiz {

	public BookBizImpl() {
		super();
	}

	public boolean buy(String userName, String bookName, Double price) {
		// 通过控制台的输出方式模拟购书
		if (null == price || price <= 0) {
			throw new PriceException("book price exception");
		}
		System.out.println(userName + " buy " + bookName + ", spend " + price);
		return true;
	}

	public void comment(String userName, String comments) {
		// 通过控制台的输出方式模拟发表书评
		System.out.println(userName + " say:" + comments);
	}

}

 准备工作做好了后我们就可以开始来编写第一个通知啦:

目标:实现在买书、评论前加系统日志

前置通知类:MyMethodBeforeAdvice

package com.leaf.aop.advice;

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

import org.springframework.aop.MethodBeforeAdvice;


public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
		//买书、评论前加系统日志
		//拿到目标对象的类名
		String clzName = arg2.getClass().getName();
		//拿到当前调用的方法名
		String methodName = arg0.getName();
		//调用当前方法所传递的参数
		String args = Arrays.toString(arg1);
		//系统日志
		System.out.println("【系统日志】:"+clzName+"."+methodName+"被调用,传递的参数为:"+args);
	}
	
}

配置到Spring-context.xml文件: 



	
	
	
	
	
	
	
	
	
		
		
		
		
			
				com.leaf.aop.biz.BookBiz
			
		
		
		
			
				myBefore
			
		
	
	

最后我们建立一个测试类来看看是否实现了前置通知:Demo1

package com.leaf.aop.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.leaf.aop.biz.BookBiz;

public class Demo1 {
	
    @SuppressWarnings("resource")
	public static void main(String[] args) {
		
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
		//获取目标对象
		//BookBiz bean = (BookBiz) context.getBean("bookBiz");
		//获取代理对象
		BookBiz bean = (BookBiz) context.getBean("bookProxy");
		//调用买书的方法
		bean.buy("Leaf", "《JAVA编程思想》", 58.90d);
		//调用评论的方法
		bean.comment("Leaf", "对Java代码理解更深了");
		
	}
	
}

 运行:


         2.2 后置通知

        目标:实现买书返利(存在bug)

        后置通知类:MyAfterReturningAdvice

package com.leaf.aop.advice;

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

import org.springframework.aop.AfterReturningAdvice;


public class MyAfterReturningAdvice implements AfterReturningAdvice {
	
	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
		//拿到目标对象的类名
		String clzName = arg3.getClass().getName();
		//拿到当前调用的方法名
		String methodName = arg1.getName();
		//调用当前方法所传递的参数
		String args = Arrays.toString(arg2);
		//方法调用的返回值
		System.out.println("【买书返利】:"+clzName+"."+methodName+"被调用,传递的参数为:"+args+";目标对象方法返回值为:"+arg0);
	}
	
}

然后配置到spring-context.xml的步骤和上面是一样的;

然后我们依然运行Demo1:

但是呢,这个时候我们的买书返利存在着一定的bug:

不管是买书还是评论都会有返利,这不符合常规。 

我们在后面的通知中会解决掉。 


        2.3 环绕通知

        类似拦截器,会包括切入点,目标类前后都会执行代码。

        环绕通知就等于:前置通知加上后置通知,所以我们一般就写一个环绕通知就行了。

       我们还是先写一个通知类:MyMethodInterceptor

package com.leaf.aop.advice;

import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;


public class MyMethodInterceptor implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation arg0) throws Throwable {
		//拿到目标对象的类名
		String clzName = arg0.getThis().getClass().getName();
		//拿到当前调用的方法名
		String methodName = arg0.getMethod().getName();
		
		//调用当前方法所传递的参数
		String args = Arrays.toString(arg0.getArguments());
		System.out.println("【环绕通知】:"+clzName+"."+methodName+"被调用,传递的参数为:"+args);

		//方法调用的返回值:arg0.proceed();
		Object rs = arg0.proceed();
		System.out.println("【环绕通知】:目标对象方法返回值为:"+rs);
		return rs;
	}
	
}

然后配置到spring-context.xml的步骤都还是一样的;

最后我们就还是运行Demo1测试看效果: 

        

        2.4 异常通知

        出现异常执行系统提示,然后进行处理。价格异常为例;

        但是我们的异常通知与前面三大通知又有点不一样,它不需要实现其中的方法,

但是它的方法名却又必须固定为:afterThrowing

我们一起编写一 个异常通知类来看看:MyThrowsAdvice

package com.leaf.aop.advice;

import org.springframework.aop.ThrowsAdvice;

import com.leaf.aop.exception.PriceException;


public class MyThrowsAdvice implements ThrowsAdvice {
	
	
	public void afterThrowing(PriceException p) {
		System.out.println("【异常通知】:当价格发生异常,那么执行此处代码块!!!");
	}
	
}

然后照样配置到spring-context.xml文件中;

这次我们测试Demo1的时候把价格改为负数,即为价格异常:

然后我们看看结果:

        

        2.5 过滤通知(适配器)

               这个过滤通知就可以解决:我们前面后置通知写的 返利功能 的 bug;

        但是过滤通知与其他的几大通知有所不一样,不用特别写一个通知类实现,

而是Spring提供了一个类,我们只需要在spring-context.xml中配置就好了。

我们看看如何配置:



	
	
	

	
	
		
		
		
	


	
		
		
		
		
			
				com.leaf.aop.biz.BookBiz
			
		
		
		
			
				
				myAfterPlus
			
		
	
	

然后最后我们来测试运行Demo1看看结果:

 


OK,到这里今天Leaf带来的关于Spring的AOP模块的相关知识就结束啦,有不理解的地方可以私信或者评论问我,我们下次见啦!!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1038276.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号