spring源码分析之AOP分析
AOP简介
什么是AOP?这可能是学习AOP时,最想知道的问题,在研究spring aop这块查阅了大量的资料,即使AOP联盟当初指定的规范也没有解释这个概念,如同OOP一样,AOP只是一种编程思想了,水平有限我只能这样解释了。OOP代码中的体现就是类了,那AOP呢?其实也是类(也可以理解为模块化),所谓的特殊的横切组织,参考下图:
一般项目里面的函数会包含业务性处理与非业务性处理两种,随着业务的发展里面可能会包含很多非业务的处理,这些非主业务的处理有可能在其他地方继续调用,这样代码的耦合性就非常高了。灰色的切面就是AOP的体现了,这些非业务的处理从代码中解耦出来就优雅多了。如果要实现自己的AOP组件要包含拦截器框架、字节码解析、织入组件(如动态代理)、配置组件,摘自AOP联盟
All these projects have their onw goals and speficities. However, several common basic components are still usefull (and sometimes required) to build a full AO system. For instance, a component that is able to add metadata on the base components, an interception framework, a component that is able to perform code translation in order to advice the classes, a weaver component, a configuration component, and so on.
spring AOP简介
如上面所述,spring实现AOP就包含了其中一些组件,如下图所示:
Spring AOP提供了几个重要概念性的东西,参考文档,其中Joinpoint与Advice是aop联盟提供的aop接口,Advice就广义的理解为拦截器,Joinpoint就是方法的执行(spring采用动态代理执行),Pointcut匹配的执行方法集合。
spring内部AOP实现包含了动态代理(JDK proxy、cglib proxy)与静态代理(AspectJ实现参考这里,在编译期间织入),
spring AOP只指针对方法级别,如果想粒度更细(如改变属性或者构造函数之类的)就要AspectJ了,但是spring解析Pointcut方法匹配还是用的AspectJ相关的包。
创建代理bean
下面以JDK动态代理实现AOP为例进行分析,配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="foo" class="mytest.aop.FooImpl"/>
<bean id="aroundBean" class="mytest.aop.config.AroundBean"/>
<bean id="myAdvice" class="mytest.aop.config.MyAdvice"/>
<bean id="myAspect" class="mytest.aop.config.MyAspect"/>
<aop:config>
<aop:pointcut expression="execution(* mytest.aop.config.*.*(..))" id="pc"/>
<aop:advisor advice-ref="myAdvice" pointcut-ref="pc"/>
<aop:aspect ref="myAspect">
<aop:around method="aroundAdvice" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>
参考《spring源码分析之基于注解配置的bean初始化分析》,跟分析context:component-scan/标签差不多,使用aop:config就由AopNamespaceHandler解析命名空间,然后ConfigBeanDefinitionParser解析标签,最后把AspectJAwareAdvisorAutoProxyCreator注册到容器中:
从这个图中就可以看出,AspectJAwareAdvisorAutoProxyCreator是BeanPostProcessor的一个子类,这个类就是执行创建代理bean的入口。整个创建流程参考下图:
初始化bean之前AspectJAwareAdvisorAutoProxyCreator将排除一些类不会生成代理类,如Advisor、Advice、Aspect以及Pointcut不匹配的类,参考AbstractAutowireCapableBeanFactory:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//执行initializeBean,bean是否有其他操作(如代理对象)
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//排除Advice、Advise、Aspect切面相关的类,并创建拦截器链
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//AspectJAwareAdvisorAutoProxyCreator执行创建代理对象
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
参考applyBeanPostProcessorsAfterInitialization方法,创建代理bean就有AspectJAwareAdvisorAutoProxyCreator的父类AbstractAdvisorAutoProxyCreator执行:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//postProcessBeforeInstantiation方法已经将排除的bean放置到advisedBeans
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//获取Alliance中实现的Interceptors
//一般bean如果不包含在PointCut表达式中,返回为null
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//将拦截器链传递给ProxyFactory
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
前面的配置文件没有特殊的配置,spring内部默认使用JDK动态代理,参考DefaultAopProxyFactory:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
mylog.debug("创建JdkDynamicAopProxy还是ObjenesisCglibAopProxy");
//检查是不是接口,或者是不是强制设置ProxyTargetClass为true,是就使用Cglib代理
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() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
然后JdkDynamicAopProxy通过getProxy就获取到代理对象了。再些一个测试类,使用上面的配置文件:
@Test
public void testProxy() {
ITestBean aroundBean = (ITestBean) context.getBean("aroundBean");
IFoo foo = (IFoo)context.getBean("foo");
System.out.println("aroundBean:" + AopUtils.isAopProxy(aroundBean));
System.out.println("foo:" + AopUtils.isAopProxy(foo));
}
输入结果为:
aroundBean:true
foo:false
aroundBean在拦截表达式内,所以是代理对象,foo不在该范围内就不是代理对象。
执行代理bean
由于跟bean相关的拦截器初始化时就已经配置好了,JdkDynamicAopProxy实现了InvocationHandler,所以执行bean的方法时就直接调用invoke方法,执行流程如下:
参考ReflectiveMethodInvocation(Joinpoint的一个实现类)执行拦截器链以及目标函数:
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);
}
}
执行测试代码
@Test
public void testAround() {
//如果是JDK代理只能声明接口,获取到的实例是JDK产生的代理bean
ITestBean aroundBean = (ITestBean) context.getBean("aroundBean");
aroundBean.print();
}
最后打印输出:
MyAspect: around before
AroundBean's print
MyAspect: around after