spring aop
aop 的全称是Aspect-Oriented Programming(面向切面编程),怎么理解面向切面这句话?可以这么理解:每一个类的一个方法是一个点,同时处理多个点也就
可以理解为处理一个面,这个面包含多个点。概念部分也就更明显了,需要被处理的点叫做Pointcut(切点),处理的动作叫做Advice(通知),将切面和点连接在一起的策略叫做Advisor(通知器)。
这里呢,只看一个包org.springframework.aop,直觉告诉我,这是最核心的包。把aop的源码导进eclipse看看,从aop包中看到,Pointcut、Advice、Proxy、Method出现的次数很多
他们之间的关系怎样,导进powerdesigner 在整理一下,看看这些类之间的关系,其它的不做说明,我只看aop3个最主要的内容,Pointcut、Advice、Advisor。
Filter、Method
Advice
Advisor
*其它
以上4张图,仅仅是描述aop的架构,但是,具体怎么与IOC中bean相结合,这点卡了很久,突破口是代理!spring的代理主要有两种,一种是jdk动态代理,一种是CGLIB,根据我的分析,spring用的应该是jdk代理,因为接口太多了,通过接口实现类达到代理的效果。在org.springframework.aop.framework.autoproxy包中,有一个AbstractAutoProxyCreator.java类,从注释上看,aop的代理动作是通过拦截器完成的。而继承AbstractAutoProxyCreator的子类也可以用自己的策略按照类型、名称自动代理bean。
看看该类里面的postProcessAfterInitialization方法:
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
结合注释,从缓存中找bean的代理,实在找不到了再wrapIfNecessary创建一个代理
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (this.nonAdvisedBeans.contains(cacheKey)) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.nonAdvisedBeans.add(cacheKey);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.add(cacheKey);
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.nonAdvisedBeans.add(cacheKey);
return bean;
}
结合注释,成功创建的代理对象都会将beanName加入到targetSourceBeans中,从代码可以看到,是用createProxy方法创建的代理
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
if (!shouldProxyTargetClass(beanClass, beanName)) {
// Must allow for introductions; can't just set interfaces to
// the target's interfaces only.
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
for (Class<?> targetInterface : targetInterfaces) {
proxyFactory.addInterface(targetInterface);
}
}
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);
}
return proxyFactory.getProxy(this.proxyClassLoader);
}
从源码中可以追踪到代理的创建时在ProxyFactory中创建的,在追踪,看看ProxyFactory
这里不多说,但是从源码看到Interfaces 和 class两个关键字,可以推算,ProxyFactory一定是根据代理的方式决定采用哪种代理方式,基于Interfaces的是jdk动态代理,基于class的是cglib代理方式。
再回到createProxy中来,不管ProxyFactory如何创建的代理,最后加入了advisors
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
advisors前面已经说了,是切面,联合切点和通知的地方,所以上面的代码就是将切点放进切面当中!
至此,spring 自动代理bean大概的脉络就清晰了,切面连接切点就通了。至于切面和通知是怎么处理到一起的?
还是回到AbstractAutoProxyCreator.java中来,看到这里有个getAdvicesAndAdvisorsForBean方法,进入他的子类看看是怎么实现的:
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
进入findEligibleAdvisors看看是怎么织入的
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not <code>null</code>,
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
没什么收获,进入findCandidateAdvisors看看,就在该方法下面,在进入findAdvisorBeans:
/**
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring currently created advisor '" + name + "': " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
return advisors;
}
一大堆不知道怎么看,分点看即可:
(1)获取advisorNames,看看有没有合适的EligibleBean
(2)遍历advisorNames,将bean加入advisor(通知+切面)
至此就完了,很简单的流程,绕来绕去我自己也看不太懂,没法画流程图,也不知道是谁执行的aop,这方便以后有时间再慢慢看。