public interface MethodMatcher {
/**
* Perform static checking whether the given method matches.
*
If this returns {@code false} or if the {@link #isRuntime()}
* method returns {@code false}, no runtime check (i.e. no
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
* will be made.
* @param method the candidate method
* @param targetClass the target class
* @return whether or not this method matches statically
*/
boolean matches(Method method, Class> targetClass);
/**
* Is this MethodMatcher dynamic, that is, must a final call be made on the
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
* runtime even if the 2-arg matches method returns {@code true}?
*
Can be invoked when an AOP proxy is created, and need not be invoked
* again before each method invocation,
* @return whether or not a runtime match via the 3-arg
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method
* is required if static matching passed
*/
boolean isRuntime();
/**
* Check whether there a runtime (dynamic) match for this method,
* which must have matched statically.
*
This method is invoked only if the 2-arg matches method returns
* {@code true} for the given method and target class, and if the
* {@link #isRuntime()} method returns {@code true}. Invoked
* immediately before potential running of the advice, after any
* advice earlier in the advice chain has run.
* @param method the candidate method
* @param targetClass the target class
* @param args arguments to the method
* @return whether there's a runtime match
* @see MethodMatcher#matches(Method, Class)
*/
boolean matches(Method method, Class> targetClass, Object... args);
/**
* Canonical instance that matches all methods.
*/
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
前面介绍了Advice的增强逻辑,Pointcut定义了方法的集合,但是哪些方法使用什么样的增强逻辑依旧没有关联起来,Advisor就是将Advice和Pointcut结合起来,通过Advisor,可以定义在某个Pointcut连接点上使用哪个Advice。 Spring 提供了一个DefaultPointcutAdvisor, 在DefaultPointcutAdvisor中有两个属性,分别为advice和pointcut用来配置Advice 和Pointcut。 其实现如下所示。
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
private Pointcut pointcut = Pointcut.TRUE;
/**
* Create an empty DefaultPointcutAdvisor.
*
Advice must be set before use using setter methods.
* Pointcut will normally be set also, but defaults to {@code Pointcut.TRUE}.
*/
public DefaultPointcutAdvisor() {
}
/**
* Create a DefaultPointcutAdvisor that matches all methods.
*
{@code Pointcut.TRUE} will be used as Pointcut.
* @param advice the Advice to use
*/
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
/**
* Create a DefaultPointcutAdvisor, specifying Pointcut and Advice.
* @param pointcut the Pointcut targeting the Advice
* @param advice the Advice to run when Pointcut matches
*/
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
setAdvice(advice);
}
/**
* Specify the pointcut targeting the advice.
*
/** The AdvisorChainFactory to use. */
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
/** Cache with Method as key and advisor chain List as value. */
private transient Map> methodCache;
/**
* Interfaces to be implemented by the proxy. Held in List to keep the order
* of registration, to create JDK proxy with specified order of interfaces.
*/
private List> interfaces = new ArrayList<>();
/**
* List of Advisors. If an Advice is added, it will be wrapped
* in an Advisor before being added to this List.
*/
private List advisors = new ArrayList<>();
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List
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 registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List interceptorList = new ArrayList<>(advisors.length);
Class> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
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));
}
}
}
}
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;
}
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.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
在系统运行后,在线程快照里总是看到线程池的名字为pool-xx,这样导致很不好定位,怎么给线程池一个有意义的名字呢。参照ThreadPoolExecutor类的ThreadFactory,自己实现ThreadFactory接口,重写newThread方法即可。参考代码如下:
public class Named
错误: IE 中"HTML Parsing Error:Unable to modify the parent container element before the child element is closed"
现象: 同事之间几个IE 测试情况下,有的报这个错,有的不报。经查询资料后,可归纳以下原因。
PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,也就是BeanFactoryPostProcessor接口的一个实现。关于BeanFactoryPostProcessor和BeanPostProcessor类似。我会在其他地方介绍。PropertyPlaceholderConfigurer可以将上下文(配置文件)中的属性值放在另一个单独的标准java P
创建一个类
public class ContextInitListener implements ServletContextListener
使得该类成为一个监听器。用于监听整个容器生命周期的,主要是初始化和销毁的。
类创建后要在web.xml配置文件中增加一个简单的监听器配置,即刚才我们定义的类。
<listener>
<des
http://developer.apple.com/iphone/library/qa/qa2009/qa1649.html
Excerpt:
You are getting this warning because you probably added your Info.plist file to your Copy Bundle
hi,
自己在做工程的时候,遇到批量插入数据的数据修复场景。我的思路是在插入前准备一个临时表,临时表的整理就看当时的选择条件了,临时表就是要插入的数据集,最后再批量插入到数据库中。
WITH tempT AS (
SELECT
item_id AS combo_id,
item_id,
now() AS create_date
FROM
a