/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.support;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

Pointcut and method matcher for use in simple cflow-style pointcut. Note that evaluating such pointcuts is 10-15 times slower than evaluating normal pointcuts, but they are useful in some cases.
Author:Rod Johnson, Rob Harrop, Juergen Hoeller, Sam Brannen
/** * Pointcut and method matcher for use in simple <b>cflow</b>-style pointcut. * Note that evaluating such pointcuts is 10-15 times slower than evaluating * normal pointcuts, but they are useful in some cases. * * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller * @author Sam Brannen */
@SuppressWarnings("serial") public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable { private final Class<?> clazz; @Nullable private final String methodName; private final AtomicInteger evaluations = new AtomicInteger();
Construct a new pointcut that matches all control flows below that class.
Params:
  • clazz – the clazz
/** * Construct a new pointcut that matches all control flows below that class. * @param clazz the clazz */
public ControlFlowPointcut(Class<?> clazz) { this(clazz, null); }
Construct a new pointcut that matches all calls below the given method in the given class. If no method name is given, matches all control flows below the given class.
Params:
  • clazz – the clazz
  • methodName – the name of the method (may be null)
/** * Construct a new pointcut that matches all calls below the given method * in the given class. If no method name is given, matches all control flows * below the given class. * @param clazz the clazz * @param methodName the name of the method (may be {@code null}) */
public ControlFlowPointcut(Class<?> clazz, @Nullable String methodName) { Assert.notNull(clazz, "Class must not be null"); this.clazz = clazz; this.methodName = methodName; }
Subclasses can override this for greater filtering (and performance).
/** * Subclasses can override this for greater filtering (and performance). */
@Override public boolean matches(Class<?> clazz) { return true; }
Subclasses can override this if it's possible to filter out some candidate classes.
/** * Subclasses can override this if it's possible to filter out some candidate classes. */
@Override public boolean matches(Method method, Class<?> targetClass) { return true; } @Override public boolean isRuntime() { return true; } @Override public boolean matches(Method method, Class<?> targetClass, Object... args) { this.evaluations.incrementAndGet(); for (StackTraceElement element : new Throwable().getStackTrace()) { if (element.getClassName().equals(this.clazz.getName()) && (this.methodName == null || element.getMethodName().equals(this.methodName))) { return true; } } return false; }
It's useful to know how many times we've fired, for optimization.
/** * It's useful to know how many times we've fired, for optimization. */
public int getEvaluations() { return this.evaluations.get(); } @Override public ClassFilter getClassFilter() { return this; } @Override public MethodMatcher getMethodMatcher() { return this; } @Override public boolean equals(@Nullable Object other) { if (this == other) { return true; } if (!(other instanceof ControlFlowPointcut)) { return false; } ControlFlowPointcut that = (ControlFlowPointcut) other; return (this.clazz.equals(that.clazz)) && ObjectUtils.nullSafeEquals(this.methodName, that.methodName); } @Override public int hashCode() { int code = this.clazz.hashCode(); if (this.methodName != null) { code = 37 * code + this.methodName.hashCode(); } return code; } @Override public String toString() { return getClass().getName() + ": class = " + this.clazz.getName() + "; methodName = " + methodName; } }