使用动态代理解决问题
动态代理,我们要实现一个系统的处理器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