在aop源码解析二:postProcessBeforeInstantiation博文中 我们花了很长的一个篇幅介绍一个方法shouldSkip
方法 虽然看名字很简单 但里面确实做了很多的事情 虽然最终也是没有去创建代理 但这些工作并不是白做的 解析完以后缓存起来了 后面就可以直接使用了 这次我们看下AnnotationAwareAspectJAutoProxyCreator##postProcessAfterInitialization(Object bean, String beanName)
方法
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
在这里看到了我们一直想看到的代理相关的代码 因为创建代理是一件耗时的事情 要做很多的解析 转换等工作 所以根据beanClass``beanName
作为缓存的key
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 因为寻找切面方法等操作是很浪费时间的操作 所以如果不必操作的话或者已经创建过代理的话 尽量提前返回
//已经创建过
if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {
return bean;
}
//本身是切面类
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;
}
// 可以看出作者的思路是很清晰的 几句代码概括了要做的事情 然后在方法里面展开
// advice advisor pointcut 等之间的名次的区别与联系
// advice : action to take at a joinpoint
// 1. 寻找适合此bean的切面方法
// 2. 创建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理对象 java动态代理或者是基于cglib的代理 cglib代理更高效
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;
}
我们又看到了shouldSkip(bean.getClass(), beanName)
方法 跟我们上篇博文介绍的是同一个方法
这里主要看下getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null)
方法
其实这个方法的主要作用是对于寻找到的所有的切面对beanClass
做过滤 涉及到切点的匹配 例如正则表达式 注解等
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
// 寻找胜任的或者说适合此bean的advior
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
//Advisor.class
//寻找所有的候选项
// 这里注意 findCandidateAdvisors() 方法在AnnotationAwareAspectJAutoProxyCreator类有继承
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//从候选项中挑出适合此bean的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//对advisor排序 按照顺序:
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findCandidateAdvisors()
方法 我们在介绍shouldSkip(xxx)
方法的时候就已经讲解过 不熟悉的读者可以多读几遍 这个方法解析出了所有的advisor
advisor
包括advice``pointcut
信息
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
//todo 写注释
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
// 类继承关系中 只要有一个类的一个方法被匹配 就返回true
Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
最重要的还是最后一个canApply
方法 根据pointcut
信息去做匹配 判断是否符合要求 因为这里是返回类的代理 所以只要有一个方法被匹配到 就人为满足条件 至于是怎么做匹配的 感兴趣的读者可以深入阅读 我们这里只要知道做了什么就可以了
回到wrapIfNecessary
方法 继续往下看 下面的就是我们一直想看到的方法了 创建代理
看一下aop
的相关配置
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
这行代码注册了BPP 另外还指定了proxy-target-class
属性 值为true
的意思是强制使用cglib
创建代理 还有另外一种java jdk
提供的代理 需要被代理的类的方法继承自某个接口方法才可以 cglib
并没有这个限制 推荐使用cglib
的方式 执行速度更快
但我们下面是以jdk
创建代理为例讲解 这种方式更简单 读者也可能更熟悉这种方式 那么就把这行xml
配置改成下面这样
<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true"/>
对java提供的动态代理实现不了解的读者 建议先看这篇博客java动态代理介绍 这样下面的代理就更容易理解
我们看下createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
方法
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);
//使用java动态代理
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
是一个很重要的类 里面有各种与切面相关的属性,方法等
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
getProxy(ClassLoader classLoader)
方法返回的就是目标类的代理类 分成两大步完成
- 返回要使用的
AopProxy
CglibAopProxy
或者JdkDynamicAopProxy
- 创建代理
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//默认是DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
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 CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
默认使用的创建AopProxy
的是DefaultAopProxyFactory 是一个工厂类 类的实现很简单 根据条件返回对应的AopProxy
当然都把proxyFactory
作为参数传递了进去
我们接下来看JdkDynamicAopProxy##getProxy
方法
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);
//寻找equals hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
completeProxiedInterfaces(AdvisedSupport advised)
方法在代理类要实现的所有接口中加入了两个接口SpringProxy
与 Advised
接口 SpringProxy
是一个标志接口 没有什么方法需要去实现 Advised
提供的接口方法就比较多了 里面有代理相关的所有配置属性
下面就是创建代理了 相信读者如果阅读了java动态代理介绍这篇博客的话 读者应该理解做了什么事情 在下一篇博客中我们看一下方法的调用过程