Spring AOP源码分析(六)Spring AOP配置的背后

本篇文章主要对Spring AOP配置背后进行了哪些事情做下说明。还是如上类似的工程,在xml中AOP拦截配置如下: 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="aspectBean" class="com.lg.aop.TestAspect" />
     
    <aop:config expose-proxy="false" proxy-target-class="false"
        <aop:aspect id="TestAspect" ref="aspectBean"
             
            <aop:pointcut id="businessService1" 
                expression="execution(* com.lg.aop.service.*.bar*(..))" /> 
            <aop:pointcut id="businessService2" 
                expression="execution(* com.lg.aop.service.*.foo*(..))" /> 
            <aop:before pointcut-ref="businessService1" method="doBefore" /> 
            <aop:after pointcut-ref="businessService2" method="doAfter"/> 
            <aop:around pointcut-ref="businessService2" method="doAround"/>
            <aop:after-throwing pointcut-ref="businessService1" method="doThrowing" throwing="ex"/> 
        </aop:aspect> 
    </aop:config>

其中接口AService和类BServiceImpl都在com.lg.aop.service包下,AService的实现类 
AServiceImpl在com.lg.aop.service.impl包下。
 
1
2
3
4
5
6
public interface AService {
 
    public void fooA(String _msg); 
       
    public void barA();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class BServiceImpl {
 
     public static final void barB(String _msg, int _type) { 
        System.out.println("BServiceImpl.barB(msg:"+_msg+" type:"+_type+")"); 
        if(_type == 1
            throw new IllegalArgumentException("测试异常"); 
     
   
    public void fooB() { 
        System.out.println("BServiceImpl.fooB()"); 
    
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class AServiceImpl implements AService{
 
    @Override
    public void fooA(String _msg) {
         System.out.println("AServiceImpl.fooA(msg:"+_msg+")");
    }
 
    @Override
    public void barA() {
         System.out.println("AServiceImpl.barA()"); 
    }
 
}

测试方法如下: 
1
2
3
4
5
@Test
    public void testAOP(){
        aService.barA();
        bServiceImpl.fooB();
    }

运行效果如下: 
1
2
3
4
5
log Begining method: com.lg.aop.service.impl.AServiceImpl.barA
AServiceImpl.barA()
BServiceImpl.fooB()
process time: 12 ms
log Ending method: com.lg.aop.service.BServiceImpl.fooB

接下来就需要看下配置完成之后是如何生成代理对象的。 
还是要从对xml中的配置<aop:config>标签的解析来入手。同样是从标签解析接口开始,即找BeanDefinitionParser的实现类,最终我们会找到AspectJAutoProxyBeanDefinitionParser是用来处理aspectj-autoproxy标签的,而ConfigBeanDefinitionParser则是用来处理aop:config标签的。看下ConfigBeanDefinitionParser的解析过程:
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);
 
        configureAutoProxyCreator(parserContext, element);
 
        List<Element> childElts = DomUtils.getChildElements(element);
        for (Element elt: childElts) {
            String localName = parserContext.getDelegate().getLocalName(elt);
            if (POINTCUT.equals(localName)) {
                parsePointcut(elt, parserContext);
            }
            else if (ADVISOR.equals(localName)) {
                parseAdvisor(elt, parserContext);
            }
            else if (ASPECT.equals(localName)) {
                parseAspect(elt, parserContext);
            }
        }
 
        parserContext.popAndRegisterContainingComponent();
        return null;
    }

这个过程比较费劲,有兴趣的可以弄清楚。这里主要注册一些Advisor,同时注册了一个AspectJAwareAdvisorAutoProxyCreator,并且设置xml中所配置的proxy-target-class和expose-proxy到它的属性中。AspectJAwareAdvisorAutoProxyCreator本身存储着配置信息,然后使用这些配置创建出来代理对象,在它的父类AbstractAutoProxyCreator的createProxy方法中: 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
        ProxyFactory proxyFactory = new ProxyFactory();
        // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
//重点1
        proxyFactory.copyFrom(this);
 
//重点2
        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
 
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);
        }
 
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);
 
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
//重点3
        return proxyFactory.getProxy(this.proxyClassLoader);
    }

在该方法中创建出代理对象,待会我们再详细说这个过程。我们先看下ProxyFactory是什么东西。 
把下面的图理解透了,就掌握了SpringAOP的整个运行机制。
 

Spring AOP源码分析(六)Spring AOP配置的背后 
然后我们就详细的说明下整个过程: 
重点1:proxyFactory.copyFrom(this);将ProxyConfig信息复制到ProxyFactory 中。ProxyFactory、AspectJAwareAdvisorAutoProxyCreator都继承了ProxyConfig,ProxyConfig拥有代理的一些配置信息。看下ProxyConfig:
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ProxyConfig implements Serializable {
 
    /** use serialVersionUID from Spring 1.2 for interoperability */
    private static final long serialVersionUID = -8409359707199703185L;
 
    private boolean proxyTargetClass = false;
 
    private boolean optimize = false;
 
    boolean opaque = false;
 
    boolean exposeProxy = false;
 
    private boolean frozen = false;
}

含有两个我们所关注的proxyTargetClass,exposeProxy : 
proxyTargetClass:是否强制使用cglib来实现代理 
exposeProxy:是否在线程内部暴露出代理对象(使用ThreadLocal模式实现线程内共享,见http://lgbolgger.iteye.com/blog/2116164中对exposeProxy的描述)。 

重点2:复制完配置信息后,看下proxyTargetClass 属性是否为false,则查看目标类是否含有接口,若无则仍然设置proxyTargetClass为true,若有则把接口设置到ProxyFactory中。然后在设置些Advisor、targetSource等其他参数,为创建代理对象做准备。来看下上述Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);的具体内容:
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
        // Handle prototypes correctly...
        Advisor[] commonInterceptors = resolveInterceptorNames();
 
        List<Object> allInterceptors = new ArrayList<Object>();
        if (specificInterceptors != null) {
            allInterceptors.addAll(Arrays.asList(specificInterceptors));
            if (commonInterceptors != null) {
                if (this.applyCommonInterceptorsFirst) {
                    allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                }
                else {
                    allInterceptors.addAll(Arrays.asList(commonInterceptors));
                }
            }
        }
        if (logger.isDebugEnabled()) {
            int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
            int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
            logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
                    " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
        }
 
        Advisor[] advisors = new Advisor[allInterceptors.size()];
        for (int i = 0; i < allInterceptors.size(); i++) {
 
//重点重点重点重点重点重点重点
            advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
        }
        return advisors;
    }

对配置信息中的specificInterceptors全部封装成Advisor。再看下具体的封装过程,在上述wrap方法中 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

如果是Advisor直接返回不处理,接下来必须是Advice,然后通过MethodInterceptor和AdvisorAdapter 对Advice进行包装。对此过程还不清楚的,请先去看之前的接口介绍(http://lgbolgger.iteye.com/blog/2117214) 
重点3:使用DefaultAopProxyFactory来创建AopProxy,有了AopProxy我们就能创建代理对象了。看下AopProxy的创建过程:
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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);
        }
    }

这里决定着到底采用jdk动态代理还是cglib方式来创建代理对象。 
条件1:config.isOptimize()是否进行优化,默认是false。 

条件2:config.isProxyTargetClass()就是ProxyConfig的proxyTargetClass属性,是否强制使用cglib代理。但它为true也不是肯定就采用cglib,因为下面还有一个判断条件,即目标类是接口,则使用jdk动态代理的方式。 

条件3:hasNoUserSuppliedProxyInterfaces(config)目标类没有实现接口,或者有但是是接口类型是SpringProxy,如下:
 
1
2
3
4
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] interfaces = config.getProxiedInterfaces();
        return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
    }

只要上述三个条件有一个为true并且目标类不是接口就会采用cglib方式来创建代理对象,其他情况使用jdk动态代理的方式来创建。 
有了JdkDynamicAopProxy和ObjenesisCglibAopProxy则可以顺利创建出代理对象,便可以跳到这篇文章http://lgbolgger.iteye.com/blog/2116164,至此整个过程就连接通了。