AOP的理解

    AOP也就是传说中的“面向切面编程”,是一种新的方法论,也是对传统的OOP的补充,AOP的主要的编程对象是切面,切面模块化横切关注点。

    以上的就是比较专业的概述了什么是AOP,当然还有一大堆术语像切点,连接点,切面啥的我就不累赘了,这些东西编程的次数多了自然就熟悉了,这里我用比较浅显易懂的方式和大家说一下什么是AOP。

    AOP是面向切面的,编写的传统的C++和JAVA程序是面向对象的,也就是OOP了,之所以一开始大家(我也一样)对AOP的概念非常模糊,看了很多博客也不能很清晰的说出了个一二三来,原因很简单,就是没有自己去写一个AOP的程序,编程这块我觉得动手才是最重要的,一会儿我会用一个简单的程序去说明AOP。在此之前呢,还是大概说一下对AOP的理解,当然我不会用术语尽量说的明白。

    大家都知道,写出的代码很注重所谓的“重用性”,要是想让自己的程序能够反复的利用,那必须做到一点,每次修改的时候只是修改一部分,而不是脱胎换骨。虽然面向对象的提出解决了很多的问题,但是也不能做的完美无缺,比如:比如我们要对两个数进行数学运算:加减乘除。但是有个要求,那就是加入日志,在运算之前要记录两个数,在运算之后要记录运算结果。为了方便就直接输出相应的信息就好了,那么我们先定义一个接口:

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);
}
那么我们在去写一个类去实现这个接口(用传统的方法):

public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) 
	{
		System.out.println("the method add begins with["+ i +","+ j +"]");
		int result = i+j;
		System.out.println("the method add ends with " + result);
		return result;
	}

	@Override
	public int sub(int i, int j) 
	{
		System.out.println("the method sub begins with["+ i +","+ j +"]");
		int result = i-j;
		System.out.println("the method sub ends with " + result);
		return result;
	}

	@Override
	public int mul(int i, int j) 
	{
		System.out.println("the method mul begins with["+ i +","+ j +"]");
		int result = i*j;	
		System.out.println("the method mul ends with " + result);
		return result;
	}

	@Override
	public int div(int i, int j) 
	{
		System.out.println("the method div begins with["+ i +","+ j +"]");
		int result = i/j;	
		System.out.println("the method div ends with " + result);
		return result;
	}

}
    想必在这里大家都能看懂,这很符合要求是不是,但是大家发现一个问题了没有,每个方法中我们都为了日志输出了两次,但是每个方法的输出时候很相似的,如果这时候我想改变输出的语句,是不是每个方法都要重新写一遍,这样是很麻烦的。于是我们就想,能不能在运行的时候插入我们想要的呢?而不是直接在函数和里面写。在外面看起来就像是在一个类中插入了相应的代码,那这个OOP就不能实现了。于是一咬牙一跺脚,AOP出来吧!于是所谓的面向切面编程就诞生了,从这里大家应该对这个所谓的“切面”有所了解了吧,或者说有点感觉了,其实这个“切面”可以理解成针对与一个类中的某个部分(也许不怎么恰当,先将就着看吧)。

    说了半天,那么这个程序如果用面向切面的思想来写会是什么样的呢?

    首先实现接口的类变了,变成啥了嗯?看看代码:

package calculate;

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;
	}

}
    很明显,没有了那些繁杂的输出语句,剩下的这些add,sub,mul,div函数可以叫做业务逻辑。那么去掉的那些前置日志,后置日志呢叫啥呢?那就是切面了。好了那么怎么实现之前的功能呢?那就要写一个代理类了。

public class ArithmeticCalculatorLogginProxy 
{
	//要代理的对象
	private ArithmeticCalculator target;
	
	public ArithmeticCalculatorLogginProxy(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();
				//日志1
				System.out.println("the method "+ methodName + " begins with " + Arrays.asList(args));
				//执行方法
				Object result = method.invoke(target, args);
				//日志2
				System.out.println("The method " + methodName + " ends with " + result);
				return result;
			}
		};
		proxy = (ArithmeticCalculator)Proxy.newProxyInstance(loader, interfaces, h);
		
		return proxy;
	}

}
    也许大家对这个proxy东西不怎么熟悉,没事,其实这玩意就是起到一个代理的功能。主要是编写invoke函数来帮我们完成应该完成的任务。这里可以看出,如果再想改变输出语句的内容,只需要该两行函数就好了。是不是很方便!

    那么写一个测试程序测试一下呗。

public class Main
{
	public static void main(String[] args) 
	{
		/*
		ArithmeticCalculator arithmeticCalculator = null;
		arithmeticCalculator = new ArithmeticCalculatorLoggingImpl();
		*/
		
		ArithmeticCalculator target = new ArithmeticCalculatorImpl();
		ArithmeticCalculator proxy = new ArithmeticCalculatorLogginProxy(target).getLoggingProxy();
		
		int result = proxy.add(1, 2);
		System.out.println("result------>" + result);

	}
}

      上面注释的就是测试之前最传统的写法的,得到的结果肯定都是一样的。


       这就是所谓的AOP了,不知道看了有没有比之前对AOP有感觉了没有哈哈。

       另外说一句,AOP和IOC都是学Spring的时候接触也是才开始学的,毕竟Spring是基于这两个玩意的,好消息是Sping的AOP实现比较简单,不需要像我一样去写一个代理类。封装就是好呀,哈哈大笑





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值