前文介绍了代理模式及实现,但想要实现一个完整的AOP框架还远远不够,接下来我们来分析一下Spring是如何实现AOP的。
1 AOP体系结构
下图AOP联盟定义的AOP体系结构,大致分为从使用到实现的三个层次。整篇文章都将按照这三个层次进行分析
1.1 层次3:语言和开发环境
- 基础:可以视为待增强对象
- 切面:通常包含对于基础的增强应用
- 配置:指配置环境或编织配置,将基础和切面结合起来,从而实现对目标对象的编织实现
Spring使用Java语言来实现增强对象和切面,并为这两者提供配置环境;对于编织配置,可以使用IoC容器来完成,而Ioc恰恰是Spring的强项。
1.2 层次2:面向方面系统
面向方面系统为上层的语言与开发环境提供支持,将基础、切面和配置封装成面向方面中的逻辑模型。
1.3 层次1:底层编织实现模块
将编织逻辑进行实现的技术。
前文所述的两种动态代理技术就是在这个层面进行应用。
2 Spring AOP实现
我们从上到下的看看Spring如何实现AOP的。整个AOP框架逻辑流程很复杂,这里就只对在目标对象在单例模式下并使用JDK动态代理的AOP进行分析。
2.1 层次3:语言和开发环境
2.1.1 基础
在Spring中,基础就是你配置的Bean对象,这个Bean对象可以配置在XML中,也可以使用注解进行配置,如
2.1.2 切面
在Spring中,切面由切点和通知组成,由使用者进行定义.
PointCut切点
决定Advice通知应该作用于哪个连接点,也就是通过切点定义哪些方法需要增强。
PointCut
接口是所有切点实现的基本接口,其中定义了MethodMatcher
方法,用来判断当前方法是否需要增强。可以通过不同的方式进行判断,如JdkRegexpMethodPointcut
类使用正则表达式进行匹配,还可以使用类限定名,切点表达式等方式进行匹配。
Advice通知
通知定义在连接点做什么,为切面增强提供织入接口。Advice
接口是AOP联盟定义的统一接口,Spring对这个接口进行了细化和扩展,如BeforeAdvice
,AfterAdvice
,ThrowsAdvice
Advisor通知器
通知器将通知和切点结合起来,为Spring配置AOP容器提供便利。
2.1.3 配置
对基础和切面进行配置,使之对基础进行增强.Spring实现多种方式的配置,ProxyFactoryBean
完成声明式配置,ProxyFactory
完成编程式配置。AspectJProxyFactory
将Spring和Aspectj集成。
2.1.4 使用ProxyFactoryBean的示例
applicationContext.xml
request
requestAdvisor
RequestBeforeAdvice.java
public class RequestBeforeAdvice implements MethodBeforeAdvice{
private void before(String param) throws Throwable{
if(!param.equals("magicalwolf"))
throw new IllegalArgumentException();
}
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
before((String)args[0]);
}
}
Main.java
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Subject proxy= (Subject) context.getBean("requestAOP");
proxy.request("magicalwolf");
proxy.request("hello");
}
}
层次3主要定义了开发人员如何使用AOP,Spring在背后将进行逻辑模型的封装工作
2.2 层次2:面向方面系统
我们从ProxyFactoryBean出发,看看面向方面系统是如何对target目标起作用的。
2.2.1 ProxyFactoryBean的继承关系
-
ProxyFactoryBean
类负责具体AOP代理对象的生成 -
ProxyCreateSupport
类是创建AOP代理对象的一个辅助类 -
AdvisedSupport
类封装了对通知和通知器相关的操作 -
ProxyConfig
类为子类提供配置属性
2.2.2 生成代理对象跟踪
从FactoryBean中获取对象,是以getObject()
方法为入口,在ProxyFactoryBean也是如此,getObject()
方法对目标对象进行增强处理。
2.2.2.1 public Object getObject()
首先对通知器链进行初始化,生成代理对象时如果是单例模式调用getSingletonInstance(),此处只分析单例的情况
public Object getObject() throws BeansException {
initializeAdvisorChain();//初始化通知器链(2.2.2.2)
if (isSingleton()) {
return getSingletonInstance();//生成Singleton的代理对象(2.2.2.3)
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
2.2.2.2 private synchronized void initializeAdvisorChain()
初始化通知器链,此方法是线程安全的
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
/检查interceptorNames是否为空,interceptorNames是一个String[]
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
//检查beanFactory是否为null,此处的beanFactory是Spring的Bean工厂,直接从容器中获得配置的通知器
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// 通过Bean Name获得通知器
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
//GLOBAL_SUFFIX = "*",说明这个通知器是全局通知器
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// 添加一个命名的通知器,检查是singleton还是prototype
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// 获得一个Advice或Advisor
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);//添加通知器到通知器列表(2.2.6)
}
}
}
this.advisorChainInitialized = true;
}
2.2.2.3 private synchronized Object getSingletonInstance()
private synchronized Object getSingletonInstance() {
//singletonInstance为缓存的单例对象,如果存在就直接返回
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();//targetSource在AdvisedSupport中定义,用来获得目标对象
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
//依靠AOP框架告诉我们哪个接口被代理
Class> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
//设置代理接口,在AdvisedSupport中定义了interfaces列表
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
super.setFrozen(this.freezeProxy);
//使用ProxyFactory生成需要的Proxy
this.singletonInstance = getProxy(createAopProxy());
//getProxy(2.2.2.4),createAopProxy(2.2.2.5)
}
return this.singletonInstance;
}
2.2.2.4 protected Object getProxy(AopProxy aopProxy)
AopProxy
是一个接口,有两个子类实现,一个是ObjenesisCglibAopProxy
,一个是JdkDynamicProxy
.分别通过CGLIB和JDK来生成需要的Proxy代理对象
protected Object getProxy(AopProxy aopProxy) {
//通过AopProxy得到代理对象
return aopProxy.getProxy(this.proxyClassLoader);
}
2.2.2.5 protected final synchronized AopProxy createAopProxy()
此方法在ProxyCreatorSupport
中定义,具体是通过AopProxyFactory
来获得AopProxy,AopProxyFactory
默认的工厂实现是DefaultAopProxyFactory
,生成哪一种AopProxy就在此类中定义
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
DefaultAopProxyFactory
中的createAopProxy方法
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.");
}
//如果是接口类使用JDK生成Proxy
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
//否则用cglib
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JdkDynamicAopProxy
中的getObject方法,这里我们可以看到熟悉的Proxy.newProxyInstance()方法
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
2.2.2.6 private void addAdvisorOnChainCreation(Object next, String name)
namedBeanToAdvisor
方法会将next对象包装为Advisor对象,并添加到Advisor集合中
private void addAdvisorOnChainCreation(Object next, String name) {
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
}
在namedBeanToAdvisor
方法中,会使用DefaultAdvisorAdapterRegistry
的warp方法对next对象进行包装.通知器是由切点和通知组成,如果只配置了通知,则切点为默认的TruePointcut
,它对任何方法的匹配都将返回true
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
//如果对象已经是Advisor直接返回
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
//检查类型
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// 包装为默认切点通知器
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// 检查是否匹配
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
通过以上的分析,我们已经得到了代理对象,至此层次2的工作已经完成了,层次3获得的配置模型,在配置逻辑的应用下向AOP模型转换,接下来该层次1的实现了
2.2 层次1:底层编织实现模块
在生成代理对象的时候,相关的拦截器已经配置完成,拦截器起作用是通过对方法进行回掉完成的。
2.2.1 使用JDK代理的实现
前文提到过,在JDK代理中方法回掉的入口是在invoke方法中。而JdkDynamicAopProxy
实现了InvocationHandler
接口,方法回掉逻辑也定义在其中.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 目标没有实现自己的equals方法
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 目标没有实现自己的hashCodes方法
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 根据代理对象的配置调用服务,如果是Advised接口的实现类,则直接调用
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 有可能为null.尽可能减少拥有目标对象的时间,在这种情况下对象来自于对象池
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获得这个方法的连接器链
List
invoke
方法获取目标对象和拦截器链,并生成ReflectiveMethodInvocation
对象,通过这个对象完成对AOP功能的封装。
2.2.2 获得方法的拦截器链
public List
methodCache是一个集合MapDefaultAdvisorChainFactory
来生成拦截器链
public List getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class> targetClass) {
//通过config获得配置好的advisor链,AdvisedSupport实现了Advised
List interceptorList = new ArrayList(config.getAdvisors().length);
//实际对象
Class> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
//判断是否符合配置要求
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//判断通知器是否匹配实际对象
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);//将通知器适配成方法拦截
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
//封装成动态方法匹配
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));//将拦截器链添加到列表中
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
此方法有一个适配和注册的过程,它将Advice通知适配成Spring预先设计好的拦截器。适配和注册的工作是在GlobalAdvisorAdapterRegistry
的getInterceptors()中完成的
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List interceptors = new ArrayList(3);
Advice advice = advisor.getAdvice();//获得通知
if (advice instanceof MethodInterceptor) {//如果是MethodInterceptor则直接添加
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {//遍历注册的适配器,检查是否匹配
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
在GlobalAdvisorAdapterRegistry
的构造函数中注册了三种适配器,注册过程就是将这三种适配器加入List集合
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
来看一下MethodBeforeAdviceAdapter
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {//是否支持
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {//将Advice适配成Interceptor
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
将Advice封装成了MethodBeforeAdviceInterceptor
,此类中有invoke方法,会先调用advice的before方法
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
至此,Spring AOP实现了对advice的织入,可以看到它将xml中配置的通知器适配成了拦截器
2.2.3 方法调用
之前讲到了拦截器的适配和注册,对呀没有拦截器的方法直接调用,有拦截器的方法会构造ReflectiveMethodInvocation
,并沿着拦截器链进行调用。整个调用链的入口在proceed
方法中
public Object proceed() throws Throwable {
//从索引为-1的拦截器开始,并递增
//如果拦截器迭代调用完成,则调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();//使用invokeJoinpointUsingReflection调用目标对象
}
//沿着拦截器链执行
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//对方法进行动态匹配,切点的匹配就在这里进行
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 动态匹配失败
// 跳过这个拦截器调用下一个
return proceed();
}
}
else {
// 这是一个拦截器,直接调用它
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
至此,完成对拦截器链及目标方法的调用
3 总结
3.1 层次3:语言与开发环境
Spring AOP使用Java语言,可以通过多种方式进行AOP配置,基础
就是Bean对象,切面
可以通过xml或注解进行声明.配置
是由IoC容器完成的
3.2 层次2:面向方面系统
本文分析使用ProxyFactoryBean
的情况,ProxyFactoryBean
处理配置逻辑,生成代理对象。ProxyFactoryBean
会先初始化通知器集合,再根据代理类型使用JdkDynamicProxy
或ObjenesisCglibAopProxy
生成代理对象
3.1 层次1:底层编织实现模块
使用JDK代理中,方法的回掉入口在invoke
方法中,在invoke
方法中实现了Advice的织入,以及目标方法的调用。
对Advice的织入,Spring预先设计好了拦截器,如MethodBeforeAdviceInterceptor
,AfterReturningAdviceInterceptor
,ThrowsAdviceInterceptor
,将Advice适配成对应的拦截器,并将拦截器链缓存,此时完成了对Advice的织入
对目标方法的调用,如果在目标方法未配置拦截器,则直接调用目标方法,如果得到了拦截器链,则沿着拦截器链执行。在执行过程中如果是动态匹配的拦截器,则需要再次进行匹配,否则直接调用拦截器。
以上分析了Spring AOP的部分实现,不过整个AOP基本流程已经分析完成。有了基础再去看AOP的高级部分会更加容易