001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.support; 018 019import java.io.Serializable; 020import java.lang.reflect.Method; 021 022import org.springframework.aop.ClassFilter; 023import org.springframework.aop.MethodMatcher; 024import org.springframework.aop.Pointcut; 025import org.springframework.util.Assert; 026import org.springframework.util.ObjectUtils; 027 028/** 029 * Pointcut and method matcher for use in simple <b>cflow</b>-style pointcut. 030 * Note that evaluating such pointcuts is 10-15 times slower than evaluating 031 * normal pointcuts, but they are useful in some cases. 032 * 033 * @author Rod Johnson 034 * @author Rob Harrop 035 * @author Juergen Hoeller 036 */ 037@SuppressWarnings("serial") 038public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable { 039 040 private Class<?> clazz; 041 042 private String methodName; 043 044 private volatile int evaluations; 045 046 047 /** 048 * Construct a new pointcut that matches all control flows below that class. 049 * @param clazz the clazz 050 */ 051 public ControlFlowPointcut(Class<?> clazz) { 052 this(clazz, null); 053 } 054 055 /** 056 * Construct a new pointcut that matches all calls below the given method 057 * in the given class. If no method name is given, matches all control flows 058 * below the given class. 059 * @param clazz the clazz 060 * @param methodName the name of the method (may be {@code null}) 061 */ 062 public ControlFlowPointcut(Class<?> clazz, String methodName) { 063 Assert.notNull(clazz, "Class must not be null"); 064 this.clazz = clazz; 065 this.methodName = methodName; 066 } 067 068 069 /** 070 * Subclasses can override this for greater filtering (and performance). 071 */ 072 @Override 073 public boolean matches(Class<?> clazz) { 074 return true; 075 } 076 077 /** 078 * Subclasses can override this if it's possible to filter out 079 * some candidate classes. 080 */ 081 @Override 082 public boolean matches(Method method, Class<?> targetClass) { 083 return true; 084 } 085 086 @Override 087 public boolean isRuntime() { 088 return true; 089 } 090 091 @Override 092 public boolean matches(Method method, Class<?> targetClass, Object... args) { 093 this.evaluations++; 094 095 for (StackTraceElement element : new Throwable().getStackTrace()) { 096 if (element.getClassName().equals(this.clazz.getName()) && 097 (this.methodName == null || element.getMethodName().equals(this.methodName))) { 098 return true; 099 } 100 } 101 return false; 102 } 103 104 /** 105 * It's useful to know how many times we've fired, for optimization. 106 */ 107 public int getEvaluations() { 108 return this.evaluations; 109 } 110 111 112 @Override 113 public ClassFilter getClassFilter() { 114 return this; 115 } 116 117 @Override 118 public MethodMatcher getMethodMatcher() { 119 return this; 120 } 121 122 123 @Override 124 public boolean equals(Object other) { 125 if (this == other) { 126 return true; 127 } 128 if (!(other instanceof ControlFlowPointcut)) { 129 return false; 130 } 131 ControlFlowPointcut that = (ControlFlowPointcut) other; 132 return (this.clazz.equals(that.clazz)) && ObjectUtils.nullSafeEquals(that.methodName, this.methodName); 133 } 134 135 @Override 136 public int hashCode() { 137 int code = this.clazz.hashCode(); 138 if (this.methodName != null) { 139 code = 37 * code + this.methodName.hashCode(); 140 } 141 return code; 142 } 143 144}