浅析AOP及其实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Snrt_Julier/article/details/78195996

AOP即面向切面的设计思想,这个思想在 Java Web 中的 Filter 最先体现,在Spring中发扬光大。


首先先说说 Filter,在 Java web 中 Filter 用于对请求对象的拦截,在 doFilter 之前,我们可以对其进行验证、字符集的处理等与主要业务逻辑不相关的操作,在之后我们也可以做一些操作。从这边我们就可以体会到AOP带来的一些好处:不对业务逻辑的源码进行改变,却也添加了功能。


其次,我们应该要谈谈 AOP 的出现,例如我现在有一个完整的项目,OOP 使得我们在该项目的纵度扩展上带来了极大的方便,但是我现在需要在不改变业务逻辑上的源码的基础上 对其中的关键的一些操作进行日志操作,在 OOP 的指导下就显得有些不给力了。这大概就是所谓的对项目的横向扩展。而 AOP 就是对 OOP 造横向扩展不足的补充。下面就来解决上述需求。


方案一:子类继承父类,重写父类所要横向扩展的方法。

例子:

public class Parent {

	public void detail() {
		System.out.println("parent需要做日志的关键方法");
	}
}
public class Son extends Parent {


	@Override
	public void detail() {
		System.out.println("日志文件:即将调用detail方法");
		super.detail();
		System.out.println("日志文件:detail方法调用完毕");
	}
}
这样我们就可以在不改变原业务逻辑的基础上对其添加了日志功能的需求。

方案二:使用代理模式,其实刚刚的做法也就是一个最初步的代理模式。

首先先定义一个接口

public interface IParent {

	void detail();
}

其次对 Parent 的做一些改变

public class Parent implements IParent{

	public void detail() {
		System.out.println("parent需要做日志的关键方法");
	}
}

最后实现一个代理类

public class ParentProxy implements IParent{
	private IParent target;
	
	public ParentProxy(IParent target) {
		super();
		this.target = target;
	}

	public IParent getTarget() {
		return target;
	}

	public void setTarget(IParent target) {
		this.target = target;
	}

	@Override
	public void detail() {
		System.out.println("日志文件:即将调用detail方法");
		target.detail();
		System.out.println("日志文件:detail方法调用完毕");
	}
	
}

这样也实现了所要的需求,为啥要使用接口(面向接口的编程的优点,呵呵),这其实是一种静态代理模式,与方案一孰优孰劣我感觉半斤八两。确定同样明显,若是有很多类,呵呵呵呵,继承或代理类的数量不敢想象。

方案三:代理模式——基于JDK的动态代理模式,这种方式据说是用了两层代理,我看的不是很明白

在这种模式下前两者(接口和业务逻辑)是不需要多做改变。只是对静态代理的代理对象进行修改。

public class DyProxyFactory implements InvocationHandler{
	private Object target;
	
	/**
	 * 构建代理对象
	 * @param target
	 * @return
	 */
	public Object bulidProxy(Object target) {
		if(target != null){
			this.target = target;
		}
		return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("开始调用"+target.getClass().getName()+"de"+method.getName());
		Object returnValue = method.invoke(target, args);
		System.out.println(target.getClass().getName()+"de"+method.getName()+"调用结束");
		return returnValue;
	}
	
	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

}
上面的代码与其说是一个动态代理类倒不如说是一个动态代理对象的工厂,你给一个需要代理的对象,我给你一个代理类。

动态代理的详解

上面说了那么多其实也就是 AOP 的一些常用的实现方式。这种设置思想带来的好处只有以后慢慢去体味了


添加内容:

作者:知乎用户
链接: https://www.zhihu.com/question/24863332/answer/48376158
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。
也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢? 这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。
这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。
AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。




猜你喜欢

转载自blog.csdn.net/Snrt_Julier/article/details/78195996
今日推荐