/**
* 获取拦截器链
*/
@Override
public List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
// 获取AdvisorAdapterRegistry对象,Spring默认初始化了MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter和ThrowsAdviceAdapter
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 获取所有增强
Advisor[] advisors = config.getAdvisors();
// 创建interceptorList保存返回结果,这里可以看到new ArrayList指定了集合长度,也是编码中节约内存开销的一个小技巧
List interceptorList = new ArrayList<>(advisors.length);
// 获取代理类的Class对象
Class> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
// 循环所有的增强
for (Advisor advisor : advisors) {
// 如果增强是PointcutAdvisor的实例
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// config.isPreFiltered() -> 返回是否对该代理配置进行了预筛选,以便仅对其进行筛选包含适用的增强(匹配此代理的目标类)。
// pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) -> 当前切点匹配的类是否匹配actualClass
// 以上两个条件是在类一级别上做出判断,如果符合,则接下来对方法级别的再做匹配判断
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 获取当前切点匹配的方法
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 区分普通的MethodMatcher和IntroductionAwareMethodMatcher,分别调用不同的匹配方法做出判断
// IntroductionAwareMethodMatcher可以作用域引入类型的增强,且当匹配方法不包含引用增强时,可以提升匹配效率
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 如果匹配
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 如果增强是IntroductionAdvisor实例
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;
}
该段代码比较关键的点:
// 如果匹配,获取方法拦截器
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
通过上面的代码可以发现Spring最终还是要把增强(切面)转换为方法拦截器,来看其具体的实现:
/**
* 获取方法连接器
*/
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// 1.如果增强是MethodInterceptor类型直接添加
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 2.循环增强适配器,并判断是否支持
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
// 3.返回结果
return interceptors.toArray(new MethodInterceptor[0]);
}
private final List adapters = new ArrayList<>(3);
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
/**
* 增强适配器
* 这个方法在获取拦截器链的时候调用,从这里也可以看出,Spring中的advisor(增强/切面)
* 最终还是被转换为MethodInterceptor对象
*
* AdvisorAdapter的实现类有AfterReturningAdviceAdapter,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter三个
*
* AfterReturningAdviceAdapter -> new AfterReturningAdviceInterceptor(advice) -> 后置返回增强
* MethodBeforeAdviceAdapter -> new MethodBeforeAdviceInterceptor(advice) -> 前置增强
* ThrowsAdviceAdapter -> new ThrowsAdviceInterceptor(advisor.getAdvice()) -> 该适配器有些特殊...看源码吧
*/
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
AfterReturningAdviceAdapter
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
ThrowsAdviceAdapter
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
return new ThrowsAdviceInterceptor(advisor.getAdvice());
}
看到这里大家一定有所了解了,Spring中的增强,最终还是会转换为方法拦截器调用。
3. 拦截器链调动过程
/**
* 调用拦截器链
*
* currentInterceptorIndex维护了一个计数器,该计数器从-1开始,当计数器值等于拦截方法长度减一时,
* 表名所有的增强方法已经被调用(但是不一定被真正执行),那么此时调用连接点的方法,针对本例:即sayHello方法
*/
@Override
@Nullable
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;
Class> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 匹配成功则执行
if (dm.methodMatcher.matches(this.method, 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.
// System.out.println(interceptorOrInterceptionAdvice.getClass());
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
FineReport使用中遇到的常见报错及解决办法(一)
这里写点抛砖引玉,希望大家能把自己整理的问题及解决方法晾出来,Mark一下,利人利己。
出现问题先搜一下文档上有没有,再看看度娘有没有,再看看论坛有没有。有报错要看日志。下面简单罗列下常见的问题,大多文档上都有提到的。
1、address pool is full:
含义:地址池满,连接数超过并发数上
原文:http://kindlefireforkid.com/how-to-setup-a-google-account-on-amazon-fire-tablet/
Step 4: Run ADB command from your PC
On the PC, you need install Amazon Fire ADB driver and instal
本文译者:candeladiao,原文:URL filtering for UIWebView on the iPhone说明:译者在做app开发时,因为页面的javascript文件比较大导致加载速度很慢,所以想把javascript文件打包在app里,当UIWebView需要加载该脚本时就从app本地读取,但UIWebView并不支持加载本地资源。最后从下文中找到了解决方法,第一次翻译,难免有