Spring旅程(三) AOP--Spring AOP容器基础(二)

2014-11-24 00:07:36 · 作者: · 浏览: 2
的角度来说,这种遍布在系统中的独立的服务,称为横切性的关注点。纵向的是方法一调用方法二,方法二调用方法三,而这个服务是切入到各个方法上的,所以认为是横向的。我们可以使用动态代理来解决这个问题。

使用动态代理解决问题

动态代理,我们要实现一个系统的处理器InvocationHandler,它可以复用,不需要每个方法一个代理,并且是在运行时声明出来的,可以为各个接口服务。把横切性的问题拿出来放到一个单独的类中,上述例子中,我们删除我们自己手动写的代理类,新建SecurityHandler类,实现InvocationHandler这个接口。

代码如下所示。

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

public class SecurityHandler implements InvocationHandler {

	private Object targetObject;
	
	public Object createProxyInstance(Object targetobject)
	{
		this.targetObject = targetobject;
		//根据目标生成代理.
		//代理是对接口来说的,是拿到目标的接口.拿到这个接口,实现这个接口.
		//targetobject这个目标类实现了哪个接口.
		//返回代理.
		 return Proxy.newProxyInstance(targetobject.getClass().getClassLoader(),
				targetobject.getClass().getInterfaces(), this);
	}
	
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		
		//检查安全性.
		checkSecurity();
		
		//当前方法,调用目标对象的方法.
		//调用目标方法.
		Object ret =  method.invoke(targetObject, args);
		
		return ret;
	}


	//检查安全性.
	private void checkSecurity()
	{
		System.out.println("------------UserManagerImpl.checkSecurity()----");
	}

}


这个代理类是运行时创建的,是动态的,而编译时创建的是静态的。TargetObject目标,建立目标实例createProxyInstance(),根据目标生成代理Proxy.newProxyInstance(),在invoke()方法中设置允不允许调用真正的对象,在invoke()中进行检查安全性控制,在invoke()中统一做控制,就像Filter中的doFilter方法。

客户端调用,代码如下所示。

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		SecurityHandler hander = new SecurityHandler();
		//返回的是一个代理类,不是真正的UserManager.而是指向代理类.在内存中.
		UserManager userManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());
		//使用的是代理.
		//共同的接口,不同的实现.
		userManager.addUser("张三", "123");
		
		
	}

}


接下来让我们走入Spring的AOP,他是如何实现的呢?如下图所示。

\


AOP中的基本概念和术语。

1、 切面(Aspect)

切面就是一个抽象出来的功能模块的实现,例如上述安全性检查,可以把这个功能从系统中抽象出来,用一个独立的模块描述,这个独立的模块就是切面,我们的SecutiryHinder类。

2、 连接点(JoinPoint)

连接点即程序运行过程中的某个阶段点,可以是方法调用、异常抛出等,在这个阶段点可以引入切面,从而给系统增加新的服务功能。

3、 通知(Advice)

通知即在某个连接点所采用的处理逻辑,即切面功能的实际实现。通知的类型包括Before、After、Around以及Throw四种,下篇文章将会展示通知的使用方法。

4、 切入点(PointCut)

接入点即一系列连接点的集合,它指明通知将在何时被触发。可以指定能类名,也可以是匹配类名和方法名的正则表达式。当匹配的类或者方法被调用的时候,就会在这个匹配的地方应用通知。

5、 目标对象(Target)

目标对象就是被通知的对象,在AOP中,目标对象可以专心实现自身的业务逻辑,通知功能可以在程序运行期间自动引入。

6、 代理(Proxy)

代理是目标对象中使用通知以后创建的对象,这个对象既拥有目标对象的全部功能,而且拥有通知提供的附加功能。



理解上述术语还是先用比较通俗的方式来解释,对于切面,我们在中学中学习过,切线,切面,切点,对于数学中学习的我们一定都不陌生。

\

如果仍然还是抽象的话,我们知道嫦娥一号与月球对接,嫦娥一号所要完成的任务或功能就是我们的切面(Aspect),带探究月球生命的使命;连接点(JoinPoint)就是总台发出命令,来触发嫦娥一号升空,这个发出的命令触发点就是JoinPoint;通知(Advice)就是具体的去执行总台的命令,包括集中类型是在总台发出命令之前(Before)、之后(After)、Around(大约多长时间)、或系统出现错误(Throw),去执行具体的操作。切入点(PointCut)就是总台发出取出月球特殊植物,嫦娥一号进行匹配特殊的植物,并通知是否找到成功或失败。那嫦娥一号这个对象本身就是我们的代理(Proxy),而真正的目标对象是总台(大概理解一下,不到之处,望原谅)。


我们这里的横切性关注点(Coreconcerns)是指安全性服务,对于安全性的检查可能分不到各个模块中。而切面(Aspect)是一个关注点的模块化,从软件角度来说是指应用程序在不同模块的某一个领域或方面。连接点(Joinpoint)程序执行过程中某个特殊的点,比如方法调用或处理异常的时候,上述我们再调用增删改查方法的时候。切入点(Pointcuts)是连接点的集合。通知(Advice)是实际的逻辑实现,即实际实现安全服务的那个方法。

通知有四种类型,前置通知(Beforeadvice):在切入点匹配方法之前使用。返回后通知(Afterreturning advice):在切入点匹配方法返回的时候执行。抛出后通知(Afterthrowing advice):在切入点匹配的方法执行时抛出异常的时候运行。后通知(After(fin