AOP,面向切面编程,主要的作用是可以将那些分散在业务系统中相同的代码抽取出来放到一个地方进行管理
这么做的好处是减少了重复代码的编写,并且软件的可维护性也强
为什么叫做面向切面编程呢? 举个例子:假如我们的代码中,
引入了AOP之后,这项工作就变得简单了
常见的应用场景:日志记录、性能统计、安全认证、事务处理、异常处理等 我们将这些代码从业务逻辑代码中分离出来,通过对这些行为的分离,我们把它们独立到非指导业务逻辑的代码中,进而改变这些代码的时候不会影响到我们的业务逻辑代码 并且业务逻辑代码也感知不到它们的存在,因为业务逻辑代码“被代理了”。
Spring AOP中代理机制的实现主要使用了了JDK动态代理以及CGLIB动态代理
Advice是AOP中的一个基本接口,BeforeAdvice、AfterAdvice、ThrowsAdvice等都继承于它
Advice继承关系图
在BeforeAdvice
的继承关系中,定义类为待增强的目标方法设置的前置增强接口MethodBeforeAdvice
使用这个前置接口需要实现一个回调函数before
,作为回调函数,before方法的实现在Advice中被配置到目标方法后,会在调用目标方法时被回调
MethodBeforeAdvice以及回调函数before
before的参数
同样的,在AfterAdvice继承体系下的AfterReturningAdvice中也有相似的回调函数
图1.3 AfterReturningAdvice及其回调函数afterReturn
从Pointcut的基本接口定义中可以看到,需要返回一个
MethodMatcher
Point的匹配判断,即
Pointcut的基本接口定义
而在MethodMatcher
接口中,有一个matcher
方法
在匹配连接点的过程中起着至关重要的作用.
MethodMatcher
对象是可以配置成
JdkRegexpMethodPointcut
有一个MethodMatcher接口定义的matches
方法,用正则表达式来对方法名进行匹配判断NameMatchMethodPointcut
完成方法的匹配判断PointCutadvisor 有 两 个 常 用 实 现 类
advice 定义一个增强,即要加入的操作(需要自己实现 MethodBeforeAdvice、MethodafterAdvice、throwAdvice、Methodinterceptor 接口之一),然后在 ProxyBeanFactory 的拦截器中注入这个 PointCutadvisor。注:一个 ProxyFactoryBean 只能指定一个代理目标。
JdkRegexpMethodPointcut中的matches函数
在NameRegexpMethodPointcut中,给出了matches方法的另一个实现,根据方法的全限定名称进行匹配
NameRegexpMethodPointcut中matches函数的实现
NameMatchMethodPointcut中matches方法的调用关系链
JdkRegexpMethodPointcut中matches方法的调用关系链
从图2.4和图2.5中我们可以看到,在JdkDynamicAopProxy的invoke方法中发出了对matches方法的调用.这个invoke方法就是Proxy对象进行代理回调的入口方法.
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] interfaces = config.getProxiedInterfaces();
return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
}
}
JdkDynamicAopProxy的类图
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}