AOP 术语
关于 AOP 的概念描述及相关术语可以参考 彻底征服 Spring AOP 之 理论篇 总结的很好; 本文将着重分析下 AOP 的实现过程。
使用示例
定义接口
public interface UserService {
void say ();
}
接口实现类如下:
public class UserServiceImpl implements UserService {
public void say() {
System.out.println("do say method");
}
}
定义通知
public class UserAdvice implements MethodBeforeAdvice {
public void before(Method m, Object[] args, Object target) throws Throwable {
System.out.println("do before advice ....");
}
}
配置 AOP
<beans>
<!-- 配置接口实现类 -->
<bean id="userService" class="org.springframework.aop.UserServiceImpl" />
<!-- 配置通知类 -->
<bean id="userAdvice" class="org.springframework.aop.UserAdvice" />
<!--代理类-->
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--要代理的接口 创建代理对象时需要-->
<!-- 配置该属性会采用 jdk 动态代理,反之采用 cglib -->
<property name="proxyInterfaces">
<value>org.springframework.aop.UserService</value>
</property>
<!--拦截器名字,也就是我们定义的通知类,可配置多个通知类 -->
<property name="interceptorNames">
<list>
<value>userAdvice</value>
</list>
</property>
<!--目标类,就是我们业务的实现类-->
<property name="target">
<ref bean="userService"/>
</property>
</bean>
</beans>
测试
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml");
UserService userService = (UserService) ctx.getBean("userProxy");
userService.say();
执行结果如下:
do before advice ....
do say method
从执行结果来看,前置通知对接口方法已经起增强作用。 下面我们将看下 Spring AOP 的具体实现。
实现分析
从上面的示例可以看出 Spring AOP 的配置主要基于类 ProxyFactoryBean
,那么我们就以此为入口去剖析其实现。
ProxyFactoryBean 类结构
创建切面链
从 ProxyFactoryBean
的类结构,我们发现其实现了接口 BeanFactoryAware
,也就说明在其实例化过程中会调用方法 setBeanFactory
; 源码如下:
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// 设置 beanFactory
this.beanFactory = beanFactory;
logger.debug("Set BeanFactory. Will configure interceptor beans...");
// 创建 advisor chain
createAdvisorChain();
logger.info("ProxyFactoryBean config: " + this);
if (singleton) {
// Eagerly initialize the shared singleton instance
getSingletonInstance();
// We must listen to superclass advice change events to recache singleton
// instance if necessary
addListener(this);
}
}
在 setBeanFactory
方法中除了设置 beanFactory
, 还有一个重要的动作就是 createAdvisorChain
创建 advisor chain (也可以理解为就是切面链)。 那么下面我们将看下具体是怎样创建 advisor chain 的。
private void createAdvisorChain() throws AopConfigException, BeansException {
// 检测是否配置了 interceptorNames, 也就是是否配置相关 advice 通知; 若没有配置直接返回
if (this.interceptorNames == null || this.interceptorNames.length == 0) {
//throw new AopConfigException("Interceptor names are required");
return;
}
// Globals can't be last
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX)) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names
for (int i = 0; i < this.interceptorNames.length; i++) {
String name = this.interceptorNames[i];
logger.debug("Configuring interceptor '" + name + "'");
// 判断 interceptor name 是否以 * 结尾
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");
}
else {
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
}
else {
// add a named interceptor
// 获取 advice bean
Object advice = this.beanFactory.getBean(this.interceptorNames[i]);
// 将 advisor 加入到链表中
addAdvisor(advice, this.interceptorNames[i]);
}
}
}
private void addAdvisor(Object next, String name) {
logger.debug("Adding advisor or TargetSource [" + next + "] with name [" + name + "]");
// We need to add a method pointcut so that our source reference matches
// what we find from superclass interceptors.
// 查找 advice 通知匹配的 pointcut, 并创建一个 advisor
Object advisor = namedBeanToAdvisorOrTargetSource(next);
if (advisor instanceof Advisor) {
// if it wasn't just updating the TargetSource
logger.debug("Adding advisor with name [" + name + "]");
addAdvisor((Advisor) advisor);
this.sourceMap.put(advisor, name);
}
else {
logger.debug("Adding TargetSource [" + advisor + "] with name [" + name + "]");
setTargetSource((TargetSource) advisor);
// save target name
this.targetName = name;
}
}
从 addAdvisor
方法可以看到,在添加 advisor 前,需要先创建 advisor , 会调用方法 namedBeanToAdvisorOrTargetSource
private Object namedBeanToAdvisorOrTargetSource(Object next) {
try {
// 将 advice 包装成一个 advisor
Advisor adv = GlobalAdvisorAdapterRegistry.getInstance().wrap(next);
return adv;
}
catch (UnknownAdviceTypeException ex) {
}
}
namedBeanToAdvisorOrTargetSource
方法会调用单例模式的 GlobalAdvisorAdapterRegistry
的方法 wrap
将 advice 包装成一个 advisor;
在查看 wrap
的实现之前,我们可以先看下 GlobalAdvisorAdapterRegistry
是做什么的。
public class GlobalAdvisorAdapterRegistry extends DefaultAdvisorAdapterRegistry {
private static GlobalAdvisorAdapterRegistry instance = new GlobalAdvisorAdapterRegistry();
public static GlobalAdvisorAdapterRegistry getInstance() {
return instance;
}
private GlobalAdvisorAdapterRegistry() {
}
}
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry {
private List adapters = new LinkedList();
public DefaultAdvisorAdapterRegistry() {
// register well-known adapters
registerAdvisorAdapter(new BeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
}
从上面 GlobalAdvisorAdapterRegistry
的实现可以看出其采用了单例模式并继承了类 DefaultAdvisorAdapterRegistry
在构造的过程中内置了 3 种 advice adapter 用于匹配 advice 。 下面我们在看下它是如何 wrap
包装 advice 的。
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof Interceptor) {
// So well-known it doesn't even need an adapter
return new DefaultPointcutAdvisor(advice);
}
// 遍历内置的 advice adapters
for (int i = 0; i < this.adapters.size(); i++) {
// Check that it is supported
AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
// 判断当前 adapter 是否支付当前 advice
if (adapter.supportsAdvice(advice)) {
// 如果支持的话,返回一个 DefaultPointcutAdvisor
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
从 wrap
的实现可以发现,若 advice 匹配了某个 adapter 将会创建一个 DefaultPointcutAdvisor
实例并返回;
public class DefaultPointcutAdvisor implements PointcutAdvisor, Ordered {
private int order = Integer.MAX_VALUE;
private Pointcut pointcut;
private Advice advice;
public DefaultPointcutAdvisor() {
}
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
this.advice = advice;
}
}
/**
* Canonical instance that matches everything.
* 默认匹配所有的类及类下的所有方法
*/
Pointcut TRUE = new Pointcut() {
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}
public String toString() {
return "Pointcut.TRUE";
}
};
从 DefaultPointcutAdvisor
的实例可以看出创建 advisor (切面) 的过程实际就是将 advice (通知) 和 pointcut (切入点) 绑定的过程;同时在 Spring AOP 默认的 pointcut 是拦截所有类下的所有方法。
简单点说也就是当前切面将会拦截哪些类下的哪些方法,拦截过程中会采用哪些增强处理(前置通知,返回通知,异常通知)。
至此 advisor chain 的创建流程结束,其过程大概如下:
- 遍历 interceptor names (也就是 advice 通知)
- 获取 advice bean
- 判断 advice 是否匹配内置的 advisorAdapter, 匹配的话则创建 DefaultPointcutAdvisor (默认拦截所有类所有方法) 加入到链表中
创建目标代理对象
从 ProxyFactoryBean
类的名字及类结构,发现其实现接口 FactoryBean
, 也就是说当其 getBean
的时候会调用方法 getObject
, 源码如下:
public Object getObject() throws BeansException {
// 默认单例
return (this.singleton) ? getSingletonInstance() : newPrototypeInstance();
}
private Object getSingletonInstance() {
if (this.singletonInstance == null) {
// This object can configure the proxy directly if it's
// being used as a singleton.
this.singletonInstance = createAopProxy().getProxy();
}
return this.singletonInstance;
}
protected synchronized AopProxy createAopProxy() {
if (!isActive) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
// 是否采用 cglib 代理
boolean useCglib = advisedSupport.getOptimize() || advisedSupport.getProxyTargetClass() || advisedSupport.getProxiedInterfaces().length == 0;
if (useCglib) {
return CglibProxyFactory.createCglibProxy(advisedSupport);
}
else {
// Depends on whether we have expose proxy or frozen or static ts
return new JdkDynamicAopProxy(advisedSupport);
}
}
public Object getProxy(ClassLoader cl) {
logger.debug("Creating JDK dynamic proxy");
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
return Proxy.newProxyInstance(cl, proxiedInterfaces, this);
}
ProxyFactoryBean
通过判断 proxyTargetClass , interfaceNames 的配置去选择采用 cglib 或者 jdk 来创建目标代理对象。
目标代理对象执行
上面简单介绍了代理对象的创建,那么在看下当我们调用目标方法的时候,代理是如何执行的,以 jdk 动态代理为例:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation = null;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = advised.targetSource;
Class targetClass = null;
Object target = null;
try {
// Try special rules for equals() method and implementation of the
// Advised AOP configuration interface
// Short-circuit expensive Method.equals() call, as Object.equals() isn't overloaded
if (method.getDeclaringClass() == Object.class && "equals".equals(method.getName())) {
// What if equals throws exception!?
// This class implements the equals() method itself
return new Boolean(equals(args[0]));
}
else if (Advised.class == method.getDeclaringClass()) {
// Service invocations on ProxyConfig with the proxy config
return AopProxyUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal = null;
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 目标实现类
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
if (this.advised.exposeProxy) {
// Make invocation available if necessary
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get the interception chain for this method
// 获取目标类,执行方法的 interception chain
List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this.advised, proxy, 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 = AopProxyUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
invocation = new ReflectiveMethodInvocation(proxy, target,
method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain
// 方法调用
retVal = invocation.proceed();
}
// Massage return value if necessary
if (retVal != null && retVal == target) {
retVal = proxy;
}
return retVal;
}
finally {
}
}
首先我们看下如何获取匹配当前 method 的拦截器, 参考 calculateInterceptorsAndDynamicInterceptionAdvice
的实现如下:
public static List calculateInterceptorsAndDynamicInterceptionAdvice(Advised config, Object proxy, Method method, Class targetClass) {
// 用于存储拦截器
List interceptors = new ArrayList(config.getAdvisors().length);
// 遍历 advisor (切面)
for (int i = 0; i < config.getAdvisors().length; i++) {
Advisor advisor = config.getAdvisors()[i];
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 判断当前 target class 是否当前 pointcut
if (pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
// 获取 advisor 对应的 method interceptor
MethodInterceptor interceptor = (MethodInterceptor) GlobalAdvisorAdapterRegistry.getInstance().getInterceptor(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 判断当前 method 是否匹配 pointcut
if (mm.matches(method, targetClass)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptor() method
// isn't a problem as we normally cache created chains
interceptors.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm) );
}
else {
// 将拦截器加入链表中
interceptors.add(interceptor);
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(targetClass)) {
MethodInterceptor interceptor = (MethodInterceptor) GlobalAdvisorAdapterRegistry.getInstance().getInterceptor(advisor);
interceptors.add(interceptor);
}
}
} // for
return interceptors;
} // calculateInterceptorsAndDynamicInterceptionAdvice
我们在详细看下如何查找 advisor 匹配的拦截器呢,同样与上文中 wrap
类似,如下:
public Interceptor getInterceptor(Advisor advisor) throws UnknownAdviceTypeException {
Advice advice = advisor.getAdvice();
if (advice instanceof Interceptor) {
return (Interceptor) advice;
}
// 遍历内置的 advisor adapter
for (int i = 0; i < this.adapters.size(); i++) {
AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
// 是否匹配当前 advice
if (adapter.supportsAdvice(advice)) {
// 匹配的话返回 interceptor
return adapter.getInterceptor(advisor);
}
}
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
到目前为止,我们多次发现 AdvisorAdapter
的身影,下面我们看下其具体的实现, 以 BeforeAdviceAdapter
为例:
class BeforeAdviceAdapter implements AdvisorAdapter {
/**
* @see org.springframework.aop.framework.adapter.AdvisorAdapter#supportsAdvice(java.lang.Object)
*/
public boolean supportsAdvice(Advice advice) {
// 匹配 MethodBeforeAdvice
return advice instanceof MethodBeforeAdvice;
}
/**
* @see org.springframework.aop.framework.adapter.AdvisorAdapter#getInterceptor(org.springframework.aop.Advisor)
*/
public Interceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
// 返回 MethodBeforeAdviceInterceptor
return new MethodBeforeAdviceInterceptor(advice) ;
}
}
通过 AdvisorAdapter
很巧妙的将 Advice 和 Interceptor 结合起来,同时也会发现二者关系是一一对应的
下面在看下方法的真正调用过程, 由 ReflectiveMethodInvocation
的方法 proceed
实现:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early
// 当执行到最后一个拦截器的时候将会调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个拦截器
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed
// Skip this interceptor and invoke the next in the chain
return proceed();
}
}
else {
// It's an interceptor so we just invoke it: the pointcut will have
// been evaluated statically before this object was constructed
// 执行拦截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
下面具体看下 MethodInterceptor
的实现,分别是前置通知,返回通知,异常通知
public Object invoke(MethodInvocation mi) throws Throwable {
// 目标方法前执行
advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
public Object invoke(MethodInvocation mi) throws Throwable {
// 先执行目标方法
Object retval = mi.proceed();
// 后置处理
advice.afterReturning(retval, mi.getMethod(), mi.getArguments(), mi.getThis() );
return retval;
}
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行目标方法
return mi.proceed();
}
catch (Throwable t) {
// 异常处理
Method handlerMethod = getExceptionHandler(t);
if (handlerMethod != null) {
invokeHandlerMethod(mi, t, handlerMethod);
}
throw t;
}
}
至此 Spring AOP 代理对象的执行过程处理结束,其流程可大概总结如下:
-
获取当前目标方法的 interceptor chain
- 遍历 advisor ,判断当前目标类和目标方法是否匹配 advisor 对应的 ponitcut
- 通过匹配的 advisor 对应的 advice 匹配对应的 advisorAdapter , 进而获取对应的 methodInterceptor
- 执行拦截器
- 执行目标方法
小结
Spring AOP 中的对象关系小结下:
- Advisor : 翻译是顾问,简单理解其就是一个 Aspect (切面); 其内部绑定了对应的 Pointcut(切入点) 和 Advice(通知)。
- Advisor Chain : 切面链,是一系列的切面的集合。
- Advice : 通知,是对拦截方法的增强处理;在 1.0 版本中包含 BeforeAdivce, AfterReturningAdvice, ThrowsAdvice; 其面向的是用户。
- MethodInterceptor : 方法拦截器,是 Advice 的执行者; 与 Advice 是一一对应的。
- AdvisorAdapter : Advice 的适配器,是 Advice 和 MethodInterceptor 匹配的纽带。
- AdvisorAdapterRegistry : 是 AdvisorAdapter 的注册中心,内置了 BeforeAdviceAdapter, AfterReturnAdviceAdapter, ThrowsAdviceAdapter; 用来将 Advice wrap 成一个 Advisor 并提供获取 Advice 对应的 MethodInterceptor。
坑
使用 Spring 1.0 版本时, 当我们自定义 Advice 时,可不可以同时支持多种 Advice 呢 ? 譬如:
public class UserAdvice implements MethodBeforeAdvice, AfterReturningAdvice {
public void before(Method m, Object[] args, Object target) throws Throwable {
System.out.println("do before advice ....");
}
public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {
System.out.println("do after returning ....");
}
}
那么当测试后,您会发现只有 before 调用了,而 afterReturning 未调用了;这是为什么呢 ? (好好看源码额)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。